mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
minor cleanup in composite (#1045)
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user