mirror of
https://github.com/actions/runner.git
synced 2025-12-11 12:57:05 +00:00
Detect Makefiles and parse out the targets
This commit is contained in:
@@ -10,6 +10,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
@@ -486,9 +487,45 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
else if (action.Reference.Type == Pipelines.ActionSourceType.Script)
|
||||
{
|
||||
definition.Data.Execution = new ScriptActionExecutionData();
|
||||
definition.Data.Name = "Run";
|
||||
definition.Data.Description = "Execute a script";
|
||||
// Load the inputs.
|
||||
executionContext.Debug("Loading inputs");
|
||||
var templateEvaluator = executionContext.ToPipelineTemplateEvaluator();
|
||||
var inputs = templateEvaluator.EvaluateStepInputs(action.Inputs, executionContext.ExpressionValues, executionContext.ExpressionFunctions);
|
||||
|
||||
// Check if we are running a Makefile.
|
||||
// Only works for the default target right now.
|
||||
if (inputs["script"] == "make")
|
||||
{
|
||||
// Get the path of the Makefile in the repository root.
|
||||
var githubContext = executionContext.ExpressionValues["github"] as GitHubContext;
|
||||
var workspaceDir = githubContext["workspace"] as StringContextData;
|
||||
var makefile = Path.Combine(workspaceDir, "Makefile");
|
||||
if (!File.Exists(makefile))
|
||||
{
|
||||
// Forget about trying to be smart. Just do the normal thing.
|
||||
definition.Data.Execution = new ScriptActionExecutionData();
|
||||
definition.Data.Name = "Run";
|
||||
definition.Data.Description = "Execute a script";
|
||||
}
|
||||
|
||||
// Assume the default target is named `all`.
|
||||
var definitionData = MakefileManager.Load(executionContext, makefile, target: "all");
|
||||
if (definitionData is null)
|
||||
{
|
||||
// Forget about trying to be smart. Just do the normal thing.
|
||||
definition.Data.Execution = new ScriptActionExecutionData();
|
||||
definition.Data.Name = "Run";
|
||||
definition.Data.Description = "Execute a script";
|
||||
}
|
||||
|
||||
definition.Data = definitionData;
|
||||
}
|
||||
else
|
||||
{
|
||||
definition.Data.Execution = new ScriptActionExecutionData();
|
||||
definition.Data.Name = "Run";
|
||||
definition.Data.Description = "Execute a script";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1143,6 +1180,7 @@ namespace GitHub.Runner.Worker
|
||||
Plugin,
|
||||
Script,
|
||||
Composite,
|
||||
Makefile,
|
||||
}
|
||||
|
||||
public sealed class ContainerActionExecutionData : ActionExecutionData
|
||||
@@ -1210,6 +1248,14 @@ namespace GitHub.Runner.Worker
|
||||
public MappingToken Outputs { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MakefileExecutionData : ActionExecutionData
|
||||
{
|
||||
public override ActionExecutionType ExecutionType => ActionExecutionType.Makefile;
|
||||
public override bool HasPre => false;
|
||||
public override bool HasPost => false;
|
||||
public List<string> Targets { get; set; }
|
||||
}
|
||||
|
||||
public abstract class ActionExecutionData
|
||||
{
|
||||
private string _initCondition = $"{Constants.Expressions.Always}()";
|
||||
|
||||
@@ -73,6 +73,11 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
handler = HostContext.CreateService<ICompositeActionHandler>();
|
||||
(handler as ICompositeActionHandler).Data = data as CompositeActionExecutionData;
|
||||
}
|
||||
else if (data.ExecutionType == ActionExecutionType.Makefile)
|
||||
{
|
||||
handler = HostContext.CreateService<IMakefileHandler>();
|
||||
(handler as IMakefileHandler).Data = data as MakefileExecutionData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This should never happen.
|
||||
|
||||
67
src/Runner.Worker/Handlers/MakefileHandler.cs
Normal file
67
src/Runner.Worker/Handlers/MakefileHandler.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.Expressions2;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Expressions;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
|
||||
namespace GitHub.Runner.Worker.Handlers
|
||||
{
|
||||
[ServiceLocator(Default = typeof(MakefileHandler))]
|
||||
public interface IMakefileHandler : IHandler
|
||||
{
|
||||
MakefileExecutionData Data { get; set; }
|
||||
}
|
||||
public sealed class MakefileHandler : Handler, IMakefileHandler
|
||||
{
|
||||
public MakefileExecutionData Data { get; set; }
|
||||
|
||||
public async Task RunAsync(ActionRunStage stage)
|
||||
{
|
||||
// Validate args
|
||||
Trace.Entering();
|
||||
ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext));
|
||||
ArgUtil.NotNull(Inputs, nameof(Inputs));
|
||||
|
||||
// Create a script handler for each target
|
||||
var handlers = Data.Targets.Select(target =>
|
||||
{
|
||||
var handler = HostContext.CreateService<IScriptHandler>();
|
||||
|
||||
// IScriptHandler does not need .Action
|
||||
// handler.Action = action;
|
||||
handler.Data = new ScriptActionExecutionData();
|
||||
handler.Environment = Environment;
|
||||
handler.RuntimeVariables = RuntimeVariables;
|
||||
handler.ExecutionContext = ExecutionContext;
|
||||
handler.StepHost = StepHost;
|
||||
handler.Inputs = new Dictionary<string, string>
|
||||
{
|
||||
["script"] = $"make {target}"
|
||||
};
|
||||
handler.ActionDirectory = ActionDirectory;
|
||||
handler.LocalActionContainerSetupSteps = LocalActionContainerSetupSteps;
|
||||
|
||||
return handler;
|
||||
});
|
||||
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
await handler.RunAsync(stage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
|
||||
Inputs.TryGetValue("script", out string contents);
|
||||
contents = contents ?? string.Empty;
|
||||
if (Action.Type == Pipelines.ActionSourceType.Script)
|
||||
{
|
||||
// if (Action.Type == Pipelines.ActionSourceType.Script)
|
||||
// {
|
||||
var firstLine = contents.TrimStart(' ', '\t', '\r', '\n');
|
||||
var firstNewLine = firstLine.IndexOfAny(new[] { '\r', '\n' });
|
||||
if (firstNewLine >= 0)
|
||||
@@ -41,11 +41,11 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
}
|
||||
|
||||
ExecutionContext.Output($"##[group]Run {firstLine}");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid action type {Action.Type} for {nameof(ScriptHandler)}");
|
||||
}
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new InvalidOperationException($"Invalid action type {Action.Type} for {nameof(ScriptHandler)}");
|
||||
// }
|
||||
|
||||
var multiLines = contents.Replace("\r\n", "\n").TrimEnd('\n').Split('\n');
|
||||
foreach (var line in multiLines)
|
||||
|
||||
39
src/Runner.Worker/MakefileManager.cs
Normal file
39
src/Runner.Worker/MakefileManager.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace GitHub.Runner.Worker
|
||||
{
|
||||
public static class MakefileManager
|
||||
{
|
||||
// Convert the `all` target to a set of steps of its dependencies.
|
||||
// Does not recurse into the dependencies of those steps.
|
||||
public static ActionDefinitionData Load(IExecutionContext executionContext, string makefile, string target)
|
||||
{
|
||||
var targetToFind = target + ":";
|
||||
var lines = File.ReadLines(makefile);
|
||||
string targetLine = lines.FirstOrDefault(line => line.TrimStart().StartsWith(targetToFind));
|
||||
if (targetLine is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var dependencies = targetLine.Split().Skip(1).ToList();
|
||||
if (dependencies.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ActionDefinitionData
|
||||
{
|
||||
Name = $"make {target}",
|
||||
Description = "Execute a Makefile target",
|
||||
Execution = new MakefileExecutionData
|
||||
{
|
||||
Targets = dependencies,
|
||||
InitCondition = "always()",
|
||||
CleanupCondition = "always()",
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user