Compare commits

..

2 Commits

Author SHA1 Message Date
Nikola Jokic
d37dfa565e Merge branch 'main' into nikola-jokic/rm-dockerd 2024-02-08 20:07:36 +01:00
Nikola Jokic
7cb4e05e53 Remove dockerd but leave docker cli in the image. Bump docker version 2024-02-08 20:03:57 +01:00
36 changed files with 185 additions and 524 deletions

View File

@@ -4,13 +4,13 @@
"features": { "features": {
"ghcr.io/devcontainers/features/docker-in-docker:1": {}, "ghcr.io/devcontainers/features/docker-in-docker:1": {},
"ghcr.io/devcontainers/features/dotnet": { "ghcr.io/devcontainers/features/dotnet": {
"version": "6.0.419" "version": "6.0.418"
}, },
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"version": "16" "version": "16"
}, },
"ghcr.io/devcontainers/features/sshd:1": { "ghcr.io/devcontainers/features/sshd:1": {
"version": "latest" "version": "latest"
} }
}, },
"customizations": { "customizations": {

View File

@@ -5,7 +5,7 @@ ARG TARGETOS
ARG TARGETARCH ARG TARGETARCH
ARG RUNNER_VERSION ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.5.1 ARG RUNNER_CONTAINER_HOOKS_VERSION=0.5.1
ARG DOCKER_VERSION=25.0.2 ARG DOCKER_VERSION=25.0.3
ARG BUILDX_VERSION=0.12.1 ARG BUILDX_VERSION=0.12.1
RUN apt update -y && apt install curl unzip -y RUN apt update -y && apt install curl unzip -y
@@ -25,7 +25,7 @@ RUN export RUNNER_ARCH=${TARGETARCH} \
&& if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \ && if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \
&& if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \ && if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \
&& curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \ && curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \
&& tar zxvf docker.tgz \ && tar zxvf docker.tgz --strip 1 -C . docker/docker \
&& rm -rf docker.tgz \ && rm -rf docker.tgz \
&& mkdir -p /usr/local/lib/docker/cli-plugins \ && mkdir -p /usr/local/lib/docker/cli-plugins \
&& curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \ && curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \
@@ -57,6 +57,6 @@ WORKDIR /home/runner
COPY --chown=runner:docker --from=build /actions-runner . COPY --chown=runner:docker --from=build /actions-runner .
COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx
RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker RUN install -o root -g root -m 755 ./docker /usr/bin/ && rm -rf docker
USER runner USER runner

View File

@@ -1,20 +1,30 @@
## What's Changed ## What's Changed
* Prepare v2.313.0 Release by @luketomlinson in https://github.com/actions/runner/pull/3137 * Bump docker and buildx to the latest version by @diogotorres97 in https://github.com/actions/runner/pull/3100
* Pass RunnerOS during job acquire. by @TingluoHuang in https://github.com/actions/runner/pull/3140 * Revert "Bump container hook version to 0.5.0 in runner image (#3003)" by @TingluoHuang in https://github.com/actions/runner/pull/3101
* Process `snapshot` tokens by @davidomid in https://github.com/actions/runner/pull/3135 * Make embedded timeline record has same order as its parent record. by @TingluoHuang in https://github.com/actions/runner/pull/3113
* Update dotnet sdk to latest version @6.0.419 by @github-actions in https://github.com/actions/runner/pull/3158 * Fix release workflow. by @TingluoHuang in https://github.com/actions/runner/pull/3102
* handle broker run service exception handling by @yaananth in https://github.com/actions/runner/pull/3163 * Add user-agent to all http clients using RawClientHttpRequestSettings. by @TingluoHuang in https://github.com/actions/runner/pull/3115
* Add a retry logic to docker login operation by @enescakir in https://github.com/actions/runner/pull/3089 * Fix JobDispatcher crash during force cancellation. by @TingluoHuang in https://github.com/actions/runner/pull/3118
* Broker fixes for token refreshes and AccessDeniedException by @luketomlinson in https://github.com/actions/runner/pull/3161 * Implement Broker Redirects for Session and Messages by @luketomlinson in https://github.com/actions/runner/pull/3103
* Remove USE_BROKER_FLOW by @luketomlinson in https://github.com/actions/runner/pull/3162 * Only keep 1 older version runner around after self-upgrade. by @TingluoHuang in https://github.com/actions/runner/pull/3122
* Refresh Token for BrokerServer by @luketomlinson in https://github.com/actions/runner/pull/3167 * Upgrade `docker` from `24.0.7` to `24.0.8` by @MPV in https://github.com/actions/runner/pull/3124
* Better step timeout message. by @TingluoHuang in https://github.com/actions/runner/pull/3166 * Upload the diagnostic logs to the Results Service by @jtamsut in https://github.com/actions/runner/pull/3114
* Upgrade `docker` from `24.0.8` to `24.0.9` by @MPV in https://github.com/actions/runner/pull/3126
* Make sure to drain the upload queue before clean temp directory by @yacaovsnc in https://github.com/actions/runner/pull/3125
* Specify `Content-Type` for BlockBlob upload by @bethanyj28 in https://github.com/actions/runner/pull/3119
* Improve error report for invalid action.yml by @jsoref in https://github.com/actions/runner/pull/3106
* Add sshd to .devcontainer.json by @pje in https://github.com/actions/runner/pull/3079
* Resolve CVE-2024-21626 by @luka5 in https://github.com/actions/runner/pull/3123
* Handle ForceTokenRefresh message by @luketomlinson in https://github.com/actions/runner/pull/3133
* Bump hook version to 0.5.1 by @nikola-jokic in https://github.com/actions/runner/pull/3129
## New Contributors ## New Contributors
* @davidomid made their first contribution in https://github.com/actions/runner/pull/3135 * @diogotorres97 made their first contribution in https://github.com/actions/runner/pull/3100
* @enescakir made their first contribution in https://github.com/actions/runner/pull/3089 * @MPV made their first contribution in https://github.com/actions/runner/pull/3124
* @jtamsut made their first contribution in https://github.com/actions/runner/pull/3114
* @luka5 made their first contribution in https://github.com/actions/runner/pull/3123
**Full Changelog**: https://github.com/actions/runner/compare/v2.313.0...v2.314.0 **Full Changelog**: https://github.com/actions/runner/compare/v2.312.0...v2.313.0
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet. _Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository. To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.

View File

@@ -21,10 +21,6 @@ namespace GitHub.Runner.Common
Task DeleteSessionAsync(CancellationToken cancellationToken); Task DeleteSessionAsync(CancellationToken cancellationToken);
Task<TaskAgentMessage> GetRunnerMessageAsync(Guid? sessionId, TaskAgentStatus status, string version, string os, string architecture, bool disableUpdate, CancellationToken token); Task<TaskAgentMessage> GetRunnerMessageAsync(Guid? sessionId, TaskAgentStatus status, string version, string os, string architecture, bool disableUpdate, CancellationToken token);
Task UpdateConnectionIfNeeded(Uri serverUri, VssCredentials credentials);
Task ForceRefreshConnection(VssCredentials credentials);
} }
public sealed class BrokerServer : RunnerService, IBrokerServer public sealed class BrokerServer : RunnerService, IBrokerServer
@@ -63,8 +59,7 @@ namespace GitHub.Runner.Common
{ {
CheckConnection(); CheckConnection();
var brokerSession = RetryRequest<TaskAgentMessage>( var brokerSession = RetryRequest<TaskAgentMessage>(
async () => await _brokerHttpClient.GetRunnerMessageAsync(sessionId, version, status, os, architecture, disableUpdate, cancellationToken), cancellationToken, shouldRetry: ShouldRetryException); async () => await _brokerHttpClient.GetRunnerMessageAsync(sessionId, version, status, os, architecture, disableUpdate, cancellationToken), cancellationToken);
return brokerSession; return brokerSession;
} }
@@ -74,30 +69,5 @@ namespace GitHub.Runner.Common
CheckConnection(); CheckConnection();
await _brokerHttpClient.DeleteSessionAsync(cancellationToken); await _brokerHttpClient.DeleteSessionAsync(cancellationToken);
} }
public Task UpdateConnectionIfNeeded(Uri serverUri, VssCredentials credentials)
{
if (_brokerUri != serverUri || !_hasConnection)
{
return ConnectAsync(serverUri, credentials);
}
return Task.CompletedTask;
}
public Task ForceRefreshConnection(VssCredentials credentials)
{
return ConnectAsync(_brokerUri, credentials);
}
public bool ShouldRetryException(Exception ex)
{
if (ex is AccessDeniedException ade && ade.ErrorCode == 1)
{
return false;
}
return true;
}
} }
} }

