diff --git a/src/Runner.Worker/ActionManager.cs b/src/Runner.Worker/ActionManager.cs index 5b2fa3fda..b34082c86 100644 --- a/src/Runner.Worker/ActionManager.cs +++ b/src/Runner.Worker/ActionManager.cs @@ -1283,6 +1283,7 @@ namespace GitHub.Runner.Worker public override bool HasPre => false; public override bool HasPost => false; public List Steps { get; set; } + public MappingToken Environment { get; set; } } public abstract class ActionExecutionData diff --git a/src/Runner.Worker/ActionManifestManager.cs b/src/Runner.Worker/ActionManifestManager.cs index b210d7938..eac9e1ea1 100644 --- a/src/Runner.Worker/ActionManifestManager.cs +++ b/src/Runner.Worker/ActionManifestManager.cs @@ -27,6 +27,7 @@ namespace GitHub.Runner.Worker Dictionary EvaluateContainerEnvironment(IExecutionContext executionContext, MappingToken token, IDictionary extraExpressionValues); + public Dictionary EvaluateCompositeActionEnvironment(IExecutionContext executionContext, MappingToken token, IDictionary extraExpressionValues); string EvaluateDefaultInput(IExecutionContext executionContext, string inputName, TemplateToken token); } @@ -214,6 +215,65 @@ namespace GitHub.Runner.Worker return result; } + // TODO: Add Evaluate Composite Action Env Function Here + // Steps will be evaluated already in StepsRunner + public Dictionary EvaluateCompositeActionEnvironment( + IExecutionContext executionContext, + MappingToken token, + IDictionary extraExpressionValues) + { + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (token != null) + { + var context = CreateContext(executionContext, extraExpressionValues); + try + { + var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-env", token, 0, null, omitHeader: true); + context.Errors.Check(); + if (evaluateResult != null) { + Trace.Info($"EvaluateCompositeActionEnvironment evaluateResult {evaluateResult}"); + } else { + Trace.Info($"EvaluateCompositeActionEnvironment evaluateResult is null"); + } + + + Trace.Info($"Composite Action Environments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}"); + + // Mapping + var mapping = evaluateResult.AssertMapping("composite env"); + if (mapping != null) { + Trace.Info($"EvaluateCompositeActionEnvironment Mapping {mapping}"); + } else { + Trace.Info($"EvaluateCompositeActionEnvironment Mapping is null"); + } + + foreach (var pair in mapping) + { + // Literal key + var key = pair.Key.AssertString("composite env key"); + Trace.Info($"EvaluateCompositeActionEnvironment Key{key.Value}"); + + // Literal value + var value = pair.Value.AssertString("composite env value"); + Trace.Info($"EvaluateCompositeActionEnvironment Value{value.Value}"); + result[key.Value] = value.Value; + + Trace.Info($"Add env {key} = {value}"); + } + } + catch (Exception ex) when (!(ex is TemplateValidationException)) + { + Trace.Error(ex); + context.Errors.Add(ex); + } + + context.Errors.Check(); + } + + return result; + + } public string EvaluateDefaultInput( IExecutionContext executionContext, string inputName, @@ -426,6 +486,7 @@ namespace GitHub.Runner.Worker return new CompositeActionExecutionData() { Steps = stepsLoaded, + Environment = envToken }; } } diff --git a/src/Runner.Worker/ExecutionContext.cs b/src/Runner.Worker/ExecutionContext.cs index a76ca3cd0..9cd7e6dbb 100644 --- a/src/Runner.Worker/ExecutionContext.cs +++ b/src/Runner.Worker/ExecutionContext.cs @@ -105,8 +105,9 @@ namespace GitHub.Runner.Worker // others void ForceTaskComplete(); void RegisterPostJobStep(IStep step); - IStep RegisterCompositeStep(IStep step, DictionaryContextData inputsData); + IStep RegisterCompositeStep(IStep step, DictionaryContextData inputsData, PipelineContextData envData); void EnqueueAllCompositeSteps(Queue steps); + ExecutionContext getParentExecutionContext(); } public sealed class ExecutionContext : RunnerService, IExecutionContext @@ -271,7 +272,7 @@ namespace GitHub.Runner.Worker RegisterCompositeStep is a helper function used in CompositeActionHandler::RunAsync to add a child node, aka a step, to the current job to the front of the queue for processing. */ - public IStep RegisterCompositeStep(IStep step, DictionaryContextData inputsData) + public IStep RegisterCompositeStep(IStep step, DictionaryContextData inputsData, PipelineContextData envData) { // ~Brute Force Method~ // There is no way to put this current job in front of the queue in < O(n) time where n = # of elements in JobSteps @@ -296,6 +297,10 @@ namespace GitHub.Runner.Worker var newGuid = Guid.NewGuid(); step.ExecutionContext = Root.CreateChild(newGuid, step.DisplayName, newGuid.ToString("N"), null, null); step.ExecutionContext.ExpressionValues["inputs"] = inputsData; + step.ExecutionContext.ExpressionValues["env"] = envData; + + // TODO add environment variables for individual composite action steps + return step; } @@ -329,6 +334,11 @@ namespace GitHub.Runner.Worker } } + public ExecutionContext getParentExecutionContext() + { + return _parentExecutionContext; + } + public IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary intraActionState = null, int? recordOrder = null) { Trace.Entering(); diff --git a/src/Runner.Worker/Handlers/CompositeActionHandler.cs b/src/Runner.Worker/Handlers/CompositeActionHandler.cs index 34f12270b..35ae41bb4 100644 --- a/src/Runner.Worker/Handlers/CompositeActionHandler.cs +++ b/src/Runner.Worker/Handlers/CompositeActionHandler.cs @@ -52,6 +52,32 @@ namespace GitHub.Runner.Worker.Handlers inputsData[i.Key] = new StringContextData(i.Value); } + // Set up parent's environment data and then add on composite action environment data +#if OS_WINDOWS + var envData = ExecutionContext.ExpressionValues["env"].Clone() as DictionaryContextData; +#else + var envData = ExecutionContext.ExpressionValues["env"].Clone() as CaseSensitiveDictionaryContextData; +#endif + // Composite action will have already inherited the root env attributes. + // We evaluated the env simimilar to how ContainerActionHandler does it. + if (Data.Environment == null) { + Trace.Info($"Composite Env Mapping Token is null"); + } else { + Trace.Info($"Composite Env Mapping Token {Data.Environment}"); + } + var extraExpressionValues = new Dictionary(StringComparer.OrdinalIgnoreCase); + extraExpressionValues["inputs"] = inputsData; + var manifestManager = HostContext.GetService(); + var evaluatedEnv = manifestManager.EvaluateCompositeActionEnvironment(ExecutionContext, Data.Environment, extraExpressionValues); + foreach (var e in evaluatedEnv) + { + // How to add to EnvironmentContextData + // We need to use IEnvironmentContextData because ScriptHandler uses this type for environment variables + Trace.Info($"Composite Action Env Key: {e.Key}"); + Trace.Info($"Composite Action Env Value: {e.Value}"); + envData[e.Key] = new StringContextData(e.Value); + } + // Add each composite action step to the front of the queue var compositeActionSteps = new Queue(); foreach (Pipelines.ActionStep aStep in actionSteps) @@ -94,7 +120,7 @@ namespace GitHub.Runner.Worker.Handlers // TODO: Do we need to add any context data from the job message? // (See JobExtension.cs ~line 236) - compositeActionSteps.Enqueue(ExecutionContext.RegisterCompositeStep(actionRunner, inputsData)); + compositeActionSteps.Enqueue(ExecutionContext.RegisterCompositeStep(actionRunner, inputsData, envData)); } ExecutionContext.EnqueueAllCompositeSteps(compositeActionSteps); diff --git a/src/Runner.Worker/Handlers/ScriptHandler.cs b/src/Runner.Worker/Handlers/ScriptHandler.cs index 051cd5fc7..b93c40de8 100644 --- a/src/Runner.Worker/Handlers/ScriptHandler.cs +++ b/src/Runner.Worker/Handlers/ScriptHandler.cs @@ -255,6 +255,14 @@ namespace GitHub.Runner.Worker.Handlers Environment[env.Key] = env.Value; } } + + // if (context.Key == "env" && context.Value != null && !String.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA"))) + // { + // foreach (var env in context.Value as DictionaryContextData) + // { + // Environment[env.Key] = env.Value as StringContextData; + // } + // } } // dump out the command diff --git a/src/Runner.Worker/StepsRunner.cs b/src/Runner.Worker/StepsRunner.cs index 6a0e2b694..a1f0bbaa8 100644 --- a/src/Runner.Worker/StepsRunner.cs +++ b/src/Runner.Worker/StepsRunner.cs @@ -90,6 +90,7 @@ namespace GitHub.Runner.Worker // Initialize scope if (InitializeScope(step, scopeInputs)) { + // TODO Check if this adds env context to each composite action step // Populate env context for each step Trace.Info("Initialize Env context for step"); #if OS_WINDOWS diff --git a/src/Runner.Worker/action_yaml.json b/src/Runner.Worker/action_yaml.json index da8fb79a9..f789edaf8 100644 --- a/src/Runner.Worker/action_yaml.json +++ b/src/Runner.Worker/action_yaml.json @@ -88,6 +88,7 @@ "mapping": { "properties": { "using": "non-empty-string", + "env": "container-runs-env", "steps": "composite-steps" } }