From ae09a9d7b52be2e5dfe5ee86226a3d03e79c228e Mon Sep 17 00:00:00 2001 From: eric sciple Date: Thu, 26 Feb 2026 08:36:55 -0600 Subject: [PATCH] Fix composite post-step marker display names (#4267) --- .../Handlers/CompositeActionHandler.cs | 9 ++- .../Handlers/CompositeActionHandlerL0.cs | 64 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/Runner.Worker/Handlers/CompositeActionHandler.cs b/src/Runner.Worker/Handlers/CompositeActionHandler.cs index c0bc6f688..6db8995d0 100644 --- a/src/Runner.Worker/Handlers/CompositeActionHandler.cs +++ b/src/Runner.Worker/Handlers/CompositeActionHandler.cs @@ -312,7 +312,14 @@ namespace GitHub.Runner.Worker.Handlers // Emit start marker after full context setup so display name expressions resolve correctly if (emitCompositeMarkers) { - step.TryUpdateDisplayName(out _); + try + { + step.EvaluateDisplayName(step.ExecutionContext.ExpressionValues, step.ExecutionContext, out _); + } + catch (Exception ex) + { + Trace.Warning("Caught exception while evaluating embedded step display name. {0}", ex); + } ExecutionContext.Output($"##[start-action display={EscapeProperty(SanitizeDisplayName(step.DisplayName))};id={EscapeProperty(markerId)}]"); stepStopwatch = Stopwatch.StartNew(); } diff --git a/src/Test/L0/Worker/Handlers/CompositeActionHandlerL0.cs b/src/Test/L0/Worker/Handlers/CompositeActionHandlerL0.cs index 09935c3ad..33b00fdb9 100644 --- a/src/Test/L0/Worker/Handlers/CompositeActionHandlerL0.cs +++ b/src/Test/L0/Worker/Handlers/CompositeActionHandlerL0.cs @@ -1,14 +1,18 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using GitHub.DistributedTask.Pipelines; +using GitHub.DistributedTask.Pipelines.ContextData; using GitHub.DistributedTask.WebApi; using GitHub.Runner.Common.Util; using GitHub.Runner.Sdk; using GitHub.Runner.Worker; using GitHub.Runner.Worker.Handlers; using Moq; +using Newtonsoft.Json.Linq; using Xunit; using DTWebApi = GitHub.DistributedTask.WebApi; +using Pipelines = GitHub.DistributedTask.Pipelines; namespace GitHub.Runner.Common.Tests.Worker.Handlers { @@ -250,6 +254,66 @@ namespace GitHub.Runner.Common.Tests.Worker.Handlers Assert.Equal("##[end-action id=failing-step;outcome=failure;conclusion=success;duration_ms=500]", marker); } + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Worker")] + public void PostStepMarker_UsesEvaluatedDisplayName() + { + // Arrange: create an ActionRunner with a RepositoryPathReference (simulating actions/cache@v4) + // and Stage = Post. Verify that EvaluateDisplayName produces the correct display name + // so the composite marker emits "Run actions/cache@v4" instead of the fallback "run". + var hc = new TestHostContext(this, nameof(PostStepMarker_UsesEvaluatedDisplayName)); + var actionManifestLegacy = new ActionManifestManagerLegacy(); + actionManifestLegacy.Initialize(hc); + hc.SetSingleton(actionManifestLegacy); + var actionManifestNew = new ActionManifestManager(); + actionManifestNew.Initialize(hc); + hc.SetSingleton(actionManifestNew); + var actionManifestManager = new ActionManifestManagerWrapper(); + actionManifestManager.Initialize(hc); + hc.SetSingleton(actionManifestManager); + + var ec = new Mock(); + var contextData = new DictionaryContextData(); + var githubContext = new GitHubContext(); + githubContext.Add("event", JToken.Parse("{\"foo\":\"bar\"}").ToPipelineContextData()); + contextData.Add("github", githubContext); +#if OS_WINDOWS + contextData["env"] = new DictionaryContextData(); +#else + contextData["env"] = new CaseSensitiveDictionaryContextData(); +#endif + ec.Setup(x => x.Global).Returns(new GlobalContext()); + ec.Setup(x => x.ExpressionValues).Returns(contextData); + ec.Setup(x => x.ExpressionFunctions).Returns(new List()); + ec.Setup(x => x.Write(It.IsAny(), It.IsAny())); + ec.Object.Global.Variables = new Variables(hc, new Dictionary()); + + var actionRunner = new ActionRunner(); + actionRunner.Initialize(hc); + actionRunner.ExecutionContext = ec.Object; + actionRunner.Stage = ActionRunStage.Post; + actionRunner.Action = new Pipelines.ActionStep() + { + Name = "cache", + Id = Guid.NewGuid(), + Reference = new Pipelines.RepositoryPathReference() + { + Name = "actions/cache", + Ref = "v4" + } + }; + + // Act: call EvaluateDisplayName directly, which is what CompositeActionHandler now does + // for embedded steps (including Post stage) instead of TryUpdateDisplayName. + var result = actionRunner.EvaluateDisplayName(contextData, ec.Object, out bool updated); + + // Assert: display name should be "Run actions/cache@v4", not the fallback "run" + Assert.True(result); + Assert.True(updated); + Assert.Equal("Run actions/cache@v4", actionRunner.DisplayName); + } + // Helper methods that call the real production code private static string EscapeProperty(string value) => CompositeActionHandler.EscapeProperty(value);