View File

@@ -5,7 +5,6 @@ using System.Threading.Tasks;
using GitHub.Actions.RunService.WebApi; using GitHub.Actions.RunService.WebApi;
using GitHub.DistributedTask.Pipelines; using GitHub.DistributedTask.Pipelines;
using GitHub.DistributedTask.WebApi; using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Common.Util;
using GitHub.Runner.Sdk; using GitHub.Runner.Sdk;
using GitHub.Services.Common; using GitHub.Services.Common;
using Sdk.RSWebApi.Contracts; using Sdk.RSWebApi.Contracts;
@@ -61,7 +60,7 @@ namespace GitHub.Runner.Common
{ {
CheckConnection(); CheckConnection();
return RetryRequest<AgentJobRequestMessage>( return RetryRequest<AgentJobRequestMessage>(
async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, VarUtil.OS, cancellationToken), cancellationToken, async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, cancellationToken), cancellationToken,
shouldRetry: ex => ex is not TaskOrchestrationJobAlreadyAcquiredException); shouldRetry: ex => ex is not TaskOrchestrationJobAlreadyAcquiredException);
} }

View File

@@ -35,7 +35,7 @@ namespace GitHub.Runner.Listener
// This implementation of IJobDispatcher is not thread safe. // This implementation of IJobDispatcher is not thread safe.
// It is based on the fact that the current design of the runner is a dequeue // It is based on the fact that the current design of the runner is a dequeue
// and processes one message from the message queue at a time. // and processes one message from the message queue at a time.
// In addition, it only executes one job every time, // In addition, it only executes one job every time,
// and the server will not send another job while this one is still running. // and the server will not send another job while this one is still running.
public sealed class JobDispatcher : RunnerService, IJobDispatcher public sealed class JobDispatcher : RunnerService, IJobDispatcher
{ {
@@ -546,27 +546,13 @@ namespace GitHub.Runner.Listener
Trace.Info($"Return code {returnCode} indicate worker encounter an unhandled exception or app crash, attach worker stdout/stderr to JobRequest result."); Trace.Info($"Return code {returnCode} indicate worker encounter an unhandled exception or app crash, attach worker stdout/stderr to JobRequest result.");
var jobServer = await InitializeJobServerAsync(systemConnection); var jobServer = await InitializeJobServerAsync(systemConnection);
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo }; await LogWorkerProcessUnhandledException(jobServer, message, detailInfo);
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
switch (jobServer)
{
case IJobServer js:
{
await LogWorkerProcessUnhandledException(js, message, unhandledExceptionIssue);
// Go ahead to finish the job with result 'Failed' if the STDERR from worker is System.IO.IOException, since it typically means we are running out of disk space.
if (detailInfo.Contains(typeof(System.IO.IOException).ToString(), StringComparison.OrdinalIgnoreCase))
{
Trace.Info($"Finish job with result 'Failed' due to IOException.");
await ForceFailJob(js, message);
}
break; // Go ahead to finish the job with result 'Failed' if the STDERR from worker is System.IO.IOException, since it typically means we are running out of disk space.
} if (detailInfo.Contains(typeof(System.IO.IOException).ToString(), StringComparison.OrdinalIgnoreCase))
case IRunServer rs: {
await ForceFailJob(rs, message, unhandledExceptionIssue); Trace.Info($"Finish job with result 'Failed' due to IOException.");
break; await ForceFailJob(jobServer, message, detailInfo);
default:
throw new NotSupportedException($"JobServer type '{jobServer.GetType().Name}' is not supported.");
} }
} }
@@ -658,7 +644,7 @@ namespace GitHub.Runner.Listener
} }
} }
// wait worker to exit // wait worker to exit
// if worker doesn't exit within timeout, then kill worker. // if worker doesn't exit within timeout, then kill worker.
completedTask = await Task.WhenAny(workerProcessTask, Task.Delay(-1, workerCancelTimeoutKillToken)); completedTask = await Task.WhenAny(workerProcessTask, Task.Delay(-1, workerCancelTimeoutKillToken));
@@ -1145,70 +1131,86 @@ namespace GitHub.Runner.Listener
} }
// log an error issue to job level timeline record // log an error issue to job level timeline record
private async Task LogWorkerProcessUnhandledException(IJobServer jobServer, Pipelines.AgentJobRequestMessage message, Issue issue) private async Task LogWorkerProcessUnhandledException(IRunnerService server, Pipelines.AgentJobRequestMessage message, string detailInfo)
{ {
try if (server is IJobServer jobServer)
{ {
var timeline = await jobServer.GetTimelineAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, CancellationToken.None); try
ArgUtil.NotNull(timeline, nameof(timeline));
TimelineRecord jobRecord = timeline.Records.FirstOrDefault(x => x.Id == message.JobId && x.RecordType == "Job");
ArgUtil.NotNull(jobRecord, nameof(jobRecord));
jobRecord.ErrorCount++;
jobRecord.Issues.Add(issue);
if (message.Variables.TryGetValue("DistributedTask.MarkJobAsFailedOnWorkerCrash", out var markJobAsFailedOnWorkerCrash) &&
StringUtil.ConvertToBoolean(markJobAsFailedOnWorkerCrash?.Value))
{ {
Trace.Info("Mark the job as failed since the worker crashed"); var timeline = await jobServer.GetTimelineAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, CancellationToken.None);
jobRecord.Result = TaskResult.Failed; ArgUtil.NotNull(timeline, nameof(timeline));
// mark the job as completed so service will pickup the result
jobRecord.State = TimelineRecordState.Completed;
}
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, new TimelineRecord[] { jobRecord }, CancellationToken.None); TimelineRecord jobRecord = timeline.Records.FirstOrDefault(x => x.Id == message.JobId && x.RecordType == "Job");
ArgUtil.NotNull(jobRecord, nameof(jobRecord));
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo };
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
jobRecord.ErrorCount++;
jobRecord.Issues.Add(unhandledExceptionIssue);
if (message.Variables.TryGetValue("DistributedTask.MarkJobAsFailedOnWorkerCrash", out var markJobAsFailedOnWorkerCrash) &&
StringUtil.ConvertToBoolean(markJobAsFailedOnWorkerCrash?.Value))
{
Trace.Info("Mark the job as failed since the worker crashed");
jobRecord.Result = TaskResult.Failed;
// mark the job as completed so service will pickup the result
jobRecord.State = TimelineRecordState.Completed;
}
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, new TimelineRecord[] { jobRecord }, CancellationToken.None);
}
catch (Exception ex)
{
Trace.Error("Fail to report unhandled exception from Runner.Worker process");
Trace.Error(ex);
}
} }
catch (Exception ex) else
{ {
Trace.Error("Fail to report unhandled exception from Runner.Worker process"); Trace.Info("Job server does not support handling unhandled exception yet, error message: {0}", detailInfo);
Trace.Error(ex); return;
} }
} }
// raise job completed event to fail the job. // raise job completed event to fail the job.
private async Task ForceFailJob(IJobServer jobServer, Pipelines.AgentJobRequestMessage message) private async Task ForceFailJob(IRunnerService server, Pipelines.AgentJobRequestMessage message, string detailInfo)
{ {
try if (server is IJobServer jobServer)
{ {
var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, TaskResult.Failed); try
await jobServer.RaisePlanEventAsync<JobCompletedEvent>(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, jobCompletedEvent, CancellationToken.None);
}
catch (Exception ex)
{
Trace.Error("Fail to raise JobCompletedEvent back to service.");
Trace.Error(ex);
}
}
private async Task ForceFailJob(IRunServer runServer, Pipelines.AgentJobRequestMessage message, Issue issue)
{
try
{
var annotation = issue.ToAnnotation();
var jobAnnotations = new List<Annotation>();
if (annotation.HasValue)
{ {
jobAnnotations.Add(annotation.Value); var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, TaskResult.Failed);
await jobServer.RaisePlanEventAsync<JobCompletedEvent>(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, jobCompletedEvent, CancellationToken.None);
}
catch (Exception ex)
{
Trace.Error("Fail to raise JobCompletedEvent back to service.");
Trace.Error(ex);
} }
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, CancellationToken.None);
} }
catch (Exception ex) else if (server is IRunServer runServer)
{ {
Trace.Error("Fail to raise job completion back to service."); try
Trace.Error(ex); {
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo };
var unhandledAnnotation = unhandledExceptionIssue.ToAnnotation();
var jobAnnotations = new List<Annotation>();
if (unhandledAnnotation.HasValue)
{
jobAnnotations.Add(unhandledAnnotation.Value);
}
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, CancellationToken.None);
}
catch (Exception ex)
{
Trace.Error("Fail to raise job completion back to service.");
Trace.Error(ex);
}
}
else
{
throw new NotSupportedException($"Server type {server.GetType().FullName} is not supported.");
} }
} }

