mirror of
https://github.com/actions/runner.git
synced 2025-12-13 19:03:44 +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;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
@@ -486,9 +487,45 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
else if (action.Reference.Type == Pipelines.ActionSourceType.Script)
|
else if (action.Reference.Type == Pipelines.ActionSourceType.Script)
|
||||||
{
|
{
|
||||||
definition.Data.Execution = new ScriptActionExecutionData();
|
// Load the inputs.
|
||||||
definition.Data.Name = "Run";
|
executionContext.Debug("Loading inputs");
|
||||||
definition.Data.Description = "Execute a script";
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -1143,6 +1180,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Plugin,
|
Plugin,
|
||||||
Script,
|
Script,
|
||||||
Composite,
|
Composite,
|
||||||
|
Makefile,
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ContainerActionExecutionData : ActionExecutionData
|
public sealed class ContainerActionExecutionData : ActionExecutionData
|
||||||
@@ -1210,6 +1248,14 @@ namespace GitHub.Runner.Worker
|
|||||||
public MappingToken Outputs { get; set; }
|
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
|
public abstract class ActionExecutionData
|
||||||
{
|
{
|
||||||
private string _initCondition = $"{Constants.Expressions.Always}()";
|
private string _initCondition = $"{Constants.Expressions.Always}()";
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
handler = HostContext.CreateService<ICompositeActionHandler>();
|
handler = HostContext.CreateService<ICompositeActionHandler>();
|
||||||
(handler as ICompositeActionHandler).Data = data as CompositeActionExecutionData;
|
(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
|
else
|
||||||
{
|
{
|
||||||
// This should never happen.
|
// 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);
|
Inputs.TryGetValue("script", out string contents);
|
||||||
contents = contents ?? string.Empty;
|
contents = contents ?? string.Empty;
|
||||||
if (Action.Type == Pipelines.ActionSourceType.Script)
|
// if (Action.Type == Pipelines.ActionSourceType.Script)
|
||||||
{
|
// {
|
||||||
var firstLine = contents.TrimStart(' ', '\t', '\r', '\n');
|
var firstLine = contents.TrimStart(' ', '\t', '\r', '\n');
|
||||||
var firstNewLine = firstLine.IndexOfAny(new[] { '\r', '\n' });
|
var firstNewLine = firstLine.IndexOfAny(new[] { '\r', '\n' });
|
||||||
if (firstNewLine >= 0)
|
if (firstNewLine >= 0)
|
||||||
@@ -41,11 +41,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExecutionContext.Output($"##[group]Run {firstLine}");
|
ExecutionContext.Output($"##[group]Run {firstLine}");
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
throw new InvalidOperationException($"Invalid action type {Action.Type} for {nameof(ScriptHandler)}");
|
// throw new InvalidOperationException($"Invalid action type {Action.Type} for {nameof(ScriptHandler)}");
|
||||||
}
|
// }
|
||||||
|
|
||||||
var multiLines = contents.Replace("\r\n", "\n").TrimEnd('\n').Split('\n');
|
var multiLines = contents.Replace("\r\n", "\n").TrimEnd('\n').Split('\n');
|
||||||
foreach (var line in multiLines)
|
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