Skip to content

Commit a54f380

Browse files
authored
Compare updated workflow parser for ActionManifestManager (#4111)
1 parent 8b184c3 commit a54f380

15 files changed

Lines changed: 2366 additions & 82 deletions

src/Runner.Common/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public static class Features
172172
public static readonly string ContainerActionRunnerTemp = "actions_container_action_runner_temp";
173173
public static readonly string SnapshotPreflightHostedRunnerCheck = "actions_snapshot_preflight_hosted_runner_check";
174174
public static readonly string SnapshotPreflightImageGenPoolCheck = "actions_snapshot_preflight_image_gen_pool_check";
175-
public static readonly string CompareTemplateEvaluator = "actions_runner_compare_template_evaluator";
175+
public static readonly string CompareWorkflowParser = "actions_runner_compare_workflow_parser";
176176
}
177177

178178
// Node version migration related constants

src/Runner.Worker/ActionManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ public Definition LoadAction(IExecutionContext executionContext, Pipelines.Actio
378378
string dockerFileLowerCase = Path.Combine(actionDirectory, "dockerfile");
379379
if (File.Exists(manifestFile) || File.Exists(manifestFileYaml))
380380
{
381-
var manifestManager = HostContext.GetService<IActionManifestManager>();
381+
var manifestManager = HostContext.GetService<IActionManifestManagerWrapper>();
382382
if (File.Exists(manifestFile))
383383
{
384384
definition.Data = manifestManager.Load(executionContext, manifestFile);
@@ -964,7 +964,7 @@ private ActionSetupInfo PrepareRepositoryActionAsync(IExecutionContext execution
964964
if (File.Exists(actionManifest) || File.Exists(actionManifestYaml))
965965
{
966966
executionContext.Debug($"action.yml for action: '{actionManifest}'.");
967-
var manifestManager = HostContext.GetService<IActionManifestManager>();
967+
var manifestManager = HostContext.GetService<IActionManifestManagerWrapper>();
968968
ActionDefinitionData actionDefinitionData = null;
969969
if (File.Exists(actionManifest))
970970
{

src/Runner.Worker/ActionManifestManager.cs

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,29 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Threading;
5-
using GitHub.Runner.Common;
6-
using GitHub.Runner.Sdk;
75
using System.Reflection;
8-
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
9-
using GitHub.DistributedTask.ObjectTemplating.Schema;
10-
using GitHub.DistributedTask.ObjectTemplating;
11-
using GitHub.DistributedTask.ObjectTemplating.Tokens;
12-
using GitHub.DistributedTask.Pipelines.ContextData;
136
using System.Linq;
14-
using Pipelines = GitHub.DistributedTask.Pipelines;
7+
using GitHub.Runner.Common;
8+
using GitHub.Runner.Sdk;
9+
using GitHub.Actions.WorkflowParser;
10+
using GitHub.Actions.WorkflowParser.Conversion;
11+
using GitHub.Actions.WorkflowParser.ObjectTemplating;
12+
using GitHub.Actions.WorkflowParser.ObjectTemplating.Schema;
13+
using GitHub.Actions.WorkflowParser.ObjectTemplating.Tokens;
14+
using GitHub.Actions.Expressions.Data;
1515

1616
namespace GitHub.Runner.Worker
1717
{
1818
[ServiceLocator(Default = typeof(ActionManifestManager))]
1919
public interface IActionManifestManager : IRunnerService
2020
{
21-
ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile);
21+
public ActionDefinitionDataNew Load(IExecutionContext executionContext, string manifestFile);
2222

23-
DictionaryContextData EvaluateCompositeOutputs(IExecutionContext executionContext, TemplateToken token, IDictionary<string, PipelineContextData> extraExpressionValues);
23+
DictionaryExpressionData EvaluateCompositeOutputs(IExecutionContext executionContext, TemplateToken token, IDictionary<string, ExpressionData> extraExpressionValues);
2424

25-
List<string> EvaluateContainerArguments(IExecutionContext executionContext, SequenceToken token, IDictionary<string, PipelineContextData> extraExpressionValues);
25+
List<string> EvaluateContainerArguments(IExecutionContext executionContext, SequenceToken token, IDictionary<string, ExpressionData> extraExpressionValues);
2626

27-
Dictionary<string, string> EvaluateContainerEnvironment(IExecutionContext executionContext, MappingToken token, IDictionary<string, PipelineContextData> extraExpressionValues);
27+
Dictionary<string, string> EvaluateContainerEnvironment(IExecutionContext executionContext, MappingToken token, IDictionary<string, ExpressionData> extraExpressionValues);
2828

2929
string EvaluateDefaultInput(IExecutionContext executionContext, string inputName, TemplateToken token);
3030
}
@@ -50,10 +50,10 @@ public override void Initialize(IHostContext hostContext)
5050
Trace.Info($"Load schema file with definitions: {StringUtil.ConvertToJson(_actionManifestSchema.Definitions.Keys)}");
5151
}
5252

53-
public ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile)
53+
public ActionDefinitionDataNew Load(IExecutionContext executionContext, string manifestFile)
5454
{
5555
var templateContext = CreateTemplateContext(executionContext);
56-
ActionDefinitionData actionDefinition = new();
56+
ActionDefinitionDataNew actionDefinition = new();
5757

5858
// Clean up file name real quick
5959
// Instead of using Regex which can be computationally expensive,
@@ -160,21 +160,21 @@ public ActionDefinitionData Load(IExecutionContext executionContext, string mani
160160
return actionDefinition;
161161
}
162162

163-
public DictionaryContextData EvaluateCompositeOutputs(
163+
public DictionaryExpressionData EvaluateCompositeOutputs(
164164
IExecutionContext executionContext,
165165
TemplateToken token,
166-
IDictionary<string, PipelineContextData> extraExpressionValues)
166+
IDictionary<string, ExpressionData> extraExpressionValues)
167167
{
168-
var result = default(DictionaryContextData);
168+
DictionaryExpressionData result = null;
169169

170170
if (token != null)
171171
{
172172
var templateContext = CreateTemplateContext(executionContext, extraExpressionValues);
173173
try
174174
{
175-
token = TemplateEvaluator.Evaluate(templateContext, "outputs", token, 0, null, omitHeader: true);
175+
token = TemplateEvaluator.Evaluate(templateContext, "outputs", token, 0, null);
176176
templateContext.Errors.Check();
177-
result = token.ToContextData().AssertDictionary("composite outputs");
177+
result = token.ToExpressionData().AssertDictionary("composite outputs");
178178
}
179179
catch (Exception ex) when (!(ex is TemplateValidationException))
180180
{
@@ -184,13 +184,13 @@ public DictionaryContextData EvaluateCompositeOutputs(
184184
templateContext.Errors.Check();
185185
}
186186

187-
return result ?? new DictionaryContextData();
187+
return result ?? new DictionaryExpressionData();
188188
}
189189

190190
public List<string> EvaluateContainerArguments(
191191
IExecutionContext executionContext,
192192
SequenceToken token,
193-
IDictionary<string, PipelineContextData> extraExpressionValues)
193+
IDictionary<string, ExpressionData> extraExpressionValues)
194194
{
195195
var result = new List<string>();
196196

@@ -199,7 +199,7 @@ public List<string> EvaluateContainerArguments(
199199
var templateContext = CreateTemplateContext(executionContext, extraExpressionValues);
200200
try
201201
{
202-
var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "container-runs-args", token, 0, null, omitHeader: true);
202+
var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "container-runs-args", token, 0, null);
203203
templateContext.Errors.Check();
204204

205205
Trace.Info($"Arguments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}");
@@ -229,7 +229,7 @@ public List<string> EvaluateContainerArguments(
229229
public Dictionary<string, string> EvaluateContainerEnvironment(
230230
IExecutionContext executionContext,
231231
MappingToken token,
232-
IDictionary<string, PipelineContextData> extraExpressionValues)
232+
IDictionary<string, ExpressionData> extraExpressionValues)
233233
{
234234
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
235235

@@ -238,7 +238,7 @@ public Dictionary<string, string> EvaluateContainerEnvironment(
238238
var templateContext = CreateTemplateContext(executionContext, extraExpressionValues);
239239
try
240240
{
241-
var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "container-runs-env", token, 0, null, omitHeader: true);
241+
var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "container-runs-env", token, 0, null);
242242
templateContext.Errors.Check();
243243

244244
Trace.Info($"Environments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}");
@@ -281,7 +281,7 @@ public string EvaluateDefaultInput(
281281
var templateContext = CreateTemplateContext(executionContext);
282282
try
283283
{
284-
var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "input-default-context", token, 0, null, omitHeader: true);
284+
var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "input-default-context", token, 0, null);
285285
templateContext.Errors.Check();
286286

287287
Trace.Info($"Input '{inputName}': default value evaluate result: {StringUtil.ConvertToJson(evaluateResult)}");
@@ -303,7 +303,7 @@ public string EvaluateDefaultInput(
303303

304304
private TemplateContext CreateTemplateContext(
305305
IExecutionContext executionContext,
306-
IDictionary<string, PipelineContextData> extraExpressionValues = null)
306+
IDictionary<string, ExpressionData> extraExpressionValues = null)
307307
{
308308
var result = new TemplateContext
309309
{
@@ -314,13 +314,17 @@ private TemplateContext CreateTemplateContext(
314314
maxEvents: 1000000,
315315
maxBytes: 10 * 1024 * 1024),
316316
Schema = _actionManifestSchema,
317-
TraceWriter = executionContext.ToTemplateTraceWriter(),
317+
// TODO: Switch to real tracewriter for cutover
318+
TraceWriter = new GitHub.Actions.WorkflowParser.ObjectTemplating.EmptyTraceWriter(),
318319
};
319320

320321
// Expression values from execution context
321322
foreach (var pair in executionContext.ExpressionValues)
322323
{
323-
result.ExpressionValues[pair.Key] = pair.Value;
324+
// Convert old PipelineContextData to new ExpressionData
325+
var json = StringUtil.ConvertToJson(pair.Value, Newtonsoft.Json.Formatting.None);
326+
var newValue = StringUtil.ConvertFromJson<GitHub.Actions.Expressions.Data.ExpressionData>(json);
327+
result.ExpressionValues[pair.Key] = newValue;
324328
}
325329

326330
// Extra expression values
@@ -332,10 +336,19 @@ private TemplateContext CreateTemplateContext(
332336
}
333337
}
334338

335-
// Expression functions from execution context
336-
foreach (var item in executionContext.ExpressionFunctions)
339+
// Expression functions
340+
foreach (var func in executionContext.ExpressionFunctions)
337341
{
338-
result.ExpressionFunctions.Add(item);
342+
GitHub.Actions.Expressions.IFunctionInfo newFunc = func.Name switch
343+
{
344+
"always" => new GitHub.Actions.Expressions.FunctionInfo<Expressions.NewAlwaysFunction>(func.Name, func.MinParameters, func.MaxParameters),
345+
"cancelled" => new GitHub.Actions.Expressions.FunctionInfo<Expressions.NewCancelledFunction>(func.Name, func.MinParameters, func.MaxParameters),
346+
"failure" => new GitHub.Actions.Expressions.FunctionInfo<Expressions.NewFailureFunction>(func.Name, func.MinParameters, func.MaxParameters),
347+
"success" => new GitHub.Actions.Expressions.FunctionInfo<Expressions.NewSuccessFunction>(func.Name, func.MinParameters, func.MaxParameters),
348+
"hashFiles" => new GitHub.Actions.Expressions.FunctionInfo<Expressions.NewHashFilesFunction>(func.Name, func.MinParameters, func.MaxParameters),
349+
_ => throw new NotSupportedException($"Expression function '{func.Name}' is not supported in ActionManifestManager")
350+
};
351+
result.ExpressionFunctions.Add(newFunc);
339352
}
340353

341354
// Add the file table from the Execution Context
@@ -368,7 +381,7 @@ private ActionExecutionData ConvertRuns(
368381
var postToken = default(StringToken);
369382
var postEntrypointToken = default(StringToken);
370383
var postIfToken = default(StringToken);
371-
var steps = default(List<Pipelines.Step>);
384+
var steps = default(List<GitHub.Actions.WorkflowParser.IStep>);
372385

373386
foreach (var run in runsMapping)
374387
{
@@ -416,7 +429,7 @@ private ActionExecutionData ConvertRuns(
416429
break;
417430
case "steps":
418431
var stepsToken = run.Value.AssertSequence("steps");
419-
steps = PipelineTemplateConverter.ConvertToSteps(templateContext, stepsToken);
432+
steps = WorkflowTemplateConverter.ConvertToSteps(templateContext, stepsToken);
420433
templateContext.Errors.Check();
421434
break;
422435
default:
@@ -435,7 +448,7 @@ private ActionExecutionData ConvertRuns(
435448
}
436449
else
437450
{
438-
return new ContainerActionExecutionData()
451+
return new ContainerActionExecutionDataNew()
439452
{
440453
Image = imageToken.Value,
441454
Arguments = argsToken,
@@ -478,11 +491,11 @@ private ActionExecutionData ConvertRuns(
478491
}
479492
else
480493
{
481-
return new CompositeActionExecutionData()
494+
return new CompositeActionExecutionDataNew()
482495
{
483-
Steps = steps.Cast<Pipelines.ActionStep>().ToList(),
484-
PreSteps = new List<Pipelines.ActionStep>(),
485-
PostSteps = new Stack<Pipelines.ActionStep>(),
496+
Steps = steps,
497+
PreSteps = new List<GitHub.Actions.WorkflowParser.IStep>(),
498+
PostSteps = new Stack<GitHub.Actions.WorkflowParser.IStep>(),
486499
InitCondition = "always()",
487500
CleanupCondition = "always()",
488501
Outputs = outputs
@@ -507,7 +520,7 @@ private ActionExecutionData ConvertRuns(
507520

508521
private void ConvertInputs(
509522
TemplateToken inputsToken,
510-
ActionDefinitionData actionDefinition)
523+
ActionDefinitionDataNew actionDefinition)
511524
{
512525
actionDefinition.Inputs = new MappingToken(null, null, null);
513526
var inputsMapping = inputsToken.AssertMapping("inputs");
@@ -542,5 +555,49 @@ private void ConvertInputs(
542555
}
543556
}
544557
}
558+
559+
public sealed class ActionDefinitionDataNew
560+
{
561+
public string Name { get; set; }
562+
563+
public string Description { get; set; }
564+
565+
public MappingToken Inputs { get; set; }
566+
567+
public ActionExecutionData Execution { get; set; }
568+
569+
public Dictionary<String, String> Deprecated { get; set; }
570+
}
571+
572+
public sealed class ContainerActionExecutionDataNew : ActionExecutionData
573+
{
574+
public override ActionExecutionType ExecutionType => ActionExecutionType.Container;
575+
576+
public override bool HasPre => !string.IsNullOrEmpty(Pre);
577+
public override bool HasPost => !string.IsNullOrEmpty(Post);
578+
579+
public string Image { get; set; }
580+
581+
public string EntryPoint { get; set; }
582+
583+
public SequenceToken Arguments { get; set; }
584+
585+
public MappingToken Environment { get; set; }
586+
587+
public string Pre { get; set; }
588+
589+
public string Post { get; set; }
590+
}
591+
592+
public sealed class CompositeActionExecutionDataNew : ActionExecutionData
593+
{
594+
public override ActionExecutionType ExecutionType => ActionExecutionType.Composite;
595+
public override bool HasPre => PreSteps.Count > 0;
596+
public override bool HasPost => PostSteps.Count > 0;
597+
public List<GitHub.Actions.WorkflowParser.IStep> PreSteps { get; set; }
598+
public List<GitHub.Actions.WorkflowParser.IStep> Steps { get; set; }
599+
public Stack<GitHub.Actions.WorkflowParser.IStep> PostSteps { get; set; }
600+
public MappingToken Outputs { get; set; }
601+
}
545602
}
546603

0 commit comments

Comments
 (0)