View File

@@ -109,8 +109,7 @@ namespace GitHub.Runner.Listener
if (_session.BrokerMigrationMessage != null) if (_session.BrokerMigrationMessage != null)
{ {
Trace.Info("Runner session is in migration mode: Creating Broker session with BrokerBaseUrl: {0}", _session.BrokerMigrationMessage.BrokerBaseUrl); Trace.Info("Runner session is in migration mode: Creating Broker session with BrokerBaseUrl: {0}", _session.BrokerMigrationMessage.BrokerBaseUrl);
await _brokerServer.ConnectAsync(_session.BrokerMigrationMessage.BrokerBaseUrl, _creds);
await _brokerServer.UpdateConnectionIfNeeded(_session.BrokerMigrationMessage.BrokerBaseUrl, _creds);
_session = await _brokerServer.CreateSessionAsync(taskAgentSession, token); _session = await _brokerServer.CreateSessionAsync(taskAgentSession, token);
_isBrokerSession = true; _isBrokerSession = true;
} }
@@ -205,17 +204,19 @@ namespace GitHub.Runner.Listener
public void OnJobStatus(object sender, JobStatusEventArgs e) public void OnJobStatus(object sender, JobStatusEventArgs e)
{ {
Trace.Info("Received job status event. JobState: {0}", e.Status); if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("USE_BROKER_FLOW")))
runnerStatus = e.Status;
try
{ {
_getMessagesTokenSource?.Cancel(); Trace.Info("Received job status event. JobState: {0}", e.Status);
runnerStatus = e.Status;
try
{
_getMessagesTokenSource?.Cancel();
}
catch (ObjectDisposedException)
{
Trace.Info("_getMessagesTokenSource is already disposed.");
}
} }
catch (ObjectDisposedException)
{
Trace.Info("_getMessagesTokenSource is already disposed.");
}
} }
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token) public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
@@ -255,7 +256,7 @@ namespace GitHub.Runner.Listener
var migrationMessage = JsonUtility.FromString<BrokerMigrationMessage>(message.Body); var migrationMessage = JsonUtility.FromString<BrokerMigrationMessage>(message.Body);
await _brokerServer.UpdateConnectionIfNeeded(migrationMessage.BrokerBaseUrl, _creds); await _brokerServer.ConnectAsync(migrationMessage.BrokerBaseUrl, _creds);
message = await _brokerServer.GetRunnerMessageAsync(_session.SessionId, message = await _brokerServer.GetRunnerMessageAsync(_session.SessionId,
runnerStatus, runnerStatus,
BuildConstants.RunnerPackage.Version, BuildConstants.RunnerPackage.Version,
@@ -383,7 +384,6 @@ namespace GitHub.Runner.Listener
public async Task RefreshListenerTokenAsync(CancellationToken cancellationToken) public async Task RefreshListenerTokenAsync(CancellationToken cancellationToken)
{ {
await _runnerServer.RefreshConnectionAsync(RunnerConnectionType.MessageQueue, TimeSpan.FromSeconds(60)); await _runnerServer.RefreshConnectionAsync(RunnerConnectionType.MessageQueue, TimeSpan.FromSeconds(60));
await _brokerServer.ForceRefreshConnection(_creds);
} }
private TaskAgentMessage DecryptMessage(TaskAgentMessage message) private TaskAgentMessage DecryptMessage(TaskAgentMessage message)

View File

@@ -598,7 +598,6 @@ namespace GitHub.Runner.Listener
} }
else if (string.Equals(message.MessageType, TaskAgentMessageTypes.ForceTokenRefresh)) else if (string.Equals(message.MessageType, TaskAgentMessageTypes.ForceTokenRefresh))
{ {
Trace.Info("Received ForceTokenRefreshMessage");
await _listener.RefreshListenerTokenAsync(messageQueueLoopTokenSource.Token); await _listener.RefreshListenerTokenAsync(messageQueueLoopTokenSource.Token);
} }
else else

