mirror of
https://github.com/actions/runner.git
synced 2026-07-06 20:55:42 +08:00
Compare commits
2 Commits
philip-gai
...
v2.335.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d310567ae | ||
|
|
1ccca7c073 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
# Build runner layout
|
||||
- name: Build & Layout Release
|
||||
@@ -95,7 +95,7 @@ jobs:
|
||||
docker_platform: linux/arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Get latest runner version
|
||||
id: latest_runner
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
2
.github/workflows/dependency-check.yml
vendored
2
.github/workflows/dependency-check.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
npm-vulnerabilities: ${{ steps.check-versions.outputs.npm-vulnerabilities }}
|
||||
open-dependency-prs: ${{ steps.check-prs.outputs.open-dependency-prs }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
|
||||
4
.github/workflows/docker-buildx-upgrade.yml
vendored
4
.github/workflows/docker-buildx-upgrade.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
BUILDX_CURRENT_VERSION: ${{ steps.check_buildx_version.outputs.CURRENT_VERSION }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Check Docker version
|
||||
id: check_docker_version
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Update Docker version
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/docker-publish.yml
vendored
2
.github/workflows/docker-publish.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.inputs.releaseBranch }}
|
||||
|
||||
|
||||
4
.github/workflows/dotnet-upgrade.yml
vendored
4
.github/workflows/dotnet-upgrade.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
DOTNET_CURRENT_MAJOR_MINOR_VERSION: ${{ steps.fetch_current_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_VERSION }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
- name: Get current major minor version
|
||||
id: fetch_current_version
|
||||
shell: bash
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
if: ${{ needs.dotnet-update.outputs.SHOULD_UPDATE == 1 && needs.dotnet-update.outputs.BRANCH_EXISTS == 0 }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: feature/dotnetsdk-upgrade/${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}
|
||||
- name: Create Pull Request
|
||||
|
||||
2
.github/workflows/node-upgrade.yml
vendored
2
.github/workflows/node-upgrade.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
update-node:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get latest Node versions
|
||||
id: node-versions
|
||||
run: |
|
||||
|
||||
2
.github/workflows/npm-audit-typescript.yml
vendored
2
.github/workflows/npm-audit-typescript.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
npm-audit-with-ts-fix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
|
||||
2
.github/workflows/npm-audit.yml
vendored
2
.github/workflows/npm-audit.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
npm-audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
|
||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
# Make sure ./releaseVersion match ./src/runnerversion
|
||||
# Query GitHub release ensure version is not used
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
# Build runner layout
|
||||
- name: Build & Layout Release
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
# Download runner package tar.gz/zip produced by 'build' job
|
||||
- name: Download Artifact (win-x64)
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Compute image version
|
||||
id: image
|
||||
|
||||
@@ -5,8 +5,8 @@ ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG RUNNER_VERSION
|
||||
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.7.0
|
||||
ARG DOCKER_VERSION=29.6.0
|
||||
ARG BUILDX_VERSION=0.35.0
|
||||
ARG DOCKER_VERSION=29.5.3
|
||||
ARG BUILDX_VERSION=0.34.1
|
||||
|
||||
RUN apt update -y && apt install curl unzip -y
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
<Update to ./src/runnerversion when creating release>
|
||||
2.335.0
|
||||
|
||||
@@ -7,7 +7,7 @@ NODE_ALPINE_URL=https://github.com/actions/alpine_nodejs/releases/download
|
||||
# When you update Node versions you must also create a new release of alpine_nodejs at that updated version.
|
||||
# Follow the instructions here: https://github.com/actions/alpine_nodejs?tab=readme-ov-file#getting-started
|
||||
NODE20_VERSION="20.20.2"
|
||||
NODE24_VERSION="24.18.0"
|
||||
NODE24_VERSION="24.16.0"
|
||||
|
||||
get_abs_path() {
|
||||
# exploits the fact that pwd will print abs path when no args
|
||||
|
||||
@@ -228,30 +228,7 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
throw new Exception($"Missing download info for {lookupKey}");
|
||||
}
|
||||
|
||||
Exception downloadFailure = null;
|
||||
try
|
||||
{
|
||||
await DownloadRepositoryActionAsync(executionContext, downloadInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// record the exception for telemetry, and rethrow the original exception to fail the step.
|
||||
downloadFailure = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||
{
|
||||
Type = JobTelemetryType.General,
|
||||
Message = $"resolve_download_actions_telemetry:{StringUtil.ConvertToJson(new ActionTelemetryPayload
|
||||
{
|
||||
Operation = "download_action",
|
||||
Result = downloadFailure == null ? "succeeded" : downloadFailure.GetType().Name
|
||||
}, Newtonsoft.Json.Formatting.None)}"
|
||||
});
|
||||
}
|
||||
await DownloadRepositoryActionAsync(executionContext, downloadInfo);
|
||||
}
|
||||
|
||||
// Parse action.yml and collect composite sub-actions for batched
|
||||
@@ -421,30 +398,7 @@ namespace GitHub.Runner.Worker
|
||||
if (repositoryActions.Count > 0)
|
||||
{
|
||||
// Get the download info
|
||||
IDictionary<string, WebApi.ActionDownloadInfo> downloadInfos = null;
|
||||
Exception resolveFailure = null;
|
||||
try
|
||||
{
|
||||
downloadInfos = await GetDownloadInfoAsync(executionContext, repositoryActions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// record the exception for telemetry, and rethrow the original exception to fail the step.
|
||||
resolveFailure = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||
{
|
||||
Type = JobTelemetryType.General,
|
||||
Message = $"resolve_download_actions_telemetry:{StringUtil.ConvertToJson(new ActionTelemetryPayload
|
||||
{
|
||||
Operation = "resolve_actions",
|
||||
Result = resolveFailure == null ? "succeeded" : resolveFailure.GetType().Name
|
||||
}, Newtonsoft.Json.Formatting.None)}"
|
||||
});
|
||||
}
|
||||
var downloadInfos = await GetDownloadInfoAsync(executionContext, repositoryActions);
|
||||
|
||||
// Download each action
|
||||
foreach (var action in repositoryActions)
|
||||
@@ -460,29 +414,7 @@ namespace GitHub.Runner.Worker
|
||||
throw new Exception($"Missing download info for {lookupKey}");
|
||||
}
|
||||
|
||||
Exception downloadFailure = null;
|
||||
try
|
||||
{
|
||||
await DownloadRepositoryActionAsync(executionContext, downloadInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// record the exception for telemetry, and rethrow the original exception to fail the step.
|
||||
downloadFailure = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||
{
|
||||
Type = JobTelemetryType.General,
|
||||
Message = $"resolve_download_actions_telemetry:{StringUtil.ConvertToJson(new ActionTelemetryPayload
|
||||
{
|
||||
Operation = "download_action",
|
||||
Result = downloadFailure == null ? "succeeded" : downloadFailure.GetType().Name
|
||||
}, Newtonsoft.Json.Formatting.None)}"
|
||||
});
|
||||
}
|
||||
await DownloadRepositoryActionAsync(executionContext, downloadInfo);
|
||||
}
|
||||
|
||||
// More preparation based on content in the repository (action.yml)
|
||||
@@ -1048,33 +980,10 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
if (actionsToResolve.Count > 0)
|
||||
{
|
||||
IDictionary<string, WebApi.ActionDownloadInfo> downloadInfos = null;
|
||||
Exception resolveFailure = null;
|
||||
try
|
||||
var downloadInfos = await GetDownloadInfoAsync(executionContext, actionsToResolve);
|
||||
foreach (var kvp in downloadInfos)
|
||||
{
|
||||
downloadInfos = await GetDownloadInfoAsync(executionContext, actionsToResolve);
|
||||
foreach (var kvp in downloadInfos)
|
||||
{
|
||||
resolvedDownloadInfos[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// record the exception for telemetry, and rethrow the original exception to fail the step.
|
||||
resolveFailure = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||
{
|
||||
Type = JobTelemetryType.General,
|
||||
Message = $"resolve_download_actions_telemetry:{StringUtil.ConvertToJson(new ActionTelemetryPayload
|
||||
{
|
||||
Operation = "resolve_actions",
|
||||
Result = resolveFailure == null ? "succeeded" : resolveFailure.GetType().Name
|
||||
}, Newtonsoft.Json.Formatting.None)}"
|
||||
});
|
||||
resolvedDownloadInfos[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1199,6 +1108,12 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
}
|
||||
|
||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||
{
|
||||
Type = JobTelemetryType.General,
|
||||
Message = $"Action archive cache usage: {downloadInfo.ResolvedNameWithOwner}@{downloadInfo.ResolvedSha} use cache {useActionArchiveCache} has cache {hasActionArchiveCache}"
|
||||
});
|
||||
|
||||
if (!useActionArchiveCache)
|
||||
{
|
||||
await DownloadRepositoryArchive(executionContext, link, downloadInfo.Authentication?.Token, archiveFile);
|
||||
@@ -1207,13 +1122,6 @@ namespace GitHub.Runner.Worker
|
||||
var stagingDirectory = Path.Combine(tempDirectory, "_staging");
|
||||
Directory.CreateDirectory(stagingDirectory);
|
||||
|
||||
var fileInfo = new FileInfo(archiveFile);
|
||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||
{
|
||||
Type = JobTelemetryType.General,
|
||||
Message = $"Action archive cache usage: {downloadInfo.ResolvedNameWithOwner}@{downloadInfo.ResolvedSha} use cache {useActionArchiveCache} has cache {hasActionArchiveCache} size {fileInfo.Length} bytes"
|
||||
});
|
||||
|
||||
#if OS_WINDOWS
|
||||
try
|
||||
{
|
||||
@@ -1251,6 +1159,7 @@ namespace GitHub.Runner.Worker
|
||||
int exitCode = await processInvoker.ExecuteAsync(stagingDirectory, tar, $"-xzf \"{archiveFile}\"", null, executionContext.CancellationToken);
|
||||
if (exitCode != 0)
|
||||
{
|
||||
var fileInfo = new FileInfo(archiveFile);
|
||||
var sha256hash = await IOUtil.GetFileContentSha256HashAsync(archiveFile);
|
||||
throw new InvalidActionArchiveException($"Can't use 'tar -xzf' extract archive file: {archiveFile} (SHA256 '{sha256hash}', size '{fileInfo.Length}' bytes, tar outputs '{string.Join(' ', tarOutputs)}'). Action being checked out: {downloadInfo.NameWithOwner}@{downloadInfo.Ref}. return code: {exitCode}.");
|
||||
}
|
||||
@@ -1300,12 +1209,6 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
private string GetWatermarkFilePath(string directory) => directory + ".completed";
|
||||
|
||||
private sealed class ActionTelemetryPayload
|
||||
{
|
||||
public string Operation { get; set; }
|
||||
public string Result { get; set; }
|
||||
}
|
||||
|
||||
private ActionSetupInfo PrepareRepositoryActionAsync(IExecutionContext executionContext, Pipelines.ActionStep repositoryAction)
|
||||
{
|
||||
var repositoryReference = repositoryAction.Reference as Pipelines.RepositoryPathReference;
|
||||
|
||||
@@ -32,11 +32,6 @@ namespace GitHub.Runner.Worker
|
||||
// IDs of background steps that have already been completed (waited on or canceled).
|
||||
// Used to avoid waiting on or flushing the same step more than once.
|
||||
private readonly HashSet<string> _completedStepIds = new();
|
||||
|
||||
// IDs of background steps that were explicitly canceled via a `cancel` control step.
|
||||
// These steps are expected to be canceled, so their (Canceled) result must not be
|
||||
// merged into the overall job result.
|
||||
private readonly HashSet<string> _explicitlyCanceledStepIds = new();
|
||||
private SemaphoreSlim _backgroundSlotSemaphore = new SemaphoreSlim(DefaultMaxBackgroundSteps);
|
||||
|
||||
/// <summary>
|
||||
@@ -46,7 +41,6 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
_backgroundSteps.Clear();
|
||||
_completedStepIds.Clear();
|
||||
_explicitlyCanceledStepIds.Clear();
|
||||
var max = maxConcurrent > 0 ? maxConcurrent : DefaultMaxBackgroundSteps;
|
||||
_backgroundSlotSemaphore = new SemaphoreSlim(max);
|
||||
}
|
||||
@@ -91,9 +85,6 @@ namespace GitHub.Runner.Worker
|
||||
// Safety net
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// Drain any background steps that weren't already waited on by an explicit wait/cancel
|
||||
// control step, then merge the final results of all background steps into a single result
|
||||
// for the caller to fold into the job result.
|
||||
public async Task<TaskResult> WaitForUnwaitedStepsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var unwaitedIds = _backgroundSteps.Keys.Where(id => !_completedStepIds.Contains(id)).ToList();
|
||||
@@ -104,26 +95,14 @@ namespace GitHub.Runner.Worker
|
||||
CompleteWaitedSteps(unwaitedIds);
|
||||
}
|
||||
|
||||
// Report the merged result of all background steps; the caller merges this into the job result.
|
||||
var result = TaskResult.Succeeded;
|
||||
foreach (var (stepId, (step, _, _)) in _backgroundSteps)
|
||||
foreach (var (_, (step, _, _)) in _backgroundSteps)
|
||||
{
|
||||
// A step that succeeded does not set a Result by default, so a missing
|
||||
// value means the step succeeded and there is nothing to merge.
|
||||
if (!step.ExecutionContext.Result.HasValue)
|
||||
if (step.ExecutionContext.Result.HasValue)
|
||||
{
|
||||
continue;
|
||||
result = TaskResultUtil.MergeTaskResults(result, step.ExecutionContext.Result.Value);
|
||||
}
|
||||
|
||||
// A step explicitly canceled via a `cancel` control step is expected to be canceled,
|
||||
// so a Canceled result must not influence the overall job result. However, if the step
|
||||
// failed (e.g. before the cancellation took effect), that failure should still count.
|
||||
if (_explicitlyCanceledStepIds.Contains(stepId) &&
|
||||
step.ExecutionContext.Result.Value == TaskResult.Canceled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = TaskResultUtil.MergeTaskResults(result, step.ExecutionContext.Result.Value);
|
||||
}
|
||||
|
||||
if (result != TaskResult.Succeeded)
|
||||
@@ -277,13 +256,6 @@ namespace GitHub.Runner.Worker
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark these steps as expected-to-be-canceled so their result does not
|
||||
// affect the overall job result.
|
||||
foreach (var id in cancelStepIds)
|
||||
{
|
||||
_explicitlyCanceledStepIds.Add(id);
|
||||
}
|
||||
|
||||
var idsToCancel = cancelStepIds
|
||||
.Where(id => _backgroundSteps.ContainsKey(id) && !_backgroundSteps[id].Task.IsCompleted)
|
||||
.ToArray();
|
||||
|
||||
@@ -239,11 +239,6 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
Environment["ACTIONS_RESULTS_URL"] = resultsUrl;
|
||||
}
|
||||
|
||||
if (ExecutionContext.Global.Variables.TryGetValue("actions_cache_mode", out var cacheMode) && !string.IsNullOrEmpty(cacheMode))
|
||||
{
|
||||
Environment["ACTIONS_CACHE_MODE"] = cacheMode;
|
||||
}
|
||||
|
||||
if (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.SetOrchestrationIdEnvForActions) ?? false)
|
||||
{
|
||||
if (ExecutionContext.Global.Variables.TryGetValue(Constants.Variables.System.OrchestrationId, out var orchestrationId) && !string.IsNullOrEmpty(orchestrationId))
|
||||
|
||||
@@ -78,11 +78,6 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
Environment["ACTIONS_CACHE_SERVICE_V2"] = bool.TrueString;
|
||||
}
|
||||
|
||||
if (ExecutionContext.Global.Variables.TryGetValue("actions_cache_mode", out var cacheMode) && !string.IsNullOrEmpty(cacheMode))
|
||||
{
|
||||
Environment["ACTIONS_CACHE_MODE"] = cacheMode;
|
||||
}
|
||||
|
||||
if (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.SetOrchestrationIdEnvForActions) ?? false)
|
||||
{
|
||||
if (ExecutionContext.Global.Variables.TryGetValue(Constants.Variables.System.OrchestrationId, out var orchestrationId) && !string.IsNullOrEmpty(orchestrationId))
|
||||
|
||||
@@ -171,12 +171,6 @@ namespace GitHub.Runner.Worker
|
||||
context.Output($"Secret source: {secretSource}");
|
||||
}
|
||||
|
||||
var cacheMode = jobContext.Global.Variables.Get("actions_cache_mode");
|
||||
if (!string.IsNullOrEmpty(cacheMode))
|
||||
{
|
||||
context.Output($"Actions cache-mode: {cacheMode}");
|
||||
}
|
||||
|
||||
var repoFullName = context.GetGitHubContext("repository");
|
||||
ArgUtil.NotNull(repoFullName, nameof(repoFullName));
|
||||
context.Debug($"Primary repository: {repoFullName}");
|
||||
|
||||
@@ -90,11 +90,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
|
||||
var actionYamlFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), ActionName, "main", "action.yml");
|
||||
Assert.True(File.Exists(actionYamlFile));
|
||||
|
||||
var telemetryMessages = GetTelemetryMessages();
|
||||
Assert.True(ContainsTelemetry(telemetryMessages, "resolve_actions"));
|
||||
Assert.True(ContainsTelemetry(telemetryMessages, "succeeded"));
|
||||
Assert.True(ContainsTelemetry(telemetryMessages, "download_action"));
|
||||
_hc.GetTrace().Info(File.ReadAllText(actionYamlFile));
|
||||
}
|
||||
finally
|
||||
@@ -153,11 +148,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
|
||||
// Act + Assert
|
||||
await Assert.ThrowsAsync<InvalidActionArchiveException>(async () => await _actionManager.PrepareActionsAsync(_ec.Object, actions));
|
||||
|
||||
var telemetryMessages = GetTelemetryMessages();
|
||||
Assert.True(ContainsTelemetry(telemetryMessages, "resolve_actions"));
|
||||
Assert.True(ContainsTelemetry(telemetryMessages, "download_action"));
|
||||
Assert.True(ContainsTelemetry(telemetryMessages, "InvalidActionArchiveException"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -225,51 +215,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task PrepareActions_ResolveActionDownloadInfo_RecordsTelemetry_OnFailure()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
Setup();
|
||||
_ec.Object.Global.Variables.Set(Constants.Variables.System.JobRequestType, "RunnerJobRequest");
|
||||
|
||||
_launchServer
|
||||
.Setup(x => x.ResolveActionsDownloadInfoAsync(It.IsAny<Guid>(), It.IsAny<Guid>(), It.IsAny<ActionReferenceList>(), It.IsAny<CancellationToken>(), It.IsAny<bool>()))
|
||||
.ThrowsAsync(new Exception("resolve failed"));
|
||||
|
||||
var actions = new List<Pipelines.JobStep>
|
||||
{
|
||||
new Pipelines.ActionStep()
|
||||
{
|
||||
Name = "action",
|
||||
Id = Guid.NewGuid(),
|
||||
Reference = new Pipelines.RepositoryPathReference()
|
||||
{
|
||||
Name = "actions/checkout",
|
||||
Ref = "v4",
|
||||
RepositoryType = "GitHub"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Act + Assert
|
||||
await Assert.ThrowsAsync<FailedToResolveActionDownloadInfoException>(async () => await _actionManager.PrepareActionsAsync(_ec.Object, actions));
|
||||
|
||||
var telemetryMessages = GetTelemetryMessages();
|
||||
Assert.Equal(1, telemetryMessages.Count(message =>
|
||||
message.Contains("resolve_actions", StringComparison.OrdinalIgnoreCase)
|
||||
&& !message.Contains("\"result\":\"succeeded\"", StringComparison.OrdinalIgnoreCase)));
|
||||
Assert.False(ContainsTelemetry(telemetryMessages, "resolve_actions\",\"result\":\"succeeded"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Teardown();
|
||||
}
|
||||
}
|
||||
|
||||
#if OS_LINUX
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
@@ -3388,16 +3333,6 @@ runs:
|
||||
}
|
||||
}
|
||||
|
||||
private IList<string> GetTelemetryMessages()
|
||||
{
|
||||
return _ec.Object.Global.JobTelemetry.Select(x => x.Message).ToList();
|
||||
}
|
||||
|
||||
private static bool ContainsTelemetry(IList<string> telemetryMessages, string expectedFragment)
|
||||
{
|
||||
return telemetryMessages.Any(message => message.Contains(expectedFragment, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
|
||||
@@ -372,88 +372,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task CanceledBackgroundStepDoesNotAffectJobResult()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange: a background step that runs until explicitly canceled. When canceled it
|
||||
// reports TaskResult.Canceled, but since the cancellation is expected (driven by a
|
||||
// cancel control step), it must not impact the overall job result.
|
||||
using var stepCts = new CancellationTokenSource();
|
||||
|
||||
var bgStep = CreateStep(hc, TaskResult.Succeeded, "success()", name: "server", contextName: "server", isBackground: true);
|
||||
var bgStepContext = Mock.Get(bgStep.Object.ExecutionContext);
|
||||
bgStepContext.Setup(x => x.CancellationToken).Returns(stepCts.Token);
|
||||
bgStepContext.Setup(x => x.CancelToken()).Callback(() => stepCts.Cancel());
|
||||
bgStep.Setup(x => x.RunAsync()).Returns(async () =>
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(2), stepCts.Token);
|
||||
});
|
||||
bgStep.Setup(x => x.Action).Returns(new GitHub.DistributedTask.Pipelines.ActionStep()
|
||||
{
|
||||
Name = "server",
|
||||
Id = Guid.NewGuid(),
|
||||
ContextName = "server",
|
||||
Background = true,
|
||||
});
|
||||
|
||||
var cancelStep = CreateCancelStep(hc, "server");
|
||||
|
||||
_ec.Object.Result = null;
|
||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new IStep[]
|
||||
{
|
||||
bgStep.Object, cancelStep
|
||||
}));
|
||||
|
||||
// Act
|
||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||
|
||||
// Assert: the canceled background step reported Canceled, but the job result is unaffected.
|
||||
Assert.Equal(TaskResult.Canceled, bgStep.Object.ExecutionContext.Result);
|
||||
Assert.Equal(TaskResult.Succeeded, _ec.Object.Result ?? TaskResult.Succeeded);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task FailedBackgroundStepTargetedByCancelStillAffectsJobResult()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange: a background step that fails (e.g. before the cancel takes effect). Even
|
||||
// though a cancel control step targets it, its Failed result must still propagate to
|
||||
// the overall job result.
|
||||
var bgStep = CreateStep(hc, TaskResult.Failed, "success()", name: "server", contextName: "server", isBackground: true);
|
||||
bgStep.Setup(x => x.RunAsync()).Returns(Task.CompletedTask);
|
||||
bgStep.Setup(x => x.Action).Returns(new GitHub.DistributedTask.Pipelines.ActionStep()
|
||||
{
|
||||
Name = "server",
|
||||
Id = Guid.NewGuid(),
|
||||
ContextName = "server",
|
||||
Background = true,
|
||||
});
|
||||
|
||||
var cancelStep = CreateCancelStep(hc, "server");
|
||||
|
||||
_ec.Object.Result = null;
|
||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new IStep[]
|
||||
{
|
||||
bgStep.Object, cancelStep
|
||||
}));
|
||||
|
||||
// Act
|
||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||
|
||||
// Assert: the background step failed, so the job result reflects that failure.
|
||||
Assert.Equal(TaskResult.Failed, bgStep.Object.ExecutionContext.Result);
|
||||
Assert.Equal(TaskResult.Failed, _ec.Object.Result);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.Actions.RunService.WebApi;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
@@ -94,260 +85,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Assert.Equal("ubuntu:20.04", _stepTelemetry.Action);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
[InlineData("read")]
|
||||
[InlineData("none")]
|
||||
[InlineData("write")]
|
||||
[InlineData("write-only")]
|
||||
public async Task RunAsync_ExportsCacheModeEnv_WhenVariableSet(string mode)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var environment = await RunNodeScriptActionHandlerAsync(hc, new Dictionary<string, VariableValue>
|
||||
{
|
||||
{ "actions_cache_mode", mode }
|
||||
});
|
||||
|
||||
Assert.True(environment.TryGetValue("ACTIONS_CACHE_MODE", out var value));
|
||||
Assert.Equal(mode, value);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task RunAsync_DoesNotExportCacheModeEnv_WhenVariableAbsent()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var environment = await RunNodeScriptActionHandlerAsync(hc, new Dictionary<string, VariableValue>());
|
||||
|
||||
Assert.False(environment.ContainsKey("ACTIONS_CACHE_MODE"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task RunAsync_DoesNotExportCacheModeEnv_WhenVariableEmpty()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var environment = await RunNodeScriptActionHandlerAsync(hc, new Dictionary<string, VariableValue>
|
||||
{
|
||||
{ "actions_cache_mode", "" }
|
||||
});
|
||||
|
||||
Assert.False(environment.ContainsKey("ACTIONS_CACHE_MODE"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task RunAsync_CacheModeCoexistsWithCacheServiceV2()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var environment = await RunNodeScriptActionHandlerAsync(hc, new Dictionary<string, VariableValue>
|
||||
{
|
||||
{ "actions_uses_cache_service_v2", "true" },
|
||||
{ "actions_cache_mode", "read" }
|
||||
});
|
||||
|
||||
Assert.Equal(bool.TrueString, environment["ACTIONS_CACHE_SERVICE_V2"]);
|
||||
Assert.Equal("read", environment["ACTIONS_CACHE_MODE"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task RunAsync_DoesNotAffectRuntimeEnv_WhenCacheModeAbsent()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var environment = await RunNodeScriptActionHandlerAsync(hc, new Dictionary<string, VariableValue>());
|
||||
|
||||
// Baseline runtime env is still exported and cache-mode adds nothing.
|
||||
Assert.Equal("https://pipelines.actions.githubusercontent.com/", environment["ACTIONS_RUNTIME_URL"]);
|
||||
Assert.Equal("token", environment["ACTIONS_RUNTIME_TOKEN"]);
|
||||
Assert.False(environment.ContainsKey("ACTIONS_CACHE_MODE"));
|
||||
Assert.False(environment.ContainsKey("ACTIONS_CACHE_SERVICE_V2"));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
[InlineData("read")]
|
||||
[InlineData("none")]
|
||||
public async Task ContainerRunAsync_ExportsCacheModeEnv_WhenVariableSet(string mode)
|
||||
{
|
||||
// Container actions only run on Linux; RunAsync throws on other platforms.
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var container = await RunContainerActionHandlerAsync(hc, new Dictionary<string, VariableValue>
|
||||
{
|
||||
{ "actions_cache_mode", mode }
|
||||
});
|
||||
|
||||
Assert.True(container.ContainerEnvironmentVariables.TryGetValue("ACTIONS_CACHE_MODE", out var value));
|
||||
Assert.Equal(mode, value);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task ContainerRunAsync_DoesNotExportCacheModeEnv_WhenVariableAbsent()
|
||||
{
|
||||
// Container actions only run on Linux; RunAsync throws on other platforms.
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var container = await RunContainerActionHandlerAsync(hc, new Dictionary<string, VariableValue>());
|
||||
|
||||
Assert.False(container.ContainerEnvironmentVariables.ContainsKey("ACTIONS_CACHE_MODE"));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ContainerInfo> RunContainerActionHandlerAsync(TestHostContext hc, IDictionary<string, VariableValue> variables)
|
||||
{
|
||||
// Route through the container-hooks path so the handler skips docker build/run.
|
||||
variables[Constants.Runner.Features.AllowRunnerContainerHooks] = "true";
|
||||
Environment.SetEnvironmentVariable(Constants.Hooks.ContainerHooksPath, Path.Combine(hc.GetDirectory(WellKnownDirectory.Root), "hooks.js"));
|
||||
|
||||
var tempDirectory = hc.GetDirectory(WellKnownDirectory.Temp);
|
||||
Directory.CreateDirectory(Path.Combine(tempDirectory, "_runner_file_commands"));
|
||||
Directory.CreateDirectory(Path.Combine(tempDirectory, "_github_workflow"));
|
||||
var workspace = Path.Combine(hc.GetDirectory(WellKnownDirectory.Work), "workspace");
|
||||
Directory.CreateDirectory(workspace);
|
||||
|
||||
var serverVariables = new Variables(hc, variables);
|
||||
var endpoints = new List<ServiceEndpoint>
|
||||
{
|
||||
new ServiceEndpoint()
|
||||
{
|
||||
Name = WellKnownServiceEndpointNames.SystemVssConnection,
|
||||
Url = new Uri("https://pipelines.actions.githubusercontent.com"),
|
||||
Authorization = new EndpointAuthorization()
|
||||
{
|
||||
Scheme = "Test",
|
||||
Parameters = { { "AccessToken", "token" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_ec.Setup(x => x.Global).Returns(new GlobalContext()
|
||||
{
|
||||
Variables = serverVariables,
|
||||
Endpoints = endpoints,
|
||||
PrependPath = new List<string>(),
|
||||
EnvironmentVariables = new Dictionary<string, string>()
|
||||
});
|
||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
||||
_ec.Setup(x => x.JobContext).Returns(new JobContext());
|
||||
_ec.Setup(x => x.GetGitHubContext("workspace")).Returns(workspace);
|
||||
|
||||
ContainerInfo captured = null;
|
||||
var hookManager = new Mock<IContainerHookManager>();
|
||||
hookManager.Setup(x => x.RunContainerStepAsync(It.IsAny<IExecutionContext>(), It.IsAny<ContainerInfo>(), It.IsAny<string>()))
|
||||
.Callback((IExecutionContext ec, ContainerInfo container, string dockerFile) => { captured = container; })
|
||||
.Returns(Task.CompletedTask);
|
||||
hc.SetSingleton(hookManager.Object);
|
||||
hc.SetSingleton(new Mock<IActionManifestManagerWrapper>().Object);
|
||||
|
||||
var handler = new ContainerActionHandler();
|
||||
handler.Initialize(hc);
|
||||
handler.ExecutionContext = _ec.Object;
|
||||
handler.Environment = new Dictionary<string, string>();
|
||||
handler.Inputs = new Dictionary<string, string>();
|
||||
handler.Action = new ContainerRegistryReference() { Image = "alpine:latest" };
|
||||
handler.Data = new ContainerActionExecutionData() { Image = "docker://alpine:latest" };
|
||||
|
||||
await handler.RunAsync(ActionRunStage.Main);
|
||||
|
||||
return captured;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> RunNodeScriptActionHandlerAsync(TestHostContext hc, IDictionary<string, VariableValue> variables)
|
||||
{
|
||||
var actionDirectory = Path.Combine(hc.GetDirectory(WellKnownDirectory.Work), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(actionDirectory);
|
||||
var scriptFile = "main.js";
|
||||
File.WriteAllText(Path.Combine(actionDirectory, scriptFile), "// noop");
|
||||
|
||||
var serverVariables = new Variables(hc, variables);
|
||||
var endpoints = new List<ServiceEndpoint>
|
||||
{
|
||||
new ServiceEndpoint()
|
||||
{
|
||||
Name = WellKnownServiceEndpointNames.SystemVssConnection,
|
||||
Url = new Uri("https://pipelines.actions.githubusercontent.com"),
|
||||
Authorization = new EndpointAuthorization()
|
||||
{
|
||||
Scheme = "Test",
|
||||
Parameters = { { "AccessToken", "token" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_ec.Setup(x => x.Global).Returns(new GlobalContext()
|
||||
{
|
||||
Variables = serverVariables,
|
||||
Endpoints = endpoints,
|
||||
PrependPath = new List<string>(),
|
||||
EnvironmentVariables = new Dictionary<string, string>()
|
||||
});
|
||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
||||
_ec.Setup(x => x.GetGitHubContext("workspace")).Returns(actionDirectory);
|
||||
_ec.Setup(x => x.GetMatchers()).Returns(new List<IssueMatcherConfig>());
|
||||
_ec.Setup(x => x.ForceCompleted).Returns(new TaskCompletionSource<int>().Task);
|
||||
_ec.Setup(x => x.CancellationToken).Returns(CancellationToken.None);
|
||||
|
||||
var stepHost = new Mock<IStepHost>();
|
||||
stepHost.Setup(x => x.DetermineNodeRuntimeVersion(It.IsAny<IExecutionContext>(), It.IsAny<string>())).ReturnsAsync("node20");
|
||||
stepHost.Setup(x => x.ResolvePathForStepHost(It.IsAny<IExecutionContext>(), It.IsAny<string>())).Returns((IExecutionContext ec, string path) => path);
|
||||
stepHost.Setup(x => x.ExecuteAsync(
|
||||
It.IsAny<IExecutionContext>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<IDictionary<string, string>>(),
|
||||
It.IsAny<bool>(),
|
||||
It.IsAny<System.Text.Encoding>(),
|
||||
It.IsAny<bool>(),
|
||||
It.IsAny<bool>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<CancellationToken>())).ReturnsAsync(0);
|
||||
|
||||
var handler = new NodeScriptActionHandler();
|
||||
handler.Initialize(hc);
|
||||
handler.ExecutionContext = _ec.Object;
|
||||
handler.StepHost = stepHost.Object;
|
||||
handler.Environment = new Dictionary<string, string>();
|
||||
handler.Inputs = new Dictionary<string, string>();
|
||||
handler.RuntimeVariables = serverVariables;
|
||||
handler.ActionDirectory = actionDirectory;
|
||||
handler.Action = new RepositoryPathReference() { Name = "actions/checkout", Ref = "v2" };
|
||||
handler.Data = new NodeJSActionExecutionData() { Script = scriptFile, NodeVersion = "node20" };
|
||||
|
||||
await handler.RunAsync(ActionRunStage.Main);
|
||||
|
||||
return handler.Environment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,54 +238,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
[InlineData("read")]
|
||||
[InlineData("none")]
|
||||
[InlineData("write")]
|
||||
[InlineData("write-only")]
|
||||
public async Task InitializeJob_LogsCacheMode_WhenVariableSet(string mode)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
_jobEc.Global.Variables.Set("actions_cache_mode", mode);
|
||||
|
||||
var jobExtension = new JobExtension();
|
||||
jobExtension.Initialize(hc);
|
||||
|
||||
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>(), It.IsAny<Guid>()))
|
||||
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>(), new Dictionary<Guid, IActionRunner>())));
|
||||
|
||||
await jobExtension.InitializeJob(_jobEc, _message);
|
||||
|
||||
_jobServerQueue.Verify(
|
||||
x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.Is<string>(m => m.Contains($"Actions cache-mode: {mode}")), It.IsAny<long?>()),
|
||||
Times.Once);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public async Task InitializeJob_DoesNotLogCacheMode_WhenVariableAbsent()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
var jobExtension = new JobExtension();
|
||||
jobExtension.Initialize(hc);
|
||||
|
||||
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>(), It.IsAny<Guid>()))
|
||||
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>(), new Dictionary<Guid, IActionRunner>())));
|
||||
|
||||
await jobExtension.InitializeJob(_jobEc, _message);
|
||||
|
||||
_jobServerQueue.Verify(
|
||||
x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.Is<string>(m => m.Contains("Actions cache-mode:")), It.IsAny<long?>()),
|
||||
Times.Never);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
|
||||
Reference in New Issue
Block a user