mirror of
https://github.com/actions/runner.git
synced 2025-12-11 04:46:58 +00:00
Defer evaluation of a step's DisplayName until its condition is evaluated. (#2313)
* Defer evaluation of a step's DisplayName until its condition is evaluated. * Formalize TryUpdateDisplayName and EvaluateDisplayName as members of interface `IStep` (#2374)
This commit is contained in:
committed by
GitHub
parent
3cd76671dd
commit
9a228e52e9
@@ -25,7 +25,6 @@ namespace GitHub.Runner.Worker
|
|||||||
public interface IActionRunner : IStep, IRunnerService
|
public interface IActionRunner : IStep, IRunnerService
|
||||||
{
|
{
|
||||||
ActionRunStage Stage { get; set; }
|
ActionRunStage Stage { get; set; }
|
||||||
bool TryEvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context);
|
|
||||||
Pipelines.ActionStep Action { get; set; }
|
Pipelines.ActionStep Action { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,25 +284,67 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryEvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context)
|
/// <summary>
|
||||||
|
/// Attempts to update the DisplayName.
|
||||||
|
/// As the "Try..." name implies, this method should never throw an exception.
|
||||||
|
/// Returns true if the DisplayName is already present or it was successfully updated.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryUpdateDisplayName(out bool updated)
|
||||||
|
{
|
||||||
|
updated = false;
|
||||||
|
|
||||||
|
// REVIEW: This try/catch can be removed if some future implementation of EvaluateDisplayName and UpdateTimelineRecordDisplayName
|
||||||
|
// can make reasonable guarantees that they won't throw an exception.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// This attempt is only worthwhile at the "Main" stage.
|
||||||
|
// When the job starts, there's an initial attempt to evaluate the DisplayName. (see JobExtension::InitializeJob)
|
||||||
|
// During the "Pre" stage, we expect that no contexts will have changed since the initial evaluation.
|
||||||
|
// "Main" stage is handled here.
|
||||||
|
// During the "Post" stage, it no longer matters.
|
||||||
|
if (this.Stage == ActionRunStage.Main && EvaluateDisplayName(this.ExecutionContext.ExpressionValues, this.ExecutionContext, out updated))
|
||||||
|
{
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
this.ExecutionContext.UpdateTimelineRecordDisplayName(this.DisplayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Warning("Caught exception while attempting to evaulate/update the step's DisplayName. Exception Details: {0}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For consistency with other implementations of TryUpdateDisplayName we use !string.IsNullOrEmpty below,
|
||||||
|
// but note that (at the time of this writing) ActionRunner::DisplayName::get always returns a non-empty string due to its fallback logic.
|
||||||
|
// In other words, the net effect is that this particular implementation of TryUpdateDisplayName will always return true.
|
||||||
|
return !string.IsNullOrEmpty(this.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to evaluate the DisplayName of this IActionRunner.
|
||||||
|
/// Returns true if the DisplayName is already present or it was successfully evaluated.
|
||||||
|
/// </summary>
|
||||||
|
public bool EvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context, out bool updated)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(context, nameof(context));
|
ArgUtil.NotNull(context, nameof(context));
|
||||||
ArgUtil.NotNull(Action, nameof(Action));
|
ArgUtil.NotNull(Action, nameof(Action));
|
||||||
|
|
||||||
// If we have already expanded the display name, there is no need to expand it again
|
updated = false;
|
||||||
// TODO: Remove the ShouldEvaluateDisplayName check and field post m158 deploy, we should do it by default once the server is updated
|
// If we have already expanded the display name, don't bother attempting [re-]expansion.
|
||||||
if (_didFullyEvaluateDisplayName || !string.IsNullOrEmpty(Action.DisplayName))
|
if (_didFullyEvaluateDisplayName || !string.IsNullOrEmpty(Action.DisplayName))
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool didFullyEvaluate;
|
_displayName = GenerateDisplayName(Action, contextData, context, out bool didFullyEvaluate);
|
||||||
_displayName = GenerateDisplayName(Action, contextData, context, out didFullyEvaluate);
|
|
||||||
|
|
||||||
// If we evaluated fully mask any secrets
|
// If we evaluated, fully mask any secrets
|
||||||
if (didFullyEvaluate)
|
if (didFullyEvaluate)
|
||||||
{
|
{
|
||||||
_displayName = HostContext.SecretMasker.MaskSecrets(_displayName);
|
_displayName = HostContext.SecretMasker.MaskSecrets(_displayName);
|
||||||
|
updated = true;
|
||||||
}
|
}
|
||||||
context.Debug($"Set step '{Action.Name}' display name to: '{_displayName}'");
|
context.Debug($"Set step '{Action.Name}' display name to: '{_displayName}'");
|
||||||
_didFullyEvaluateDisplayName = didFullyEvaluate;
|
_didFullyEvaluateDisplayName = didFullyEvaluate;
|
||||||
|
|||||||
@@ -306,13 +306,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actionRunner.TryEvaluateDisplayName(contextData, context);
|
actionRunner.EvaluateDisplayName(contextData, context, out _);
|
||||||
jobSteps.Add(actionRunner);
|
jobSteps.Add(actionRunner);
|
||||||
|
|
||||||
if (prepareResult.PreStepTracker.TryGetValue(step.Id, out var preStep))
|
if (prepareResult.PreStepTracker.TryGetValue(step.Id, out var preStep))
|
||||||
{
|
{
|
||||||
Trace.Info($"Adding pre-{action.DisplayName}.");
|
Trace.Info($"Adding pre-{action.DisplayName}.");
|
||||||
preStep.TryEvaluateDisplayName(contextData, context);
|
preStep.EvaluateDisplayName(contextData, context, out _);
|
||||||
preStep.DisplayName = $"Pre {preStep.DisplayName}";
|
preStep.DisplayName = $"Pre {preStep.DisplayName}";
|
||||||
preJobSteps.Add(preStep);
|
preJobSteps.Add(preStep);
|
||||||
}
|
}
|
||||||
@@ -328,10 +328,10 @@ namespace GitHub.Runner.Worker
|
|||||||
if (message.ContextData.TryGetValue("inputs", out var pipelineContextData))
|
if (message.ContextData.TryGetValue("inputs", out var pipelineContextData))
|
||||||
{
|
{
|
||||||
var inputs = pipelineContextData.AssertDictionary("inputs");
|
var inputs = pipelineContextData.AssertDictionary("inputs");
|
||||||
if (inputs.Any())
|
if (inputs.Any())
|
||||||
{
|
{
|
||||||
context.Output($"##[group] Inputs");
|
context.Output($"##[group] Inputs");
|
||||||
foreach (var input in inputs)
|
foreach (var input in inputs)
|
||||||
{
|
{
|
||||||
context.Output($" {input.Key}: {input.Value}");
|
context.Output($" {input.Key}: {input.Value}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -32,5 +33,18 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
await _runAsync(ExecutionContext, _data);
|
await _runAsync(ExecutionContext, _data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryUpdateDisplayName(out bool updated)
|
||||||
|
{
|
||||||
|
updated = false;
|
||||||
|
return !string.IsNullOrEmpty(this.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context, out bool updated)
|
||||||
|
{
|
||||||
|
updated = false;
|
||||||
|
return !string.IsNullOrEmpty(this.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
@@ -14,8 +11,6 @@ using GitHub.Runner.Common;
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Expressions;
|
using GitHub.Runner.Worker.Expressions;
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -26,6 +21,8 @@ namespace GitHub.Runner.Worker
|
|||||||
string DisplayName { get; set; }
|
string DisplayName { get; set; }
|
||||||
IExecutionContext ExecutionContext { get; set; }
|
IExecutionContext ExecutionContext { get; set; }
|
||||||
TemplateToken Timeout { get; }
|
TemplateToken Timeout { get; }
|
||||||
|
bool TryUpdateDisplayName(out bool updated);
|
||||||
|
bool EvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context, out bool updated);
|
||||||
Task RunAsync();
|
Task RunAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +192,12 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// This is our last, best chance to expand the display name. (At this point, all the requirements for successful expansion should be met.)
|
||||||
|
// That being said, evaluating the display name should still be considered as a "best effort" exercise. (It's not critical or paramount.)
|
||||||
|
// For that reason, we call a safe "Try..." wrapper method to ensure that any potential problems we encounter in evaluating the display name
|
||||||
|
// don't interfere with our ultimate goal within this code block: evaluation of the condition.
|
||||||
|
step.TryUpdateDisplayName(out _);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
||||||
@@ -256,14 +259,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
private async Task RunStepAsync(IStep step, CancellationToken jobCancellationToken)
|
private async Task RunStepAsync(IStep step, CancellationToken jobCancellationToken)
|
||||||
{
|
{
|
||||||
// Check to see if we can expand the display name
|
|
||||||
if (step is IActionRunner actionRunner &&
|
|
||||||
actionRunner.Stage == ActionRunStage.Main &&
|
|
||||||
actionRunner.TryEvaluateDisplayName(step.ExecutionContext.ExpressionValues, step.ExecutionContext))
|
|
||||||
{
|
|
||||||
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}");
|
||||||
|
|||||||
@@ -3,20 +3,14 @@ using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
@@ -149,11 +143,12 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_context.Add("matrix", matrixData);
|
_context.Add("matrix", matrixData);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
// Should not do anything if we don't have a displayNameToken to expand
|
// Should report success with no updated required if there's already a valid display name.
|
||||||
var didUpdateDisplayName = _actionRunner.TryEvaluateDisplayName(_context, _actionRunner.ExecutionContext);
|
var validDisplayName = _actionRunner.EvaluateDisplayName(_context, _actionRunner.ExecutionContext, out bool updated);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(didUpdateDisplayName);
|
Assert.True(validDisplayName);
|
||||||
|
Assert.False(updated);
|
||||||
Assert.Equal(actionDisplayName, _actionRunner.DisplayName);
|
Assert.Equal(actionDisplayName, _actionRunner.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,13 +178,51 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
// Should expand the displaynameToken and set the display name to that
|
// Should expand the displaynameToken and set the display name to that
|
||||||
var didUpdateDisplayName = _actionRunner.TryEvaluateDisplayName(_context, _actionRunner.ExecutionContext);
|
var validDisplayName = _actionRunner.EvaluateDisplayName(_context, _actionRunner.ExecutionContext, out bool updated);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(didUpdateDisplayName);
|
Assert.True(validDisplayName);
|
||||||
|
Assert.True(updated);
|
||||||
Assert.Equal(expectedString, _actionRunner.DisplayName);
|
Assert.Equal(expectedString, _actionRunner.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void IgnoreDisplayNameTokenWhenDisplayNameIsExplicitlySet()
|
||||||
|
{
|
||||||
|
var explicitDisplayName = "Explcitly Set Name";
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
Setup();
|
||||||
|
var actionId = Guid.NewGuid();
|
||||||
|
var action = new Pipelines.ActionStep()
|
||||||
|
{
|
||||||
|
Name = "action",
|
||||||
|
Id = actionId,
|
||||||
|
DisplayName = explicitDisplayName,
|
||||||
|
DisplayNameToken = new BasicExpressionToken(null, null, null, "matrix.node"),
|
||||||
|
};
|
||||||
|
|
||||||
|
_actionRunner.Action = action;
|
||||||
|
|
||||||
|
var matrixData = new DictionaryContextData
|
||||||
|
{
|
||||||
|
["node"] = new StringContextData("8")
|
||||||
|
};
|
||||||
|
_context.Add("matrix", matrixData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// Should ignore the displayNameToken since there's already an explicit value for DisplayName
|
||||||
|
var validDisplayName = _actionRunner.EvaluateDisplayName(_context, _actionRunner.ExecutionContext, out bool updated);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(validDisplayName);
|
||||||
|
Assert.False(updated);
|
||||||
|
Assert.Equal(explicitDisplayName, _actionRunner.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -218,10 +251,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
// Should expand the displaynameToken and set the display name to that
|
// Should expand the displaynameToken and set the display name to that
|
||||||
var didUpdateDisplayName = _actionRunner.TryEvaluateDisplayName(_context, _actionRunner.ExecutionContext);
|
var validDisplayName = _actionRunner.EvaluateDisplayName(_context, _actionRunner.ExecutionContext, out bool updated);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(didUpdateDisplayName);
|
Assert.True(validDisplayName);
|
||||||
|
Assert.True(updated);
|
||||||
Assert.Equal("Run 8", _actionRunner.DisplayName);
|
Assert.Equal("Run 8", _actionRunner.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,10 +280,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
// Should expand the displaynameToken and set the display name to that
|
// Should expand the displaynameToken and set the display name to that
|
||||||
var didUpdateDisplayName = _actionRunner.TryEvaluateDisplayName(_context, _actionRunner.ExecutionContext);
|
var validDisplayName = _actionRunner.EvaluateDisplayName(_context, _actionRunner.ExecutionContext, out bool updated);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(didUpdateDisplayName);
|
Assert.True(validDisplayName);
|
||||||
|
Assert.True(updated);
|
||||||
Assert.Equal("Run TestImageName:latest", _actionRunner.DisplayName);
|
Assert.Equal("Run TestImageName:latest", _actionRunner.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,10 +307,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
// Should not do anything if we don't have context on the display name
|
// Should not do anything if we don't have context on the display name
|
||||||
var didUpdateDisplayName = _actionRunner.TryEvaluateDisplayName(_context, _actionRunner.ExecutionContext);
|
var validDisplayName = _actionRunner.EvaluateDisplayName(_context, _actionRunner.ExecutionContext, out bool updated);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(didUpdateDisplayName);
|
Assert.False(validDisplayName);
|
||||||
|
Assert.False(updated);
|
||||||
// Should use the pretty display name until we can eval
|
// Should use the pretty display name until we can eval
|
||||||
Assert.Equal("${{ matrix.node }}", _actionRunner.DisplayName);
|
Assert.Equal("${{ matrix.node }}", _actionRunner.DisplayName);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user