View File

@@ -85,6 +85,11 @@ namespace GitHub.Runner.Sdk
settings.SendTimeout = TimeSpan.FromSeconds(Math.Min(Math.Max(httpRequestTimeoutSeconds, 100), 1200)); settings.SendTimeout = TimeSpan.FromSeconds(Math.Min(Math.Max(httpRequestTimeoutSeconds, 100), 1200));
} }
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("USE_BROKER_FLOW")))
{
settings.AllowAutoRedirectForBroker = true;
}
// Remove Invariant from the list of accepted languages. // Remove Invariant from the list of accepted languages.
// //
// The constructor of VssHttpRequestSettings (base class of VssClientHttpRequestSettings) adds the current // The constructor of VssHttpRequestSettings (base class of VssClientHttpRequestSettings) adds the current

View File

@@ -466,39 +466,17 @@ namespace GitHub.Runner.Worker
{ {
throw new InvalidOperationException($"Failed to create directory to store registry client credentials: {e.Message}"); throw new InvalidOperationException($"Failed to create directory to store registry client credentials: {e.Message}");
} }
var loginExitCode = await _dockerManager.DockerLogin(
executionContext,
configLocation,
container.RegistryServer,
container.RegistryAuthUsername,
container.RegistryAuthPassword);
// Login docker with retry up to 3 times if (loginExitCode != 0)
int retryCount = 0;
int loginExitCode = 0;
while (retryCount < 3)
{
loginExitCode = await _dockerManager.DockerLogin(
executionContext,
configLocation,
container.RegistryServer,
container.RegistryAuthUsername,
container.RegistryAuthPassword);
if (loginExitCode == 0)
{
break;
}
else
{
retryCount++;
if (retryCount < 3)
{
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(10));
executionContext.Warning($"Docker login for '{container.RegistryServer}' failed with exit code {loginExitCode}, back off {backOff.TotalSeconds} seconds before retry.");
await Task.Delay(backOff);
}
}
}
if (retryCount == 3 && loginExitCode != 0)
{ {
throw new InvalidOperationException($"Docker login for '{container.RegistryServer}' failed with exit code {loginExitCode}"); throw new InvalidOperationException($"Docker login for '{container.RegistryServer}' failed with exit code {loginExitCode}");
} }
return configLocation; return configLocation;
} }

View File

