minor cleanup in composite (#1045)

This commit is contained in:
eric sciple
2021-04-30 15:48:53 -05:00
committed by GitHub
parent 5941cceb7c
commit 7cc689b0d9
6 changed files with 136 additions and 174 deletions

View File

@@ -61,14 +61,15 @@ namespace GitHub.Runner.Worker
bool EchoOnActionCommand { get; set; } bool EchoOnActionCommand { get; set; }
bool InsideComposite { get; } bool IsEmbedded { get; }
ExecutionContext Root { get; } ExecutionContext Root { get; }
// Initialize // Initialize
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token); void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
void CancelToken(); void CancelToken();
IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool insideComposite = false, CancellationTokenSource cancellationTokenSource = null); IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null);
IExecutionContext CreateEmbeddedChild(string scopeName, string contextName);
// logging // logging
long Write(string tag, string message); long Write(string tag, string message);
@@ -99,7 +100,6 @@ namespace GitHub.Runner.Worker
// others // others
void ForceTaskComplete(); void ForceTaskComplete();
void RegisterPostJobStep(IStep step); void RegisterPostJobStep(IStep step);
IStep CreateCompositeStep(string scopeName, IActionRunner step, DictionaryContextData inputsData, Dictionary<string, string> envData);
} }
public sealed class ExecutionContext : RunnerService, IExecutionContext public sealed class ExecutionContext : RunnerService, IExecutionContext
@@ -157,7 +157,9 @@ namespace GitHub.Runner.Worker
public bool EchoOnActionCommand { get; set; } public bool EchoOnActionCommand { get; set; }
public bool InsideComposite { get; private set; } // An embedded execution context shares the same record ID, record name, and logger
// as its enclosing execution context.
public bool IsEmbedded { get; private set; }
public TaskResult? Result public TaskResult? Result
{ {
@@ -253,36 +255,7 @@ namespace GitHub.Runner.Worker
Root.PostJobSteps.Push(step); Root.PostJobSteps.Push(step);
} }
/// <summary> public IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null)
/// Helper function used in CompositeActionHandler::RunAsync to
/// add a child node, aka a step, to the current job to the Root.JobSteps based on the location.
/// </summary>
public IStep CreateCompositeStep(
string scopeName,
IActionRunner step,
DictionaryContextData inputsData,
Dictionary<string, string> envData)
{
step.ExecutionContext = Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, step.Action.ContextName, logger: _logger, insideComposite: true, cancellationTokenSource: CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token));
step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
step.ExecutionContext.ExpressionValues["steps"] = Global.StepsContext.GetScope(step.ExecutionContext.GetFullyQualifiedContextName());
// Add the composite action environment variables to each step.
#if OS_WINDOWS
var envContext = new DictionaryContextData();
#else
var envContext = new CaseSensitiveDictionaryContextData();
#endif
foreach (var pair in envData)
{
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
}
step.ExecutionContext.ExpressionValues["env"] = envContext;
return step;
}
public IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool insideComposite = false, CancellationTokenSource cancellationTokenSource = null)
{ {
Trace.Entering(); Trace.Entering();
@@ -329,11 +302,20 @@ namespace GitHub.Runner.Worker
child._logger.Setup(_mainTimelineId, recordId); child._logger.Setup(_mainTimelineId, recordId);
} }
child.InsideComposite = insideComposite; child.IsEmbedded = isEmbedded;
return child; return child;
} }
/// <summary>
/// An embedded execution context shares the same record ID, record name, logger,
/// and a linked cancellation token.
/// </summary>
public IExecutionContext CreateEmbeddedChild(string scopeName, string contextName)
{
return Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, contextName, logger: _logger, isEmbedded: true, cancellationTokenSource: CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token));
}
public void Start(string currentOperation = null) public void Start(string currentOperation = null)
{ {
_record.CurrentOperation = currentOperation ?? _record.CurrentOperation; _record.CurrentOperation = currentOperation ?? _record.CurrentOperation;

View File

@@ -26,65 +26,60 @@ namespace GitHub.Runner.Worker.Handlers
public async Task RunAsync(ActionRunStage stage) public async Task RunAsync(ActionRunStage stage)
{ {
// Validate args. // Validate args
Trace.Entering(); Trace.Entering();
ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext));
ArgUtil.NotNull(Inputs, nameof(Inputs)); ArgUtil.NotNull(Inputs, nameof(Inputs));
ArgUtil.NotNull(Data.Steps, nameof(Data.Steps)); ArgUtil.NotNull(Data.Steps, nameof(Data.Steps));
// Resolve action steps
var actionSteps = Data.Steps;
// Create Context Data to reuse for each composite action step
var inputsData = new DictionaryContextData();
foreach (var i in Inputs)
{
inputsData[i.Key] = new StringContextData(i.Value);
}
// Initialize Composite Steps List of Steps
var compositeSteps = new List<IStep>();
// Temporary hack until after M271-ish. After M271-ish the server will never send an empty
// context name. Generated context names start with "__"
var childScopeName = ExecutionContext.GetFullyQualifiedContextName();
if (string.IsNullOrEmpty(childScopeName))
{
childScopeName = $"__{Guid.NewGuid()}";
}
foreach (Pipelines.ActionStep actionStep in actionSteps)
{
var actionRunner = HostContext.CreateService<IActionRunner>();
actionRunner.Action = actionStep;
actionRunner.Stage = stage;
actionRunner.Condition = actionStep.Condition;
var step = ExecutionContext.CreateCompositeStep(childScopeName, actionRunner, inputsData, Environment);
// Shallow copy github context
var gitHubContext = step.ExecutionContext.ExpressionValues["github"] as GitHubContext;
ArgUtil.NotNull(gitHubContext, nameof(gitHubContext));
gitHubContext = gitHubContext.ShallowCopy();
step.ExecutionContext.ExpressionValues["github"] = gitHubContext;
// Set GITHUB_ACTION_PATH
step.ExecutionContext.SetGitHubContext("action_path", ActionDirectory);
compositeSteps.Add(step);
}
try try
{ {
// This is where we run each step. // Inputs of the composite step
await RunStepsAsync(compositeSteps); var inputsData = new DictionaryContextData();
foreach (var i in Inputs)
{
inputsData[i.Key] = new StringContextData(i.Value);
}
// Get the pointer of the correct "steps" object and pass it to the ExecutionContext so that we can process the outputs correctly // Temporary hack until after M271-ish. After M271-ish the server will never send an empty
// context name. Generated context names start with "__"
var childScopeName = ExecutionContext.GetFullyQualifiedContextName();
if (string.IsNullOrEmpty(childScopeName))
{
childScopeName = $"__{Guid.NewGuid()}";
}
// Create nested steps
var nestedSteps = new List<IStep>();
foreach (Pipelines.ActionStep stepData in Data.Steps)
{
var step = HostContext.CreateService<IActionRunner>();
step.Action = stepData;
step.Stage = stage;
step.Condition = stepData.Condition;
step.ExecutionContext = ExecutionContext.CreateEmbeddedChild(childScopeName, stepData.ContextName);
step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
step.ExecutionContext.ExpressionValues["steps"] = ExecutionContext.Global.StepsContext.GetScope(childScopeName);
// Shallow copy github context
var gitHubContext = step.ExecutionContext.ExpressionValues["github"] as GitHubContext;
ArgUtil.NotNull(gitHubContext, nameof(gitHubContext));
gitHubContext = gitHubContext.ShallowCopy();
step.ExecutionContext.ExpressionValues["github"] = gitHubContext;
// Set GITHUB_ACTION_PATH
step.ExecutionContext.SetGitHubContext("action_path", ActionDirectory);
nestedSteps.Add(step);
}
// Run nested steps
await RunStepsAsync(nestedSteps);
// Set outputs
ExecutionContext.ExpressionValues["inputs"] = inputsData; ExecutionContext.ExpressionValues["inputs"] = inputsData;
ExecutionContext.ExpressionValues["steps"] = ExecutionContext.Global.StepsContext.GetScope(ExecutionContext.GetFullyQualifiedContextName()); ExecutionContext.ExpressionValues["steps"] = ExecutionContext.Global.StepsContext.GetScope(childScopeName);
ProcessOutputs();
ProcessCompositeActionOutputs();
ExecutionContext.Global.StepsContext.ClearScope(childScopeName); ExecutionContext.Global.StepsContext.ClearScope(childScopeName);
} }
catch (Exception ex) catch (Exception ex)
@@ -96,7 +91,7 @@ namespace GitHub.Runner.Worker.Handlers
} }
} }
private void ProcessCompositeActionOutputs() private void ProcessOutputs()
{ {
ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext));
@@ -113,69 +108,57 @@ namespace GitHub.Runner.Worker.Handlers
evaluateContext[pair.Key] = pair.Value; evaluateContext[pair.Key] = pair.Value;
} }
// Get the evluated composite outputs' values mapped to the outputs named // Evaluate outputs
DictionaryContextData actionOutputs = actionManifestManager.EvaluateCompositeOutputs(ExecutionContext, Data.Outputs, evaluateContext); DictionaryContextData actionOutputs = actionManifestManager.EvaluateCompositeOutputs(ExecutionContext, Data.Outputs, evaluateContext);
// Set the outputs for the outputs object in the whole composite action // Set outputs
// Each pair is structured like this //
// We ignore "description" for now // Each pair is structured like:
// { // {
// "the-output-name": { // "the-output-name": {
// "description": "", // "description": "",
// "value": "the value" // "value": "the value"
// }, // },
// ... // ...
// } // }
foreach (var pair in actionOutputs) foreach (var pair in actionOutputs)
{ {
var outputsName = pair.Key; var outputName = pair.Key;
var outputsAttributes = pair.Value as DictionaryContextData; var outputDefinition = pair.Value as DictionaryContextData;
outputsAttributes.TryGetValue("value", out var val); if (outputDefinition.TryGetValue("value", out var val))
if (val != null)
{ {
var outputsValue = val as StringContextData; var outputValue = val.AssertString("output value");
// Set output in the whole composite scope. ExecutionContext.SetOutput(outputName, outputValue.Value, out _);
if (!String.IsNullOrEmpty(outputsValue))
{
ExecutionContext.SetOutput(outputsName, outputsValue, out _);
}
else
{
ExecutionContext.SetOutput(outputsName, "", out _);
}
} }
} }
} }
} }
private async Task RunStepsAsync(List<IStep> compositeSteps) private async Task RunStepsAsync(List<IStep> nestedSteps)
{ {
ArgUtil.NotNull(compositeSteps, nameof(compositeSteps)); ArgUtil.NotNull(nestedSteps, nameof(nestedSteps));
// The parent StepsRunner of the whole Composite Action Step handles the cancellation stuff already. foreach (IStep step in nestedSteps)
foreach (IStep step in compositeSteps)
{ {
Trace.Info($"Processing composite step: DisplayName='{step.DisplayName}'"); Trace.Info($"Processing nested step: DisplayName='{step.DisplayName}'");
step.ExecutionContext.ExpressionValues["steps"] = ExecutionContext.Global.StepsContext.GetScope(step.ExecutionContext.ScopeName); // Initialize env context
Trace.Info("Initialize Env context for nested step");
// Populate env context for each step
Trace.Info("Initialize Env context for step");
#if OS_WINDOWS #if OS_WINDOWS
var envContext = new DictionaryContextData(); var envContext = new DictionaryContextData();
#else #else
var envContext = new CaseSensitiveDictionaryContextData(); var envContext = new CaseSensitiveDictionaryContextData();
#endif #endif
step.ExecutionContext.ExpressionValues["env"] = envContext;
// Global env // Merge global env
foreach (var pair in ExecutionContext.Global.EnvironmentVariables) foreach (var pair in ExecutionContext.Global.EnvironmentVariables)
{ {
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty); envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
} }
// Stomps over with outside step env // Merge composite-step env
if (step.ExecutionContext.ExpressionValues.TryGetValue("env", out var envContextData)) if (ExecutionContext.ExpressionValues.TryGetValue("env", out var envContextData))
{ {
#if OS_WINDOWS #if OS_WINDOWS
var dict = envContextData as DictionaryContextData; var dict = envContextData as DictionaryContextData;
@@ -188,13 +171,11 @@ namespace GitHub.Runner.Worker.Handlers
} }
} }
step.ExecutionContext.ExpressionValues["env"] = envContext;
var actionStep = step as IActionRunner; var actionStep = step as IActionRunner;
try try
{ {
// Evaluate and merge action's env block to env context // Evaluate and merge nested-step env
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(); var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, Common.Util.VarUtil.EnvironmentVariableKeyComparer); var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, Common.Util.VarUtil.EnvironmentVariableKeyComparer);
foreach (var env in actionEnvironment) foreach (var env in actionEnvironment)
@@ -204,39 +185,28 @@ namespace GitHub.Runner.Worker.Handlers
} }
catch (Exception ex) catch (Exception ex)
{ {
// fail the step since there is an evaluate error. // Evaluation error
Trace.Info("Caught exception in Composite Steps Runner from expression for step.env"); Trace.Info("Caught exception from expression for nested step.env");
// evaluateStepEnvFailed = true;
step.ExecutionContext.Error(ex); step.ExecutionContext.Error(ex);
step.ExecutionContext.Complete(TaskResult.Failed); step.ExecutionContext.Complete(TaskResult.Failed);
} }
await RunStepAsync(step); await RunStepAsync(step);
// Directly after the step, check if the step has failed or cancelled // Check failed or canceled
// If so, return that to the output
if (step.ExecutionContext.Result == TaskResult.Failed || step.ExecutionContext.Result == TaskResult.Canceled) if (step.ExecutionContext.Result == TaskResult.Failed || step.ExecutionContext.Result == TaskResult.Canceled)
{ {
ExecutionContext.Result = step.ExecutionContext.Result; ExecutionContext.Result = step.ExecutionContext.Result;
break; break;
} }
// TODO: Add compat for other types of steps.
} }
// Completion Status handled by StepsRunner for the whole Composite Action Step
} }
private async Task RunStepAsync(IStep step) private async Task RunStepAsync(IStep step)
{ {
// Start the step. Trace.Info($"Starting: {step.DisplayName}");
Trace.Info("Starting the step.");
step.ExecutionContext.Debug($"Starting: {step.DisplayName}"); step.ExecutionContext.Debug($"Starting: {step.DisplayName}");
// TODO: Fix for Step Level Timeout Attributes for an individual Composite Run Step
// For now, we are not going to support this for an individual composite run step
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
await Common.Util.EncodingUtil.SetEncoding(HostContext, Trace, step.ExecutionContext.CancellationToken); await Common.Util.EncodingUtil.SetEncoding(HostContext, Trace, step.ExecutionContext.CancellationToken);
try try
@@ -261,7 +231,7 @@ namespace GitHub.Runner.Worker.Handlers
} }
catch (Exception ex) catch (Exception ex)
{ {
// Log the error and fail the step. // Log the error and fail the step
Trace.Error($"Caught exception from step: {ex}"); Trace.Error($"Caught exception from step: {ex}");
step.ExecutionContext.Error(ex); step.ExecutionContext.Error(ex);
step.ExecutionContext.Result = TaskResult.Failed; step.ExecutionContext.Result = TaskResult.Failed;
@@ -274,9 +244,7 @@ namespace GitHub.Runner.Worker.Handlers
} }
Trace.Info($"Step result: {step.ExecutionContext.Result}"); Trace.Info($"Step result: {step.ExecutionContext.Result}");
step.ExecutionContext.Debug($"Finished: {step.DisplayName}");
// Complete the step context.
step.ExecutionContext.Debug($"Finishing: {step.DisplayName}");
} }
} }
} }

