Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
            }