@@ -392,18 +392,6 @@ namespace GitHub.Runner.Worker
} }
} }
// Register custom image creation post-job step if the "snapshot" token is present in the message.
var snapshotRequest = templateEvaluator.EvaluateJobSnapshotRequest(message.Snapshot, jobContext.ExpressionValues, jobContext.ExpressionFunctions);
if (snapshotRequest != null)
{
var snapshotOperationProvider = HostContext.GetService<ISnapshotOperationProvider>();
jobContext.RegisterPostJobStep(new JobExtensionRunner(
runAsync: (executionContext, _) => snapshotOperationProvider.CreateSnapshotRequestAsync(executionContext, snapshotRequest),
condition: $"{PipelineTemplateConstants.Success}()",
displayName: $"Create custom image",
data: null));
}
// Register Job Completed hook if the variable is set // Register Job Completed hook if the variable is set
var completedHookPath = Environment.GetEnvironmentVariable("ACTIONS_RUNNER_HOOK_JOB_COMPLETED"); var completedHookPath = Environment.GetEnvironmentVariable("ACTIONS_RUNNER_HOOK_JOB_COMPLETED");
if (!string.IsNullOrEmpty(completedHookPath)) if (!string.IsNullOrEmpty(completedHookPath))

View File

@@ -1,32 +0,0 @@
#nullable enable
using System.IO;
using System.Threading.Tasks;
using GitHub.DistributedTask.Pipelines;
using GitHub.Runner.Common;
using GitHub.Runner.Sdk;
namespace GitHub.Runner.Worker;
[ServiceLocator(Default = typeof(SnapshotOperationProvider))]
public interface ISnapshotOperationProvider : IRunnerService
{
Task CreateSnapshotRequestAsync(IExecutionContext executionContext, Snapshot snapshotRequest);
}
public class SnapshotOperationProvider : RunnerService, ISnapshotOperationProvider
{
public Task CreateSnapshotRequestAsync(IExecutionContext executionContext, Snapshot snapshotRequest)
{
var snapshotRequestFilePath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), ".snapshot", "request.json");
var snapshotRequestDirectoryPath = Path.GetDirectoryName(snapshotRequestFilePath);
if (snapshotRequestDirectoryPath != null)
{
Directory.CreateDirectory(snapshotRequestDirectoryPath);
}
IOUtil.SaveObject(snapshotRequest, snapshotRequestFilePath);
executionContext.Output($"Request written to: {snapshotRequestFilePath}");
executionContext.Output("This request will be processed after the job completes. You will not receive any feedback on the snapshot process within the workflow logs of this job.");
executionContext.Output("If the snapshot process is successful, you should see a new image with the requested name in the list of available custom images when creating a new GitHub-hosted Runner.");
return Task.CompletedTask;
}
}

View File

@@ -295,7 +295,7 @@ namespace GitHub.Runner.Worker
!jobCancellationToken.IsCancellationRequested) !jobCancellationToken.IsCancellationRequested)
{ {
Trace.Error($"Caught timeout exception from step: {ex.Message}"); Trace.Error($"Caught timeout exception from step: {ex.Message}");
step.ExecutionContext.Error($"The action '{step.DisplayName}' has timed out after {timeoutMinutes} minutes."); step.ExecutionContext.Error("The action has timed out.");
step.ExecutionContext.Result = TaskResult.Failed; step.ExecutionContext.Result = TaskResult.Failed;
} }
else else

View File

@@ -214,7 +214,25 @@ namespace GitHub.Services.Common
// ConfigureAwait(false) enables the continuation to be run outside any captured // ConfigureAwait(false) enables the continuation to be run outside any captured
// SyncronizationContext (such as ASP.NET's) which keeps things from deadlocking... // SyncronizationContext (such as ASP.NET's) which keeps things from deadlocking...
response = await m_messageInvoker.SendAsync(request, tokenSource.Token).ConfigureAwait(false); var tmpResponse = await m_messageInvoker.SendAsync(request, tokenSource.Token).ConfigureAwait(false);
if (Settings.AllowAutoRedirectForBroker && tmpResponse.StatusCode == HttpStatusCode.Redirect)
{
//Dispose of the previous response
tmpResponse?.Dispose();
var location = tmpResponse.Headers.Location;
request = new HttpRequestMessage(HttpMethod.Get, location);
// Reapply the token to new redirected request
ApplyToken(request, token, applyICredentialsToWebProxy: lastResponseDemandedProxyAuth);
// Resend the request
response = await m_messageInvoker.SendAsync(request, tokenSource.Token).ConfigureAwait(false);
}
else
{
response = tmpResponse;
}
traceInfo?.TraceRequestSendTime(); traceInfo?.TraceRequestSendTime();

View File

@@ -110,6 +110,16 @@ namespace GitHub.Services.Common
set; set;
} }
/// <summary>
/// Gets or sets a value indicating whether or not HttpClientHandler should follow redirect on outgoing broker requests
/// This is special since this also sends token in the request, where as default AllowAutoRedirect does not
/// </summary>
public Boolean AllowAutoRedirectForBroker
{
get;
set;
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether or not compression should be used on outgoing requests. /// Gets or sets a value indicating whether or not compression should be used on outgoing requests.
/// The default value is true. /// The default value is true.

View File

@@ -43,7 +43,6 @@ namespace GitHub.DistributedTask.Pipelines
TemplateToken jobOutputs, TemplateToken jobOutputs,
IList<TemplateToken> defaults, IList<TemplateToken> defaults,
ActionsEnvironmentReference actionsEnvironment, ActionsEnvironmentReference actionsEnvironment,
TemplateToken snapshot,
String messageType = JobRequestMessageTypes.PipelineAgentJobRequest) String messageType = JobRequestMessageTypes.PipelineAgentJobRequest)
{ {
this.MessageType = messageType; this.MessageType = messageType;
@@ -58,7 +57,6 @@ namespace GitHub.DistributedTask.Pipelines
this.Workspace = workspaceOptions; this.Workspace = workspaceOptions;
this.JobOutputs = jobOutputs; this.JobOutputs = jobOutputs;
this.ActionsEnvironment = actionsEnvironment; this.ActionsEnvironment = actionsEnvironment;
this.Snapshot = snapshot;
m_variables = new Dictionary<String, VariableValue>(variables, StringComparer.OrdinalIgnoreCase); m_variables = new Dictionary<String, VariableValue>(variables, StringComparer.OrdinalIgnoreCase);
m_maskHints = new List<MaskHint>(maskHints); m_maskHints = new List<MaskHint>(maskHints);
m_steps = new List<JobStep>(steps); m_steps = new List<JobStep>(steps);
@@ -239,13 +237,6 @@ namespace GitHub.DistributedTask.Pipelines
set; set;
} }
[DataMember(EmitDefaultValue = false)]
public TemplateToken Snapshot
{
get;
set;
}
/// <summary> /// <summary>
/// Gets the collection of variables associated with the current context. /// Gets the collection of variables associated with the current context.
/// </summary> /// </summary>