View File

@@ -26,7 +26,7 @@ namespace GitHub.Runner.Worker.Handlers
// We don't want to display the internal workings if composite (similar/equivalent information can be found in debug) // We don't want to display the internal workings if composite (similar/equivalent information can be found in debug)
void writeDetails(string message) void writeDetails(string message)
{ {
if (ExecutionContext.InsideComposite) if (ExecutionContext.IsEmbedded)
{ {
ExecutionContext.Debug(message); ExecutionContext.Debug(message);
} }
@@ -52,7 +52,7 @@ namespace GitHub.Runner.Worker.Handlers
firstLine = firstLine.Substring(0, firstNewLine); firstLine = firstLine.Substring(0, firstNewLine);
} }
writeDetails(ExecutionContext.InsideComposite ? $"Run {firstLine}" : $"##[group]Run {firstLine}"); writeDetails(ExecutionContext.IsEmbedded ? $"Run {firstLine}" : $"##[group]Run {firstLine}");
} }
else else
{ {
@@ -138,7 +138,7 @@ namespace GitHub.Runner.Worker.Handlers
} }
} }
writeDetails(ExecutionContext.InsideComposite ? "" : "##[endgroup]"); writeDetails(ExecutionContext.IsEmbedded ? "" : "##[endgroup]");
} }
public async Task RunAsync(ActionRunStage stage) public async Task RunAsync(ActionRunStage stage)

