Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
c7a13f33d3 Bump System.Threading.Channels from 8.0.0 to 10.0.3
---
updated-dependencies:
- dependency-name: System.Threading.Channels
  dependency-version: 10.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 04:54:17 +00:00
4 changed files with 16 additions and 60 deletions

View File

@@ -17,7 +17,7 @@
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
<PackageReference Include="System.Threading.Channels" Version="10.0.3" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@@ -77,7 +77,8 @@ namespace GitHub.Runner.Worker
List<string> StepEnvironmentOverrides { get; }
IExecutionContext Root { get; }
ExecutionContext Root { get; }
ExecutionContext Parent { get; }
// Initialize
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
@@ -250,9 +251,7 @@ namespace GitHub.Runner.Worker
}
}
IExecutionContext IExecutionContext.Root => Root;
private ExecutionContext Root
public ExecutionContext Root
{
get
{
@@ -267,7 +266,13 @@ namespace GitHub.Runner.Worker
}
}
public ExecutionContext Parent
{
get
{
return _parentExecutionContext;
}
}
public JobContext JobContext
{

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading;
using GitHub.Actions.WorkflowParser;
using GitHub.DistributedTask.Expressions2;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
@@ -227,12 +226,8 @@ namespace GitHub.Runner.Worker
Func<TNew> newEvaluator,
Func<TLegacy, TNew, bool> resultComparer)
{
// Use the root (job-level) cancellation token to detect cancellation race conditions.
// The step-level token only fires on step timeout, not on job cancellation.
// Job cancellation mutates JobContext.Status which expression functions read,
// so we need the root token to properly detect cancellation between evaluator runs.
var rootCancellationToken = _context.Root?.CancellationToken ?? CancellationToken.None;
var cancellationRequestedBefore = rootCancellationToken.IsCancellationRequested;
// Capture cancellation state before evaluation
var cancellationRequestedBefore = _context.CancellationToken.IsCancellationRequested;
// Legacy evaluator
var legacyException = default(Exception);
@@ -266,7 +261,7 @@ namespace GitHub.Runner.Worker
}
// Capture cancellation state after evaluation
var cancellationRequestedAfter = rootCancellationToken.IsCancellationRequested;
var cancellationRequestedAfter = _context.CancellationToken.IsCancellationRequested;
// Compare results or exceptions
bool hasMismatch = false;

View File

@@ -19,7 +19,6 @@ namespace GitHub.Runner.Common.Tests.Worker
public sealed class PipelineTemplateEvaluatorWrapperL0
{
private CancellationTokenSource _ecTokenSource;
private CancellationTokenSource _rootTokenSource;
private Mock<IExecutionContext> _ec;
private TestHostContext _hc;
@@ -66,7 +65,7 @@ namespace GitHub.Runner.Common.Tests.Worker
var wrapper = new PipelineTemplateEvaluatorWrapper(_hc, _ec.Object, allowServiceContainerCommand: false);
// Call EvaluateAndCompare directly: the new evaluator cancels the root token
// Call EvaluateAndCompare directly: the new evaluator cancels the token
// and returns a different value, forcing hasMismatch = true.
// Because cancellation flipped during the evaluation window, the
// mismatch should be skipped.
@@ -75,7 +74,7 @@ namespace GitHub.Runner.Common.Tests.Worker
() => "legacy-value",
() =>
{
_rootTokenSource.Cancel();
_ecTokenSource.Cancel();
return "different-value";
},
(legacy, @new) => string.Equals(legacy, @new, StringComparison.Ordinal));
@@ -89,43 +88,6 @@ namespace GitHub.Runner.Common.Tests.Worker
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void EvaluateAndCompare_SkipsMismatchRecording_WhenRootCancellationOccursBetweenEvaluators()
{
// Simulates job-level cancellation firing between legacy and new evaluator runs.
// Root is mocked with a separate CancellationTokenSource to exercise the
// _context.Root?.CancellationToken path (the job-level token).
try
{
Setup();
_ec.Object.Global.Variables.Set(Constants.Runner.Features.CompareWorkflowParser, "true");
var wrapper = new PipelineTemplateEvaluatorWrapper(_hc, _ec.Object, allowServiceContainerCommand: false);
// Legacy evaluator cancels the root token (simulating job cancel) and returns a value.
// The new evaluator returns a different value. The mismatch should be skipped.
var result = wrapper.EvaluateAndCompare<string, string>(
"TestRootCancellationSkip",
() =>
{
var legacyValue = "legacy-value";
_rootTokenSource.Cancel();
return legacyValue;
},
() => "different-value",
(legacy, @new) => string.Equals(legacy, @new, StringComparison.Ordinal));
Assert.Equal("legacy-value", result);
Assert.False(_ec.Object.Global.HasTemplateEvaluatorMismatch);
}
finally
{
Teardown();
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
@@ -900,8 +862,6 @@ namespace GitHub.Runner.Common.Tests.Worker
{
_ecTokenSource?.Dispose();
_ecTokenSource = new CancellationTokenSource();
_rootTokenSource?.Dispose();
_rootTokenSource = new CancellationTokenSource();
_hc = new TestHostContext(this, name);
@@ -917,9 +877,6 @@ namespace GitHub.Runner.Common.Tests.Worker
WriteDebug = true,
});
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
var rootEc = new Mock<IExecutionContext>();
rootEc.Setup(x => x.CancellationToken).Returns(_rootTokenSource.Token);
_ec.Setup(x => x.Root).Returns(rootEc.Object);
_ec.Setup(x => x.ExpressionValues).Returns(expressionValues);
_ec.Setup(x => x.ExpressionFunctions).Returns(expressionFunctions);
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"{tag}{message}"); });
@@ -928,7 +885,6 @@ namespace GitHub.Runner.Common.Tests.Worker
private void Teardown()
{
_rootTokenSource?.Dispose();
_hc?.Dispose();
}
}