View File

@@ -29,7 +29,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String Id = "id"; public const String Id = "id";
public const String If = "if"; public const String If = "if";
public const String Image = "image"; public const String Image = "image";
public const String ImageName = "image-name";
public const String Include = "include"; public const String Include = "include";
public const String Inputs = "inputs"; public const String Inputs = "inputs";
public const String Job = "job"; public const String Job = "job";
@@ -61,7 +60,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String Services = "services"; public const String Services = "services";
public const String Shell = "shell"; public const String Shell = "shell";
public const String Skipped = "skipped"; public const String Skipped = "skipped";
public const String Snapshot = "snapshot";
public const String StepEnv = "step-env"; public const String StepEnv = "step-env";
public const String StepIfResult = "step-if-result"; public const String StepIfResult = "step-if-result";
public const String StepWith = "step-with"; public const String StepWith = "step-with";

View File

@@ -346,39 +346,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
return result; return result;
} }
internal static Snapshot ConvertToJobSnapshotRequest(TemplateContext context, TemplateToken token)
{
string imageName = null;
if (token is StringToken snapshotStringLiteral)
{
imageName = snapshotStringLiteral.Value;
}
else
{
var snapshotMapping = token.AssertMapping($"{PipelineTemplateConstants.Snapshot}");
foreach (var snapshotPropertyPair in snapshotMapping)
{
var propertyName = snapshotPropertyPair.Key.AssertString($"{PipelineTemplateConstants.Snapshot} key");
switch (propertyName.Value)
{
case PipelineTemplateConstants.ImageName:
imageName = snapshotPropertyPair.Value.AssertString($"{PipelineTemplateConstants.Snapshot} {propertyName}").Value;
break;
default:
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Snapshot} key");
break;
}
}
}
if (String.IsNullOrEmpty(imageName))
{
return null;
}
return new Snapshot(imageName);
}
private static ActionStep ConvertToStep( private static ActionStep ConvertToStep(
TemplateContext context, TemplateContext context,
TemplateToken stepsItem, TemplateToken stepsItem,

View File

@@ -370,32 +370,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
return result; return result;
} }
public Snapshot EvaluateJobSnapshotRequest(TemplateToken token,
DictionaryContextData contextData,
IList<IFunctionInfo> expressionFunctions)
{
var result = default(Snapshot);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(contextData, expressionFunctions);
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.Snapshot, token, 0, null, omitHeader: true);
context.Errors.Check();
result = PipelineTemplateConverter.ConvertToJobSnapshotRequest(context, token);
}
catch (Exception ex) when (!(ex is TemplateValidationException))
{
context.Errors.Add(ex);
}
context.Errors.Check();
}
return result;
}
private TemplateContext CreateContext( private TemplateContext CreateContext(
DictionaryContextData contextData, DictionaryContextData contextData,
IList<IFunctionInfo> expressionFunctions, IList<IFunctionInfo> expressionFunctions,

View File

@@ -1,17 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace GitHub.DistributedTask.Pipelines
{
[DataContract]
public class Snapshot
{
public Snapshot(string imageName)
{
ImageName = imageName;
}
[DataMember(EmitDefaultValue = false)]
public String ImageName { get; set; }
}
}

View File

@@ -71,8 +71,7 @@
"env": "job-env", "env": "job-env",
"outputs": "job-outputs", "outputs": "job-outputs",
"defaults": "job-defaults", "defaults": "job-defaults",
"steps": "steps", "steps": "steps"
"snapshot": "snapshot"
} }
} }
}, },
@@ -156,24 +155,6 @@
} }
}, },
"snapshot": {
"one-of": [
"non-empty-string",
"snapshot-mapping"
]
},
"snapshot-mapping": {
"mapping": {
"properties": {
"image-name": {
"type": "non-empty-string",
"required": true
}
}
}
},
"runs-on": { "runs-on": {
"context": [ "context": [
"github", "github",

View File

@@ -7,8 +7,5 @@ namespace GitHub.Actions.RunService.WebApi
{ {
[DataMember(Name = "jobMessageId", EmitDefaultValue = false)] [DataMember(Name = "jobMessageId", EmitDefaultValue = false)]
public string JobMessageId { get; set; } public string JobMessageId { get; set; }
[DataMember(Name = "runnerOS", EmitDefaultValue = false)]
public string RunnerOS { get; set; }
} }
} }

View File

@@ -59,14 +59,12 @@ namespace GitHub.Actions.RunService.WebApi
public async Task<AgentJobRequestMessage> GetJobMessageAsync( public async Task<AgentJobRequestMessage> GetJobMessageAsync(
Uri requestUri, Uri requestUri,
string messageId, string messageId,
string runnerOS,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
HttpMethod httpMethod = new HttpMethod("POST"); HttpMethod httpMethod = new HttpMethod("POST");
var payload = new AcquireJobRequest var payload = new AcquireJobRequest
{ {
JobMessageId = messageId, JobMessageId = messageId,
RunnerOS = runnerOS
}; };
requestUri = new Uri(requestUri, "acquirejob"); requestUri = new Uri(requestUri, "acquirejob");

View File

@@ -110,14 +110,9 @@ namespace GitHub.Actions.RunService.WebApi
return result.Value; return result.Value;
} }
// the only time we throw a `Forbidden` exception from Listener /messages is when the runner is
// disable_update and is too old to poll
if (result.StatusCode == HttpStatusCode.Forbidden) if (result.StatusCode == HttpStatusCode.Forbidden)
{ {
throw new AccessDeniedException($"{result.Error} Runner version v{runnerVersion} is deprecated and cannot receive messages.") throw new AccessDeniedException(result.Error);
{
ErrorCode = 1
};
} }
throw new Exception($"Failed to get job message: {result.Error}"); throw new Exception($"Failed to get job message: {result.Error}");

View File

@@ -41,7 +41,7 @@ namespace GitHub.Runner.Common.Tests.Listener
TaskOrchestrationPlanReference plan = new(); TaskOrchestrationPlanReference plan = new();
TimelineReference timeline = null; TimelineReference timeline = null;
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData(); result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
return result; return result;
} }
@@ -806,8 +806,7 @@ namespace GitHub.Runner.Common.Tests.Listener
}, },
null, null,
new List<TemplateToken>(), new List<TemplateToken>(),
new ActionsEnvironmentReference("env"), new ActionsEnvironmentReference("env")
null
); );
return message; return message;
} }

