public async Task RunAsync(ActionRunStage stage) { // Validate args. Trace.Entering(); ArgUtil.NotNull(Data, nameof(Data)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Inputs, nameof(Inputs)); string plugin = null; if (stage == ActionRunStage.Main) { plugin = Data.Plugin; } else if (stage == ActionRunStage.Post) { plugin = Data.Cleanup; } ArgUtil.NotNullOrEmpty(plugin, nameof(plugin)); // Update the env dictionary. AddPrependPathToEnvironment(); // Make sure only particular task get run as runner plugin. var runnerPlugin = HostContext.GetService <IRunnerPluginManager>(); using (var outputManager = new OutputManager(ExecutionContext, ActionCommandManager)) { ActionCommandManager.EnablePluginInternalCommand(); try { await runnerPlugin.RunPluginActionAsync(ExecutionContext, plugin, Inputs, Environment, RuntimeVariables, outputManager.OnDataReceived); } finally { ActionCommandManager.DisablePluginInternalCommand(); } } }
public async Task RunAsync(ActionRunStage stage) { // Validate args. Trace.Entering(); ArgUtil.NotNull(Data, nameof(Data)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Inputs, nameof(Inputs)); ArgUtil.Directory(ActionDirectory, nameof(ActionDirectory)); // Update the env dictionary. AddInputsToEnvironment(); AddPrependPathToEnvironment(); // expose context to environment foreach (var context in ExecutionContext.ExpressionValues) { if (context.Value is IEnvironmentContextData runtimeContext && runtimeContext != null) { foreach (var env in runtimeContext.GetRuntimeEnvironmentVariables()) { Environment[env.Key] = env.Value; } } } // Add Actions Runtime server info var systemConnection = ExecutionContext.Global.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase)); Environment["ACTIONS_RUNTIME_URL"] = systemConnection.Url.AbsoluteUri; Environment["ACTIONS_RUNTIME_TOKEN"] = systemConnection.Authorization.Parameters[EndpointAuthorizationParameters.AccessToken]; if (systemConnection.Data.TryGetValue("CacheServerUrl", out var cacheUrl) && !string.IsNullOrEmpty(cacheUrl)) { Environment["ACTIONS_CACHE_URL"] = cacheUrl; } // Resolve the target script. string target = null; if (stage == ActionRunStage.Main) { target = Data.Script; } else if (stage == ActionRunStage.Pre) { target = Data.Pre; } else if (stage == ActionRunStage.Post) { target = Data.Post; } ArgUtil.NotNullOrEmpty(target, nameof(target)); target = Path.Combine(ActionDirectory, target); ArgUtil.File(target, nameof(target)); // Resolve the working directory. string workingDirectory = ExecutionContext.GetGitHubContext("workspace"); if (string.IsNullOrEmpty(workingDirectory)) { workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work); } var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext); string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}"); if (System.Environment.GetEnvironmentVariable("K8S_POD_NAME") != null) { file = Path.Combine(Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Work), "__externals_copy"), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}"); } // Format the arguments passed to node. // 1) Wrap the script file path in double quotes. // 2) Escape double quotes within the script file path. Double-quote is a valid // file name character on Linux. string arguments = StepHost.ResolvePathForStepHost(StringUtil.Format(@"""{0}""", target.Replace(@"""", @"\"""))); #if OS_WINDOWS // It appears that node.exe outputs UTF8 when not in TTY mode. Encoding outputEncoding = Encoding.UTF8; #else // Let .NET choose the default. Encoding outputEncoding = null; #endif using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager)) using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager)) { StepHost.OutputDataReceived += stdoutManager.OnDataReceived; StepHost.ErrorDataReceived += stderrManager.OnDataReceived; // Execute the process. Exit code 0 should always be returned. // A non-zero exit code indicates infrastructural failure. // Task failure should be communicated over STDOUT using ## commands. Task <int> step = StepHost.ExecuteAsync(workingDirectory: StepHost.ResolvePathForStepHost(workingDirectory), fileName: StepHost.ResolvePathForStepHost(file), arguments: arguments, environment: Environment, requireExitCodeZero: false, outputEncoding: outputEncoding, killProcessOnCancel: false, inheritConsoleHandler: !ExecutionContext.Global.Variables.Retain_Default_Encoding, cancellationToken: ExecutionContext.CancellationToken); // Wait for either the node exit or force finish through ##vso command await System.Threading.Tasks.Task.WhenAny(step, ExecutionContext.ForceCompleted); if (ExecutionContext.ForceCompleted.IsCompleted) { ExecutionContext.Debug("The task was marked as \"done\", but the process has not closed after 5 seconds. Treating the task as complete."); } else { var exitCode = await step; ExecutionContext.Debug($"Node Action run completed with exit code {exitCode}"); if (exitCode != 0) { ExecutionContext.Result = TaskResult.Failed; } } } }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously (method has async logic on only certain platforms) public async Task RunAsync(ActionRunStage stage) #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { // Validate args. Trace.Entering(); ArgUtil.NotNull(Data, nameof(Data)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); #if OS_WINDOWS || OS_OSX throw new NotSupportedException($"Container action is only supported on Linux"); #else // Update the env dictionary. AddInputsToEnvironment(); var dockerManger = HostContext.GetService <IDockerCommandManager>(); // container image haven't built/pull if (Data.Image.StartsWith("docker://", StringComparison.OrdinalIgnoreCase)) { Data.Image = Data.Image.Substring("docker://".Length); } else if (Data.Image.EndsWith("Dockerfile") || Data.Image.EndsWith("dockerfile")) { // ensure docker file exist var dockerFile = Path.Combine(ActionDirectory, Data.Image); ArgUtil.File(dockerFile, nameof(Data.Image)); ExecutionContext.Output($"Dockerfile for action: '{dockerFile}'."); var imageName = $"{dockerManger.DockerInstanceLabel}:{ExecutionContext.Id.ToString("N")}"; var buildExitCode = await dockerManger.DockerBuild(ExecutionContext, ExecutionContext.GetGitHubContext("workspace"), Directory.GetParent(dockerFile).FullName, imageName); if (buildExitCode != 0) { throw new InvalidOperationException($"Docker build failed with exit code {buildExitCode}"); } Data.Image = imageName; } // run container var container = new ContainerInfo() { ContainerImage = Data.Image, ContainerName = ExecutionContext.Id.ToString("N"), ContainerDisplayName = $"{Pipelines.Validation.NameValidation.Sanitize(Data.Image)}_{Guid.NewGuid().ToString("N").Substring(0, 6)}", }; if (stage == ActionRunStage.Main) { if (!string.IsNullOrEmpty(Data.EntryPoint)) { // use entrypoint from action.yml container.ContainerEntryPoint = Data.EntryPoint; } else { // use entrypoint input, this is for action v1 which doesn't have action.yml container.ContainerEntryPoint = Inputs.GetValueOrDefault("entryPoint"); } } else if (stage == ActionRunStage.Post) { container.ContainerEntryPoint = Data.Cleanup; } // create inputs context for template evaluation var inputsContext = new DictionaryContextData(); if (this.Inputs != null) { foreach (var input in Inputs) { inputsContext.Add(input.Key, new StringContextData(input.Value)); } } var evaluateContext = new Dictionary <string, PipelineContextData>(StringComparer.OrdinalIgnoreCase); evaluateContext["inputs"] = inputsContext; var manifestManager = HostContext.GetService <IActionManifestManager>(); if (Data.Arguments != null) { container.ContainerEntryPointArgs = ""; var evaluatedArgs = manifestManager.EvaluateContainerArguments(ExecutionContext, Data.Arguments, evaluateContext); foreach (var arg in evaluatedArgs) { if (!string.IsNullOrEmpty(arg)) { container.ContainerEntryPointArgs = container.ContainerEntryPointArgs + $" \"{arg.Replace("\"", "\\\"")}\""; } else { container.ContainerEntryPointArgs = container.ContainerEntryPointArgs + " \"\""; } } } else { container.ContainerEntryPointArgs = Inputs.GetValueOrDefault("args"); } if (Data.Environment != null) { var evaluatedEnv = manifestManager.EvaluateContainerEnvironment(ExecutionContext, Data.Environment, evaluateContext); foreach (var env in evaluatedEnv) { if (!this.Environment.ContainsKey(env.Key)) { this.Environment[env.Key] = env.Value; } } } if (ExecutionContext.JobContext.Container.TryGetValue("network", out var networkContextData) && networkContextData is StringContextData networkStringData) { container.ContainerNetwork = networkStringData.ToString(); } var defaultWorkingDirectory = ExecutionContext.GetGitHubContext("workspace"); var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp); ArgUtil.NotNullOrEmpty(defaultWorkingDirectory, nameof(defaultWorkingDirectory)); ArgUtil.NotNullOrEmpty(tempDirectory, nameof(tempDirectory)); var tempHomeDirectory = Path.Combine(tempDirectory, "_github_home"); Directory.CreateDirectory(tempHomeDirectory); this.Environment["HOME"] = tempHomeDirectory; var tempWorkflowDirectory = Path.Combine(tempDirectory, "_github_workflow"); ArgUtil.Directory(tempWorkflowDirectory, nameof(tempWorkflowDirectory)); container.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock")); container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home")); container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow")); container.MountVolumes.Add(new MountVolume(defaultWorkingDirectory, "/github/workspace")); container.AddPathTranslateMapping(tempHomeDirectory, "/github/home"); container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow"); container.AddPathTranslateMapping(defaultWorkingDirectory, "/github/workspace"); container.ContainerWorkDirectory = "/github/workspace"; // expose context to environment foreach (var context in ExecutionContext.ExpressionValues) { if (context.Value is IEnvironmentContextData runtimeContext && runtimeContext != null) { foreach (var env in runtimeContext.GetRuntimeEnvironmentVariables()) { Environment[env.Key] = env.Value; } } } // Add Actions Runtime server info var systemConnection = ExecutionContext.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase)); Environment["ACTIONS_RUNTIME_URL"] = systemConnection.Url.AbsoluteUri; Environment["ACTIONS_RUNTIME_TOKEN"] = systemConnection.Authorization.Parameters[EndpointAuthorizationParameters.AccessToken]; if (systemConnection.Data.TryGetValue("CacheServerUrl", out var cacheUrl) && !string.IsNullOrEmpty(cacheUrl)) { Environment["ACTIONS_CACHE_URL"] = cacheUrl; } foreach (var variable in this.Environment) { container.ContainerEnvironmentVariables[variable.Key] = container.TranslateToContainerPath(variable.Value); } using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager, container)) using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager, container)) { var runExitCode = await dockerManger.DockerRun(ExecutionContext, container, stdoutManager.OnDataReceived, stderrManager.OnDataReceived); ExecutionContext.Debug($"Docker Action run completed with exit code {runExitCode}"); if (runExitCode != 0) { ExecutionContext.Result = TaskResult.Failed; } } #endif }
public async Task RunAsync(ActionRunStage stage) { if (stage == ActionRunStage.Post) { throw new NotSupportedException("Script action should not have 'Post' job action."); } // Validate args Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Inputs, nameof(Inputs)); var githubContext = ExecutionContext.ExpressionValues["github"] as GitHubContext; ArgUtil.NotNull(githubContext, nameof(githubContext)); var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp); Inputs.TryGetValue("script", out var contents); contents = contents ?? string.Empty; Inputs.TryGetValue("workingDirectory", out var workingDirectory); var workspaceDir = githubContext["workspace"] as StringContextData; workingDirectory = Path.Combine(workspaceDir, workingDirectory ?? string.Empty); Inputs.TryGetValue("shell", out var shell); var isContainerStepHost = StepHost is ContainerStepHost; string prependPath = string.Join(Path.PathSeparator.ToString(), ExecutionContext.PrependPath.Reverse <string>()); string commandPath, argFormat, shellCommand; // Set up default command and arguments if (string.IsNullOrEmpty(shell)) { #if OS_WINDOWS shellCommand = "pwsh"; commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath); if (string.IsNullOrEmpty(commandPath)) { shellCommand = "powershell"; Trace.Info($"Defaulting to {shellCommand}"); commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath); } ArgUtil.NotNullOrEmpty(commandPath, "Default Shell"); #else shellCommand = "sh"; commandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath); #endif argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand); } else { var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell); shellCommand = parsed.shellCommand; // For non-ContainerStepHost, the command must be located on the host by Which commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath); argFormat = $"{parsed.shellArgs}".TrimStart(); if (string.IsNullOrEmpty(argFormat)) { argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand); } } // No arg format was given, shell must be a built-in if (string.IsNullOrEmpty(argFormat) || !argFormat.Contains("{0}")) { throw new ArgumentException("Invalid shell option. Shell must be a valid built-in (bash, sh, cmd, powershell, pwsh) or a format string containing '{0}'"); } // We do not not the full path until we know what shell is being used, so that we can determine the file extension var scriptFilePath = Path.Combine(tempDirectory, $"{Guid.NewGuid()}{ScriptHandlerHelpers.GetScriptFileExtension(shellCommand)}"); var resolvedScriptPath = $"{StepHost.ResolvePathForStepHost(scriptFilePath).Replace("\"", "\\\"")}"; // Format arg string with script path var arguments = string.Format(argFormat, resolvedScriptPath); // Fix up and write the script contents = ScriptHandlerHelpers.FixUpScriptContents(shellCommand, contents); #if OS_WINDOWS // Normalize Windows line endings contents = contents.Replace("\r\n", "\n").Replace("\n", "\r\n"); var encoding = ExecutionContext.Variables.Retain_Default_Encoding && Console.InputEncoding.CodePage != 65001 ? Console.InputEncoding : new UTF8Encoding(false); #else // Don't add a BOM. It causes the script to fail on some operating systems (e.g. on Ubuntu 14). var encoding = new UTF8Encoding(false); #endif // Script is written to local path (ie host) but executed relative to the StepHost, which may be a container File.WriteAllText(scriptFilePath, contents, encoding); // Prepend PATH AddPrependPathToEnvironment(); // expose context to environment foreach (var context in ExecutionContext.ExpressionValues) { if (context.Value is IEnvironmentContextData runtimeContext && runtimeContext != null) { foreach (var env in runtimeContext.GetRuntimeEnvironmentVariables()) { Environment[env.Key] = env.Value; } } } // dump out the command var fileName = isContainerStepHost ? shellCommand : commandPath; ExecutionContext.Debug($"{fileName} {arguments}"); using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager)) using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager)) { StepHost.OutputDataReceived += stdoutManager.OnDataReceived; StepHost.ErrorDataReceived += stderrManager.OnDataReceived; // Execute int exitCode = await StepHost.ExecuteAsync(workingDirectory : StepHost.ResolvePathForStepHost(workingDirectory), fileName : fileName, arguments : arguments, environment : Environment, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, inheritConsoleHandler : !ExecutionContext.Variables.Retain_Default_Encoding, cancellationToken : ExecutionContext.CancellationToken); // Error if (exitCode != 0) { ExecutionContext.Error($"Process completed with exit code {exitCode}."); ExecutionContext.Result = TaskResult.Failed; } } }
public async Task RunAsync(ActionRunStage stage) { if (stage == ActionRunStage.Post) { throw new NotSupportedException("Script action should not have 'Post' job action."); } // Validate args Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(Inputs, nameof(Inputs)); var githubContext = ExecutionContext.ExpressionValues["github"] as GitHubContext; ArgUtil.NotNull(githubContext, nameof(githubContext)); // Add Telemetry to JobContext to send with JobCompleteMessage if (stage == ActionRunStage.Main) { var telemetry = new ActionsStepTelemetry { IsEmbedded = ExecutionContext.IsEmbedded, Type = "run", }; ExecutionContext.Root.ActionsStepsTelemetry.Add(telemetry); } var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp); Inputs.TryGetValue("script", out var contents); contents = contents ?? string.Empty; string workingDirectory = null; if (!Inputs.TryGetValue("workingDirectory", out workingDirectory)) { if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults)) { if (runDefaults.TryGetValue("working-directory", out workingDirectory)) { ExecutionContext.Debug("Overwrite 'working-directory' base on job defaults."); } } } var workspaceDir = githubContext["workspace"] as StringContextData; workingDirectory = Path.Combine(workspaceDir, workingDirectory ?? string.Empty); string shell = null; if (!Inputs.TryGetValue("shell", out shell) || string.IsNullOrEmpty(shell)) { if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults)) { if (runDefaults.TryGetValue("shell", out shell)) { ExecutionContext.Debug("Overwrite 'shell' base on job defaults."); } } } var isContainerStepHost = StepHost is ContainerStepHost; string prependPath = string.Join(Path.PathSeparator.ToString(), ExecutionContext.Global.PrependPath.Reverse <string>()); string commandPath, argFormat, shellCommand; // Set up default command and arguments if (string.IsNullOrEmpty(shell)) { #if OS_WINDOWS shellCommand = "pwsh"; commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath); if (string.IsNullOrEmpty(commandPath)) { shellCommand = "powershell"; Trace.Info($"Defaulting to {shellCommand}"); commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath); } ArgUtil.NotNullOrEmpty(commandPath, "Default Shell"); #else shellCommand = "sh"; commandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath); #endif argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand); } else { var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell); shellCommand = parsed.shellCommand; // For non-ContainerStepHost, the command must be located on the host by Which commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath); argFormat = $"{parsed.shellArgs}".TrimStart(); if (string.IsNullOrEmpty(argFormat)) { argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand); } } // No arg format was given, shell must be a built-in if (string.IsNullOrEmpty(argFormat) || !argFormat.Contains("{0}")) { throw new ArgumentException("Invalid shell option. Shell must be a valid built-in (bash, sh, cmd, powershell, pwsh) or a format string containing '{0}'"); } // We do not not the full path until we know what shell is being used, so that we can determine the file extension var scriptFilePath = Path.Combine(tempDirectory, $"{Guid.NewGuid()}{ScriptHandlerHelpers.GetScriptFileExtension(shellCommand)}"); var resolvedScriptPath = $"{StepHost.ResolvePathForStepHost(scriptFilePath).Replace("\"", "\\\"")}"; // Format arg string with script path var arguments = string.Format(argFormat, resolvedScriptPath); // Fix up and write the script contents = ScriptHandlerHelpers.FixUpScriptContents(shellCommand, contents); #if OS_WINDOWS // Normalize Windows line endings contents = contents.Replace("\r\n", "\n").Replace("\n", "\r\n"); var encoding = ExecutionContext.Global.Variables.Retain_Default_Encoding && Console.InputEncoding.CodePage != 65001 ? Console.InputEncoding : new UTF8Encoding(false); #else // Don't add a BOM. It causes the script to fail on some operating systems (e.g. on Ubuntu 14). var encoding = new UTF8Encoding(false); #endif // Script is written to local path (ie host) but executed relative to the StepHost, which may be a container File.WriteAllText(scriptFilePath, contents, encoding); // Prepend PATH AddPrependPathToEnvironment(); // expose context to environment foreach (var context in ExecutionContext.ExpressionValues) { if (context.Value is IEnvironmentContextData runtimeContext && runtimeContext != null) { foreach (var env in runtimeContext.GetRuntimeEnvironmentVariables()) { Environment[env.Key] = env.Value; } } } // dump out the command var fileName = isContainerStepHost ? shellCommand : commandPath; #if OS_OSX if (Environment.ContainsKey("DYLD_INSERT_LIBRARIES")) // We don't check `isContainerStepHost` because we don't support container on macOS { // launch `node macOSRunInvoker.js shell args` instead of `shell args` to avoid macOS SIP remove `DYLD_INSERT_LIBRARIES` when launch process string node12 = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"); string macOSRunInvoker = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "macos-run-invoker.js"); arguments = $"\"{macOSRunInvoker.Replace("\"", "\\\"")}\" \"{fileName.Replace("\"", "\\\"")}\" {arguments}"; fileName = node12; } #endif var systemConnection = ExecutionContext.Global.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase)); if (systemConnection.Data.TryGetValue("GenerateIdTokenUrl", out var generateIdTokenUrl) && !string.IsNullOrEmpty(generateIdTokenUrl)) { Environment["ACTIONS_ID_TOKEN_REQUEST_URL"] = generateIdTokenUrl; Environment["ACTIONS_ID_TOKEN_REQUEST_TOKEN"] = systemConnection.Authorization.Parameters[EndpointAuthorizationParameters.AccessToken]; } ExecutionContext.Debug($"{fileName} {arguments}"); using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager)) using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager)) { StepHost.OutputDataReceived += stdoutManager.OnDataReceived; StepHost.ErrorDataReceived += stderrManager.OnDataReceived; // Execute int exitCode = await StepHost.ExecuteAsync(workingDirectory : StepHost.ResolvePathForStepHost(workingDirectory), fileName : fileName, arguments : arguments, environment : Environment, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, inheritConsoleHandler : !ExecutionContext.Global.Variables.Retain_Default_Encoding, cancellationToken : ExecutionContext.CancellationToken); // Error if (exitCode != 0) { ExecutionContext.Error($"Process completed with exit code {exitCode}."); ExecutionContext.Result = TaskResult.Failed; } } }