View File

@@ -10,11 +10,19 @@ using GitHub.Runner.Sdk;
namespace GitHub.Runner.Worker namespace GitHub.Runner.Worker
{ {
/// <summary>
/// Manages the "steps" context. The "steps" context is used to track individual steps
/// "outcome", "conclusion", and "outputs".
/// </summary>
public sealed class StepsContext public sealed class StepsContext
{ {
private static readonly Regex _propertyRegex = new Regex("^[a-zA-Z_][a-zA-Z0-9_]*$", RegexOptions.Compiled); private static readonly Regex _propertyRegex = new Regex("^[a-zA-Z_][a-zA-Z0-9_]*$", RegexOptions.Compiled);
private readonly DictionaryContextData _contextData = new DictionaryContextData(); private readonly DictionaryContextData _contextData = new DictionaryContextData();
/// <summary>
/// Clears memory for a composite action's isolated "steps" context, after the action
/// is finished executing.
/// </summary>
public void ClearScope(string scopeName) public void ClearScope(string scopeName)
{ {
if (_contextData.TryGetValue(scopeName, out _)) if (_contextData.TryGetValue(scopeName, out _))
@@ -23,6 +31,14 @@ namespace GitHub.Runner.Worker
} }
} }
/// <summary>
/// Gets the "steps" context for a given scope. The root steps in a workflow use the
/// default "steps" context (i.e. scopeName="").
///
/// An isolated "steps" context is created for each composite action. All child steps
/// within a composite action, share an isolated "steps" context. The scope name matches
/// the composite action's fully qualified context name.
/// </summary>
public DictionaryContextData GetScope(string scopeName) public DictionaryContextData GetScope(string scopeName)
{ {
if (scopeName == null) if (scopeName == null)

View File

@@ -82,24 +82,21 @@ namespace GitHub.Runner.Worker
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<SuccessFunction>(PipelineTemplateConstants.Success, 0, 0)); step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<SuccessFunction>(PipelineTemplateConstants.Success, 0, 0));
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<HashFilesFunction>(PipelineTemplateConstants.HashFiles, 1, byte.MaxValue)); step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<HashFilesFunction>(PipelineTemplateConstants.HashFiles, 1, byte.MaxValue));
// Expression values
step.ExecutionContext.ExpressionValues["steps"] = step.ExecutionContext.Global.StepsContext.GetScope(step.ExecutionContext.ScopeName); step.ExecutionContext.ExpressionValues["steps"] = step.ExecutionContext.Global.StepsContext.GetScope(step.ExecutionContext.ScopeName);
// Populate env context for each step
Trace.Info("Initialize Env context for step");
#if OS_WINDOWS #if OS_WINDOWS
var envContext = new DictionaryContextData(); var envContext = new DictionaryContextData();
#else #else
var envContext = new CaseSensitiveDictionaryContextData(); var envContext = new CaseSensitiveDictionaryContextData();
#endif #endif
step.ExecutionContext.ExpressionValues["env"] = envContext;
// Global env // Merge global env
foreach (var pair in step.ExecutionContext.Global.EnvironmentVariables) foreach (var pair in step.ExecutionContext.Global.EnvironmentVariables)
{ {
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty); envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
} }
step.ExecutionContext.ExpressionValues["env"] = envContext;
bool evaluateStepEnvFailed = false; bool evaluateStepEnvFailed = false;
if (step is IActionRunner actionStep) if (step is IActionRunner actionStep)
{ {
@@ -108,7 +105,7 @@ namespace GitHub.Runner.Worker
try try
{ {
// Evaluate and merge action's env block to env context // Evaluate and merge step env
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(); var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer); var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer);
foreach (var env in actionEnvironment) foreach (var env in actionEnvironment)
@@ -118,7 +115,7 @@ namespace GitHub.Runner.Worker
} }
catch (Exception ex) catch (Exception ex)
{ {
// fail the step since there is an evaluate error. // Fail the step since there is an evaluate error
Trace.Info("Caught exception from expression for step.env"); Trace.Info("Caught exception from expression for step.env");
evaluateStepEnvFailed = true; evaluateStepEnvFailed = true;
step.ExecutionContext.Error(ex); step.ExecutionContext.Error(ex);
@@ -136,7 +133,7 @@ namespace GitHub.Runner.Worker
// Test the condition again. The job was canceled after the condition was originally evaluated. // Test the condition again. The job was canceled after the condition was originally evaluated.
jobCancelRegister = jobContext.CancellationToken.Register(() => jobCancelRegister = jobContext.CancellationToken.Register(() =>
{ {
// mark job as cancelled // Mark job as cancelled
jobContext.Result = TaskResult.Canceled; jobContext.Result = TaskResult.Canceled;
jobContext.JobContext.Status = jobContext.Result?.ToActionResult(); jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
@@ -157,7 +154,7 @@ namespace GitHub.Runner.Worker
} }
catch (Exception ex) catch (Exception ex)
{ {
// Cancel the step since we get exception while re-evaluate step condition. // Cancel the step since we get exception while re-evaluate step condition
Trace.Info("Caught exception from expression when re-test condition on job cancellation."); Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
step.ExecutionContext.Error(ex); step.ExecutionContext.Error(ex);
} }
@@ -165,7 +162,7 @@ namespace GitHub.Runner.Worker
if (!conditionReTestResult) if (!conditionReTestResult)
{ {
// Cancel the step. // Cancel the step
Trace.Info("Cancel current running step."); Trace.Info("Cancel current running step.");
step.ExecutionContext.CancelToken(); step.ExecutionContext.CancelToken();
} }
@@ -175,13 +172,13 @@ namespace GitHub.Runner.Worker
{ {
if (jobContext.Result != TaskResult.Canceled) if (jobContext.Result != TaskResult.Canceled)
{ {
// mark job as cancelled // Mark job as cancelled
jobContext.Result = TaskResult.Canceled; jobContext.Result = TaskResult.Canceled;
jobContext.JobContext.Status = jobContext.Result?.ToActionResult(); jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
} }
} }
// Evaluate condition. // Evaluate condition
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'"); step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext); var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext);
var conditionResult = false; var conditionResult = false;
@@ -206,22 +203,21 @@ namespace GitHub.Runner.Worker
} }
} }
// no evaluate error but condition is false
if (!conditionResult && conditionEvaluateError == null) if (!conditionResult && conditionEvaluateError == null)
{ {
// Condition == false // Condition is false
Trace.Info("Skipping step due to condition evaluation."); Trace.Info("Skipping step due to condition evaluation.");
CompleteStep(step, TaskResult.Skipped, resultCode: conditionTraceWriter.Trace); CompleteStep(step, TaskResult.Skipped, resultCode: conditionTraceWriter.Trace);
} }
else if (conditionEvaluateError != null) else if (conditionEvaluateError != null)
{ {
// fail the step since there is an evaluate error. // Condition error
step.ExecutionContext.Error(conditionEvaluateError); step.ExecutionContext.Error(conditionEvaluateError);
CompleteStep(step, TaskResult.Failed); CompleteStep(step, TaskResult.Failed);
} }
else else
{ {
// Run the step. // Run the step
await RunStepAsync(step, jobContext.CancellationToken); await RunStepAsync(step, jobContext.CancellationToken);
CompleteStep(step); CompleteStep(step);
} }
@@ -236,7 +232,7 @@ namespace GitHub.Runner.Worker
} }
} }
// Update the job result. // Update the job result
if (step.ExecutionContext.Result == TaskResult.Failed) if (step.ExecutionContext.Result == TaskResult.Failed)
{ {
Trace.Info($"Update job result with current step result '{step.ExecutionContext.Result}'."); Trace.Info($"Update job result with current step result '{step.ExecutionContext.Result}'.");
@@ -262,7 +258,7 @@ namespace GitHub.Runner.Worker
step.ExecutionContext.UpdateTimelineRecordDisplayName(actionRunner.DisplayName); step.ExecutionContext.UpdateTimelineRecordDisplayName(actionRunner.DisplayName);
} }
// Start the step. // Start the step
Trace.Info("Starting the step."); Trace.Info("Starting the step.");
step.ExecutionContext.Debug($"Starting: {step.DisplayName}"); step.ExecutionContext.Debug($"Starting: {step.DisplayName}");
@@ -303,7 +299,7 @@ namespace GitHub.Runner.Worker
} }
else else
{ {
// Log the exception and cancel the step. // Log the exception and cancel the step
Trace.Error($"Caught cancellation exception from step: {ex}"); Trace.Error($"Caught cancellation exception from step: {ex}");
step.ExecutionContext.Error(ex); step.ExecutionContext.Error(ex);
step.ExecutionContext.Result = TaskResult.Canceled; step.ExecutionContext.Result = TaskResult.Canceled;
@@ -311,7 +307,7 @@ namespace GitHub.Runner.Worker
} }
catch (Exception ex) catch (Exception ex)
{ {
// Log the error and fail the step. // Log the error and fail the step
Trace.Error($"Caught exception from step: {ex}"); Trace.Error($"Caught exception from step: {ex}");
step.ExecutionContext.Error(ex); step.ExecutionContext.Error(ex);
step.ExecutionContext.Result = TaskResult.Failed; step.ExecutionContext.Result = TaskResult.Failed;
@@ -323,7 +319,7 @@ namespace GitHub.Runner.Worker
step.ExecutionContext.Result = TaskResultUtil.MergeTaskResults(step.ExecutionContext.Result, step.ExecutionContext.CommandResult.Value); step.ExecutionContext.Result = TaskResultUtil.MergeTaskResults(step.ExecutionContext.Result, step.ExecutionContext.CommandResult.Value);
} }
// Fixup the step result if ContinueOnError. // Fixup the step result if ContinueOnError
if (step.ExecutionContext.Result == TaskResult.Failed) if (step.ExecutionContext.Result == TaskResult.Failed)
{ {
var continueOnError = false; var continueOnError = false;
@@ -348,7 +344,7 @@ namespace GitHub.Runner.Worker
} }
Trace.Info($"Step result: {step.ExecutionContext.Result}"); Trace.Info($"Step result: {step.ExecutionContext.Result}");
// Complete the step context. // Complete the step context
step.ExecutionContext.Debug($"Finishing: {step.DisplayName}"); step.ExecutionContext.Debug($"Finishing: {step.DisplayName}");
} }

View File

@@ -32,10 +32,10 @@
"outputs": { "outputs": {
"mapping": { "mapping": {
"loose-key-type": "non-empty-string", "loose-key-type": "non-empty-string",
"loose-value-type": "outputs-attributes" "loose-value-type": "output-definition"
} }
}, },
"outputs-attributes": { "output-definition": {
"mapping": { "mapping": {
"properties": { "properties": {
"description": "string", "description": "string",