View File

@@ -42,7 +42,7 @@ namespace GitHub.Runner.Common.Tests.Listener
TaskOrchestrationPlanReference plan = new(); TaskOrchestrationPlanReference plan = new();
TimelineReference timeline = null; TimelineReference timeline = null;
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
} }
private JobCancelMessage CreateJobCancelMessage() private JobCancelMessage CreateJobCancelMessage()

View File

@@ -232,7 +232,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,

View File

@@ -193,7 +193,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "Summary Job"; string jobName = "Summary Job";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,

View File

@@ -29,7 +29,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -106,7 +106,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -162,7 +162,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -216,7 +216,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -271,7 +271,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -322,7 +322,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -373,7 +373,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -471,7 +471,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -555,7 +555,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -610,7 +610,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -653,7 +653,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -717,7 +717,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -781,7 +781,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -969,7 +969,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new(); TimelineReference timeline = new();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -1014,7 +1014,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -1057,7 +1057,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,

View File

@@ -4,8 +4,6 @@ using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
using GitHub.DistributedTask.WebApi; using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Worker; using GitHub.Runner.Worker;
using Moq; using Moq;
@@ -27,9 +25,6 @@ namespace GitHub.Runner.Common.Tests.Worker
private Mock<IContainerOperationProvider> _containerProvider; private Mock<IContainerOperationProvider> _containerProvider;
private Mock<IDiagnosticLogManager> _diagnosticLogManager; private Mock<IDiagnosticLogManager> _diagnosticLogManager;
private Mock<IJobHookProvider> _jobHookProvider; private Mock<IJobHookProvider> _jobHookProvider;
private Mock<ISnapshotOperationProvider> _snapshotOperationProvider;
private Pipelines.Snapshot _requestedSnapshot;
private CancellationTokenSource _tokenSource; private CancellationTokenSource _tokenSource;
private TestHostContext CreateTestContext([CallerMemberName] String testName = "") private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
@@ -46,16 +41,7 @@ namespace GitHub.Runner.Common.Tests.Worker
_directoryManager.Setup(x => x.PrepareDirectory(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.WorkspaceOptions>())) _directoryManager.Setup(x => x.PrepareDirectory(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.WorkspaceOptions>()))
.Returns(new TrackingConfig() { PipelineDirectory = "runner", WorkspaceDirectory = "runner/runner" }); .Returns(new TrackingConfig() { PipelineDirectory = "runner", WorkspaceDirectory = "runner/runner" });
_jobHookProvider = new Mock<IJobHookProvider>(); _jobHookProvider = new Mock<IJobHookProvider>();
_snapshotOperationProvider = new Mock<ISnapshotOperationProvider>();
_requestedSnapshot = null;
_snapshotOperationProvider
.Setup(p => p.CreateSnapshotRequestAsync(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.Snapshot>()))
.Returns((IExecutionContext _, object data) =>
{
_requestedSnapshot = data as Pipelines.Snapshot;
return Task.CompletedTask;
});
IActionRunner step1 = new ActionRunner(); IActionRunner step1 = new ActionRunner();
IActionRunner step2 = new ActionRunner(); IActionRunner step2 = new ActionRunner();
IActionRunner step3 = new ActionRunner(); IActionRunner step3 = new ActionRunner();
@@ -114,7 +100,7 @@ namespace GitHub.Runner.Common.Tests.Worker
}; };
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null, null, null); _message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null, null);
GitHubContext github = new(); GitHubContext github = new();
github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner"); github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner");
github["secret_source"] = new Pipelines.ContextData.StringContextData("Actions"); github["secret_source"] = new Pipelines.ContextData.StringContextData("Actions");
@@ -139,7 +125,6 @@ namespace GitHub.Runner.Common.Tests.Worker
hc.SetSingleton(_directoryManager.Object); hc.SetSingleton(_directoryManager.Object);
hc.SetSingleton(_diagnosticLogManager.Object); hc.SetSingleton(_diagnosticLogManager.Object);
hc.SetSingleton(_jobHookProvider.Object); hc.SetSingleton(_jobHookProvider.Object);
hc.SetSingleton(_snapshotOperationProvider.Object);
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // JobExecutionContext hc.EnqueueInstance<IPagingLogger>(_logger.Object); // JobExecutionContext
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // job start hook hc.EnqueueInstance<IPagingLogger>(_logger.Object); // job start hook
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // Initial Job hc.EnqueueInstance<IPagingLogger>(_logger.Object); // Initial Job
@@ -458,80 +443,5 @@ namespace GitHub.Runner.Common.Tests.Worker
Assert.Equal(0, _jobEc.PostJobSteps.Count); Assert.Equal(0, _jobEc.PostJobSteps.Count);
} }
} }
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task EnsureNoSnapshotPostJobStep()
{
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>())));
_message.Snapshot = null;
await jobExtension.InitializeJob(_jobEc, _message);
var postJobSteps = _jobEc.PostJobSteps;
Assert.Equal(0, postJobSteps.Count);
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public Task EnsureSnapshotPostJobStepForStringToken()
{
var snapshot = new Pipelines.Snapshot("TestImageNameFromStringToken");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
return EnsureSnapshotPostJobStepForToken(imageNameValueStringToken, snapshot);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public Task EnsureSnapshotPostJobStepForMappingToken()
{
var snapshot = new Pipelines.Snapshot("TestImageNameFromMappingToken");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
var mappingToken = new MappingToken(null, null, null)
{
{ new StringToken(null,null,null, PipelineTemplateConstants.ImageName), imageNameValueStringToken }
};
return EnsureSnapshotPostJobStepForToken(mappingToken, snapshot);
}
private async Task EnsureSnapshotPostJobStepForToken(TemplateToken snapshotToken, Pipelines.Snapshot expectedSnapshot)
{
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>())));
_message.Snapshot = snapshotToken;
await jobExtension.InitializeJob(_jobEc, _message);
var postJobSteps = _jobEc.PostJobSteps;
Assert.Equal(1, postJobSteps.Count);
var snapshotStep = postJobSteps.First();
Assert.Equal("Create custom image", snapshotStep.DisplayName);
Assert.Equal($"{PipelineTemplateConstants.Success}()", snapshotStep.Condition);
// Run the mock snapshot step, so we can verify it was executed with the expected snapshot object.
await snapshotStep.RunAsync();
Assert.NotNull(_requestedSnapshot);
Assert.Equal(expectedSnapshot.ImageName, _requestedSnapshot.ImageName);
}
}
} }
} }

