public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Action, nameof(Action)); var taskManager = HostContext.GetService <IActionManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Load the task definition and choose the handler. Definition definition = taskManager.LoadAction(ExecutionContext, Action); ArgUtil.NotNull(definition, nameof(definition)); ActionExecutionData handlerData = definition.Data?.Execution; ArgUtil.NotNull(handlerData, nameof(handlerData)); if (handlerData.HasPre && Action.Reference is Pipelines.RepositoryPathReference repoAction && string.Equals(repoAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase)) { ExecutionContext.Warning($"`pre` execution is not supported for local action from '{repoAction.Path}'"); } // The action has post cleanup defined. // we need to create timeline record for them and add them to the step list that StepRunner is using if (handlerData.HasPost && (Stage == ActionRunStage.Pre || Stage == ActionRunStage.Main)) { string postDisplayName = $"Post {this.DisplayName}"; if (Stage == ActionRunStage.Pre && this.DisplayName.StartsWith("Pre ", StringComparison.OrdinalIgnoreCase)) { // Trim the leading `Pre ` from the display name. // Otherwise, we will get `Post Pre xxx` as DisplayName for the Post step. postDisplayName = $"Post {this.DisplayName.Substring("Pre ".Length)}"; } var repositoryReference = Action.Reference as RepositoryPathReference; var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}"; var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" : $"{repositoryReference.Name}{pathString}@{repositoryReference.Ref}"; ExecutionContext.Debug($"Register post job cleanup for action: {repoString}"); var actionRunner = HostContext.CreateService <IActionRunner>(); actionRunner.Action = Action; actionRunner.Stage = ActionRunStage.Post; actionRunner.Condition = handlerData.CleanupCondition; actionRunner.DisplayName = postDisplayName; ExecutionContext.RegisterPostJobStep(actionRunner); } IStepHost stepHost = HostContext.CreateService <IDefaultStepHost>(); // Makes directory for event_path data var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp); var workflowDirectory = Path.Combine(tempDirectory, "_github_workflow"); Directory.CreateDirectory(workflowDirectory); var gitHubEvent = ExecutionContext.GetGitHubContext("event"); // adds the GitHub event path/file if the event exists if (gitHubEvent != null) { var workflowFile = Path.Combine(workflowDirectory, "event.json"); Trace.Info($"Write event payload to {workflowFile}"); File.WriteAllText(workflowFile, gitHubEvent, new UTF8Encoding(false)); ExecutionContext.SetGitHubContext("event_path", workflowFile); } // Setup container stephost for running inside the container. if (ExecutionContext.Global.Container != null) { // Make sure required container is already created. ArgUtil.NotNullOrEmpty(ExecutionContext.Global.Container.ContainerId, nameof(ExecutionContext.Global.Container.ContainerId)); var containerStepHost = HostContext.CreateService <IContainerStepHost>(); containerStepHost.Container = ExecutionContext.Global.Container; stepHost = containerStepHost; } // Load the inputs. ExecutionContext.Debug("Loading inputs"); var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator(); var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions); var userInputs = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair <string, string> input in inputs) { userInputs.Add(input.Key); string message = ""; if (definition.Data?.Deprecated?.TryGetValue(input.Key, out message) == true) { ExecutionContext.Warning(String.Format("Input '{0}' has been deprecated with message: {1}", input.Key, message)); } } var validInputs = new HashSet <string>(StringComparer.OrdinalIgnoreCase); if (handlerData.ExecutionType == ActionExecutionType.Container) { // container action always accept 'entryPoint' and 'args' as inputs // https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepswithargs validInputs.Add("entryPoint"); validInputs.Add("args"); } // Merge the default inputs from the definition if (definition.Data?.Inputs != null) { var manifestManager = HostContext.GetService <IActionManifestManager>(); foreach (var input in definition.Data.Inputs) { string key = input.Key.AssertString("action input name").Value; validInputs.Add(key); if (!inputs.ContainsKey(key)) { inputs[key] = manifestManager.EvaluateDefaultInput(ExecutionContext, key, input.Value); } } } // Validate inputs only for actions with action.yml if (Action.Reference.Type == Pipelines.ActionSourceType.Repository) { var unexpectedInputs = new List <string>(); foreach (var input in userInputs) { if (!validInputs.Contains(input)) { unexpectedInputs.Add(input); } } if (unexpectedInputs.Count > 0) { ExecutionContext.Warning($"Unexpected input(s) '{string.Join("', '", unexpectedInputs)}', valid inputs are ['{string.Join("', '", validInputs)}']"); } } // Load the action environment. ExecutionContext.Debug("Loading env"); var environment = new Dictionary <String, String>(VarUtil.EnvironmentVariableKeyComparer); #if OS_WINDOWS var envContext = ExecutionContext.ExpressionValues["env"] as DictionaryContextData; #else var envContext = ExecutionContext.ExpressionValues["env"] as CaseSensitiveDictionaryContextData; #endif // Apply environment from env context, env context contains job level env and action's evn block foreach (var env in envContext) { environment[env.Key] = env.Value.ToString(); } // Apply action's intra-action state at last foreach (var state in ExecutionContext.IntraActionState) { environment[$"STATE_{state.Key}"] = state.Value ?? string.Empty; } // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, Action.Reference, stepHost, handlerData, inputs, environment, ExecutionContext.Global.Variables, actionDirectory: definition.Directory); // Print out action details handler.PrintActionDetails(Stage); // Run the task. await handler.RunAsync(Stage); }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Action, nameof(Action)); var taskManager = HostContext.GetService <IActionManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Load the task definition and choose the handler. Definition definition = taskManager.LoadAction(ExecutionContext, Action); ArgUtil.NotNull(definition, nameof(definition)); ActionExecutionData handlerData = definition.Data?.Execution; ArgUtil.NotNull(handlerData, nameof(handlerData)); // The action has post cleanup defined. // we need to create timeline record for them and add them to the step list that StepRunner is using if (handlerData.HasCleanup && Stage == ActionRunStage.Main) { string postDisplayName = null; if (this.DisplayName.StartsWith(PipelineTemplateConstants.RunDisplayPrefix)) { postDisplayName = $"Post {this.DisplayName.Substring(PipelineTemplateConstants.RunDisplayPrefix.Length)}"; } else { postDisplayName = $"Post {this.DisplayName}"; } var repositoryReference = Action.Reference as RepositoryPathReference; var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}"; var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" : $"{repositoryReference.Name}{pathString}@{repositoryReference.Ref}"; ExecutionContext.Debug($"Register post job cleanup for action: {repoString}"); var actionRunner = HostContext.CreateService <IActionRunner>(); actionRunner.Action = Action; actionRunner.Stage = ActionRunStage.Post; actionRunner.Condition = handlerData.CleanupCondition; actionRunner.DisplayName = postDisplayName; ExecutionContext.RegisterPostJobStep($"{actionRunner.Action.Name}_post", actionRunner); } IStepHost stepHost = HostContext.CreateService <IDefaultStepHost>(); // Makes directory for event_path data var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp); var workflowDirectory = Path.Combine(tempDirectory, "_github_workflow"); Directory.CreateDirectory(workflowDirectory); var gitHubEvent = ExecutionContext.GetGitHubContext("event"); // adds the GitHub event path/file if the event exists if (gitHubEvent != null) { var workflowFile = Path.Combine(workflowDirectory, "event.json"); Trace.Info($"Write event payload to {workflowFile}"); File.WriteAllText(workflowFile, gitHubEvent, new UTF8Encoding(false)); ExecutionContext.SetGitHubContext("event_path", workflowFile); } // Setup container stephost for running inside the container. if (ExecutionContext.Container != null) { // Make sure required container is already created. ArgUtil.NotNullOrEmpty(ExecutionContext.Container.ContainerId, nameof(ExecutionContext.Container.ContainerId)); var containerStepHost = HostContext.CreateService <IContainerStepHost>(); containerStepHost.Container = ExecutionContext.Container; stepHost = containerStepHost; } // Load the inputs. ExecutionContext.Debug("Loading inputs"); var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator(); var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues); foreach (KeyValuePair <string, string> input in inputs) { string message = ""; if (definition.Data?.Deprecated?.TryGetValue(input.Key, out message) == true) { ExecutionContext.Warning(String.Format("Input '{0}' has been deprecated with message: {1}", input.Key, message)); } } // Merge the default inputs from the definition if (definition.Data?.Inputs != null) { var manifestManager = HostContext.GetService <IActionManifestManager>(); foreach (var input in (definition.Data?.Inputs)) { string key = input.Key.AssertString("action input name").Value; if (!inputs.ContainsKey(key)) { var evaluateContext = new Dictionary <string, PipelineContextData>(StringComparer.OrdinalIgnoreCase); foreach (var data in ExecutionContext.ExpressionValues) { evaluateContext[data.Key] = data.Value; } inputs[key] = manifestManager.EvaluateDefaultInput(ExecutionContext, key, input.Value, evaluateContext); } } } // Load the action environment. ExecutionContext.Debug("Loading env"); var environment = new Dictionary <String, String>(VarUtil.EnvironmentVariableKeyComparer); #if OS_WINDOWS var envContext = ExecutionContext.ExpressionValues["env"] as DictionaryContextData; #else var envContext = ExecutionContext.ExpressionValues["env"] as CaseSensitiveDictionaryContextData; #endif // Apply environment from env context, env context contains job level env and action's evn block foreach (var env in envContext) { environment[env.Key] = env.Value.ToString(); } // Apply action's intra-action state at last foreach (var state in ExecutionContext.IntraActionState) { environment[$"STATE_{state.Key}"] = state.Value ?? string.Empty; } // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, Action.Reference, stepHost, handlerData, inputs, environment, ExecutionContext.Variables, actionDirectory: definition.Directory); // Print out action details handler.PrintActionDetails(Stage); // Run the task. await handler.RunAsync(Stage); }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Action, nameof(Action)); var taskManager = HostContext.GetService <IActionManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Load the task definition and choose the handler. Definition definition = taskManager.LoadAction(ExecutionContext, Action); ArgUtil.NotNull(definition, nameof(definition)); ActionExecutionData handlerData = definition.Data?.Execution; ArgUtil.NotNull(handlerData, nameof(handlerData)); if (handlerData.HasPre && Action.Reference is Pipelines.RepositoryPathReference repoAction && string.Equals(repoAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase)) { ExecutionContext.Warning($"`pre` execution is not supported for local action from '{repoAction.Path}'"); } // The action has post cleanup defined. // we need to create timeline record for them and add them to the step list that StepRunner is using if (handlerData.HasPost && (Stage == ActionRunStage.Pre || Stage == ActionRunStage.Main)) { string postDisplayName = $"Post {this.DisplayName}"; if (Stage == ActionRunStage.Pre && this.DisplayName.StartsWith("Pre ", StringComparison.OrdinalIgnoreCase)) { // Trim the leading `Pre ` from the display name. // Otherwise, we will get `Post Pre xxx` as DisplayName for the Post step. postDisplayName = $"Post {this.DisplayName.Substring("Pre ".Length)}"; } var repositoryReference = Action.Reference as RepositoryPathReference; var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}"; var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" : $"{repositoryReference.Name}{pathString}@{repositoryReference.Ref}"; ExecutionContext.Debug($"Register post job cleanup for action: {repoString}"); var actionRunner = HostContext.CreateService <IActionRunner>(); actionRunner.Action = Action; actionRunner.Stage = ActionRunStage.Post; actionRunner.Condition = handlerData.CleanupCondition; actionRunner.DisplayName = postDisplayName; ExecutionContext.RegisterPostJobStep(actionRunner); } IStepHost stepHost = HostContext.CreateService <IDefaultStepHost>(); // Makes directory for event_path data var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp); var workflowDirectory = Path.Combine(tempDirectory, "_github_workflow"); Directory.CreateDirectory(workflowDirectory); var gitHubEvent = ExecutionContext.GetGitHubContext("event"); // adds the GitHub event path/file if the event exists if (gitHubEvent != null) { var workflowFile = Path.Combine(workflowDirectory, "event.json"); Trace.Info($"Write event payload to {workflowFile}"); File.WriteAllText(workflowFile, gitHubEvent, new UTF8Encoding(false)); ExecutionContext.SetGitHubContext("event_path", workflowFile); } // Set GITHUB_ACTION_REPOSITORY if this Action is from a repository if (Action.Reference is Pipelines.RepositoryPathReference repoPathReferenceAction && !string.Equals(repoPathReferenceAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase)) { ExecutionContext.SetGitHubContext("action_repository", repoPathReferenceAction.Name); ExecutionContext.SetGitHubContext("action_ref", repoPathReferenceAction.Ref); }