View File

@@ -101,7 +101,6 @@ namespace GitHub.Runner.Common.Tests.Worker
testName, testName,
testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null,
new ActionsEnvironmentReference("staging"), new ActionsEnvironmentReference("staging"),
null,
messageType: messageType); messageType: messageType);
message.Variables[Constants.Variables.System.Culture] = "en-US"; message.Variables[Constants.Variables.System.Culture] = "en-US";
message.Resources.Endpoints.Add(new ServiceEndpoint() message.Resources.Endpoints.Add(new ServiceEndpoint()

View File

@@ -1,78 +0,0 @@
#nullable enable
using System;
using System.IO;
using System.Runtime.CompilerServices;
using GitHub.DistributedTask.Pipelines;
using GitHub.Runner.Sdk;
using GitHub.Runner.Worker;
using Moq;
using Xunit;
namespace GitHub.Runner.Common.Tests.Worker;
public class SnapshotOperationProviderL0
{
private Mock<IExecutionContext>? _ec;
private SnapshotOperationProvider? _snapshotOperationProvider;
private string? _snapshotRequestFilePath;
private string? _snapshotRequestDirectoryPath;
[Theory]
[InlineData(true)]
[InlineData(false)]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async void CreateSnapshotRequestAsync(bool shouldSnapshotDirectoryAlreadyExist)
{
using (TestHostContext testHostContext = CreateTestHostContext())
{
//Arrange
Setup(testHostContext, shouldSnapshotDirectoryAlreadyExist);
var expectedSnapshot = new Snapshot(Guid.NewGuid().ToString());
//Act
await _snapshotOperationProvider!.CreateSnapshotRequestAsync(_ec!.Object, expectedSnapshot);
//Assert
var actualSnapshot = IOUtil.LoadObject<Snapshot>(_snapshotRequestFilePath);
Assert.NotNull(actualSnapshot);
Assert.Equal(expectedSnapshot.ImageName, actualSnapshot!.ImageName);
_ec.Verify(ec => ec.Write(null, $"Request written to: {_snapshotRequestFilePath}"), Times.Once);
_ec.Verify(ec => ec.Write(null, "This request will be processed after the job completes. You will not receive any feedback on the snapshot process within the workflow logs of this job."), Times.Once);
_ec.Verify(ec => ec.Write(null, "If the snapshot process is successful, you should see a new image with the requested name in the list of available custom images when creating a new GitHub-hosted Runner."), Times.Once);
_ec.VerifyNoOtherCalls();
}
}
private void Setup(IHostContext hostContext, bool shouldSnapshotDirectoryAlreadyExist)
{
_ec = new Mock<IExecutionContext>();
_snapshotOperationProvider = new SnapshotOperationProvider();
_snapshotOperationProvider.Initialize(hostContext);
_snapshotRequestFilePath = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Root), ".snapshot", "request.json");
_snapshotRequestDirectoryPath = Path.GetDirectoryName(_snapshotRequestFilePath);
if (_snapshotRequestDirectoryPath != null)
{
// Clean up any existing the snapshot directory and its contents before starting the test.
if (Directory.Exists(_snapshotRequestDirectoryPath))
{
Directory.Delete(_snapshotRequestDirectoryPath, true);
}
if (shouldSnapshotDirectoryAlreadyExist)
{
// Create a fresh snapshot directory if it's required for the test.
Directory.CreateDirectory(_snapshotRequestDirectoryPath);
}
}
}
private TestHostContext CreateTestHostContext([CallerMemberName] string testName = "")
{
var testHostContext = new TestHostContext(this, testName);
_ec = new Mock<IExecutionContext>();
_ec.Object.Initialize(testHostContext);
return testHostContext;
}
}

View File

@@ -67,7 +67,7 @@ namespace GitHub.Runner.Common.Tests.Worker
new Pipelines.ContextData.DictionaryContextData() new Pipelines.ContextData.DictionaryContextData()
}, },
}; };
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null, null);
return jobRequest; return jobRequest;
} }

View File

@@ -17,7 +17,7 @@ LAYOUT_DIR="$SCRIPT_DIR/../_layout"
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x" DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
PACKAGE_DIR="$SCRIPT_DIR/../_package" PACKAGE_DIR="$SCRIPT_DIR/../_package"
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk" DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
DOTNETSDK_VERSION="6.0.419" DOTNETSDK_VERSION="6.0.418"
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION" DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
RUNNER_VERSION=$(cat runnerversion) RUNNER_VERSION=$(cat runnerversion)

View File

@@ -1,5 +1,5 @@
{ {
"sdk": { "sdk": {
"version": "6.0.419" "version": "6.0.418"
} }
} }

View File

@@ -1 +1 @@
2.314.0 2.313.0