mirror of
https://github.com/actions/runner.git
synced 2025-12-10 12:36:23 +00:00
Merge branch 'main' into revert-2918-revert-2844-takost/update-internal-node
This commit is contained in:
@@ -1,33 +1,20 @@
|
||||
## What's Changed
|
||||
* fix summaries for actions results by @SrRyan in https://github.com/actions/runner/pull/3174
|
||||
* Bump runner version to match the latest patch release by @TingluoHuang in https://github.com/actions/runner/pull/3175
|
||||
* don't crash listener on getting job exceptions for run-service by @yaananth in https://github.com/actions/runner/pull/3177
|
||||
* Remove -f flag in wait when manually trap signal by @nikola-jokic in https://github.com/actions/runner/pull/3182
|
||||
* consume new pipelines service url in handlers by @patrickcarnahan in https://github.com/actions/runner/pull/3185
|
||||
* Add ability to enforce actions to run on node20 by @takost in https://github.com/actions/runner/pull/3192
|
||||
* Bump hook version to 0.6.0 by @nikola-jokic in https://github.com/actions/runner/pull/3203
|
||||
* Update dotnet sdk to latest version @6.0.420 by @github-actions in https://github.com/actions/runner/pull/3211
|
||||
* Bump docker version and docker buildx version by @nikola-jokic in https://github.com/actions/runner/pull/3208
|
||||
* Handle new non-retryable exception type by @thyeggman in https://github.com/actions/runner/pull/3191
|
||||
* Always Delete Actions Service Session by @luketomlinson in https://github.com/actions/runner/pull/3214
|
||||
|
||||
## New Contributors
|
||||
* @SrRyan made their first contribution in https://github.com/actions/runner/pull/3174
|
||||
* @patrickcarnahan made their first contribution in https://github.com/actions/runner/pull/3185
|
||||
- Preserve dates when deserializing job message from Run Service by @ericsciple in https://github.com/actions/runner/pull/3269
|
||||
|
||||
**Full Changelog**: https://github.com/actions/runner/compare/v2.314.1...v2.315.0
|
||||
|
||||
**Full Changelog**: https://github.com/actions/runner/compare/v2.313.0...v2.314.0
|
||||
**Full Changelog**: https://github.com/actions/runner/compare/v2.316.0...v2.316.1
|
||||
|
||||
_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.
|
||||
See https://docs.github.com/en/enterprise-cloud@latest/actions/hosting-your-own-runners/adding-self-hosted-runners_
|
||||
|
||||
## Windows x64
|
||||
|
||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||
|
||||
The following snipped needs to be run on `powershell`:
|
||||
``` powershell
|
||||
|
||||
```powershell
|
||||
# Create a folder under the drive root
|
||||
mkdir \actions-runner ; cd \actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -38,12 +25,14 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
||||
```
|
||||
|
||||
## [Pre-release] Windows arm64
|
||||
|
||||
**Warning:** Windows arm64 runners are currently in preview status and use [unofficial versions of nodejs](https://unofficial-builds.nodejs.org/). They are not intended for production workflows.
|
||||
|
||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||
|
||||
The following snipped needs to be run on `powershell`:
|
||||
``` powershell
|
||||
|
||||
```powershell
|
||||
# Create a folder under the drive root
|
||||
mkdir \actions-runner ; cd \actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -55,7 +44,7 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
||||
|
||||
## OSX x64
|
||||
|
||||
``` bash
|
||||
```bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -66,7 +55,7 @@ tar xzf ./actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz
|
||||
|
||||
## OSX arm64 (Apple silicon)
|
||||
|
||||
``` bash
|
||||
```bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -77,7 +66,7 @@ tar xzf ./actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz
|
||||
|
||||
## Linux x64
|
||||
|
||||
``` bash
|
||||
```bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -88,7 +77,7 @@ tar xzf ./actions-runner-linux-x64-<RUNNER_VERSION>.tar.gz
|
||||
|
||||
## Linux arm64
|
||||
|
||||
``` bash
|
||||
```bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -99,7 +88,7 @@ tar xzf ./actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz
|
||||
|
||||
## Linux arm
|
||||
|
||||
``` bash
|
||||
```bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
@@ -109,6 +98,7 @@ tar xzf ./actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz
|
||||
```
|
||||
|
||||
## Using your self hosted runner
|
||||
|
||||
For additional details about configuring, running, or shutting down the runner please check out our [product docs.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/adding-self-hosted-runners)
|
||||
|
||||
## SHA-256 Checksums
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace GitHub.Runner.Common
|
||||
{
|
||||
private bool _hasConnection;
|
||||
private VssConnection _connection;
|
||||
private TaskAgentHttpClient _taskAgentClient;
|
||||
private ActionsRunServerHttpClient _actionsRunServerClient;
|
||||
|
||||
public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials)
|
||||
{
|
||||
_connection = await EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||
_taskAgentClient = _connection.GetClient<TaskAgentHttpClient>();
|
||||
_actionsRunServerClient = _connection.GetClient<ActionsRunServerHttpClient>();
|
||||
_hasConnection = true;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace GitHub.Runner.Common
|
||||
CheckConnection();
|
||||
var jobMessage = RetryRequest<AgentJobRequestMessage>(async () =>
|
||||
{
|
||||
return await _taskAgentClient.GetJobMessageAsync(id, cancellationToken);
|
||||
return await _actionsRunServerClient.GetJobMessageAsync(id, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
return jobMessage;
|
||||
|
||||
@@ -1155,18 +1155,13 @@ namespace GitHub.Runner.Listener
|
||||
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");
|
||||
jobRecord.Result = TaskResult.Failed;
|
||||
// mark the job as completed so service will pickup the result
|
||||
jobRecord.State = TimelineRecordState.Completed;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -459,6 +459,34 @@ namespace GitHub.Runner.Sdk
|
||||
File.WriteAllText(path, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces invalid file name characters with '_'
|
||||
/// </summary>
|
||||
public static string ReplaceInvalidFileNameChars(string fileName)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
|
||||
var current = 0; // Current index
|
||||
while (current < fileName?.Length)
|
||||
{
|
||||
var next = fileName.IndexOfAny(invalidChars, current);
|
||||
if (next >= 0)
|
||||
{
|
||||
result.Append(fileName.Substring(current, next - current));
|
||||
result.Append('_');
|
||||
current = next + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Append(fileName.Substring(current));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively enumerates a directory without following directory reparse points.
|
||||
/// </summary>
|
||||
|
||||
@@ -483,10 +483,6 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
// Load stored Ids for later load actions
|
||||
compositeAction.Steps[i].Id = _cachedEmbeddedStepIds[action.Id][i];
|
||||
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && compositeAction.Steps[i].Reference.Type != Pipelines.ActionSourceType.Script)
|
||||
{
|
||||
throw new Exception("`uses:` keyword is not currently supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1022,13 +1018,6 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var step in compositeAction.Steps)
|
||||
{
|
||||
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && step.Reference.Type != Pipelines.ActionSourceType.Script)
|
||||
{
|
||||
throw new Exception("`uses:` keyword is not currently supported.");
|
||||
}
|
||||
}
|
||||
return setupInfo;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -91,13 +91,13 @@ namespace GitHub.Runner.Worker
|
||||
string phaseName = executionContext.Global.Variables.System_PhaseDisplayName ?? "UnknownPhaseName";
|
||||
|
||||
// zip the files
|
||||
string diagnosticsZipFileName = $"{buildName}-{phaseName}.zip";
|
||||
string diagnosticsZipFileName = $"{buildName}-{IOUtil.ReplaceInvalidFileNameChars(phaseName)}.zip";
|
||||
string diagnosticsZipFilePath = Path.Combine(supportRootFolder, diagnosticsZipFileName);
|
||||
ZipFile.CreateFromDirectory(supportFilesFolder, diagnosticsZipFilePath);
|
||||
|
||||
// upload the json metadata file
|
||||
executionContext.Debug("Uploading diagnostic metadata file.");
|
||||
string metadataFileName = $"diagnostics-{buildName}-{phaseName}.json";
|
||||
string metadataFileName = $"diagnostics-{buildName}-{IOUtil.ReplaceInvalidFileNameChars(phaseName)}.json";
|
||||
string metadataFilePath = Path.Combine(supportFilesFolder, metadataFileName);
|
||||
string phaseResult = GetTaskResultAsString(executionContext.Result);
|
||||
|
||||
|
||||
95
src/Sdk/DTWebApi/WebApi/ActionsRunServerHttpClient.cs
Normal file
95
src/Sdk/DTWebApi/WebApi/ActionsRunServerHttpClient.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.Common.Diagnostics;
|
||||
using GitHub.Services.WebApi;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GitHub.DistributedTask.WebApi
|
||||
{
|
||||
[ResourceArea(TaskResourceIds.AreaId)]
|
||||
public class ActionsRunServerHttpClient : TaskAgentHttpClient
|
||||
{
|
||||
private static readonly JsonSerializerSettings s_serializerSettings;
|
||||
|
||||
static ActionsRunServerHttpClient()
|
||||
{
|
||||
s_serializerSettings = new VssJsonMediaTypeFormatter().SerializerSettings;
|
||||
s_serializerSettings.DateParseHandling = DateParseHandling.None;
|
||||
s_serializerSettings.FloatParseHandling = FloatParseHandling.Double;
|
||||
}
|
||||
|
||||
public ActionsRunServerHttpClient(
|
||||
Uri baseUrl,
|
||||
VssCredentials credentials)
|
||||
: base(baseUrl, credentials)
|
||||
{
|
||||
}
|
||||
|
||||
public ActionsRunServerHttpClient(
|
||||
Uri baseUrl,
|
||||
VssCredentials credentials,
|
||||
VssHttpRequestSettings settings)
|
||||
: base(baseUrl, credentials, settings)
|
||||
{
|
||||
}
|
||||
|
||||
public ActionsRunServerHttpClient(
|
||||
Uri baseUrl,
|
||||
VssCredentials credentials,
|
||||
params DelegatingHandler[] handlers)
|
||||
: base(baseUrl, credentials, handlers)
|
||||
{
|
||||
}
|
||||
|
||||
public ActionsRunServerHttpClient(
|
||||
Uri baseUrl,
|
||||
VssCredentials credentials,
|
||||
VssHttpRequestSettings settings,
|
||||
params DelegatingHandler[] handlers)
|
||||
: base(baseUrl, credentials, settings, handlers)
|
||||
{
|
||||
}
|
||||
|
||||
public ActionsRunServerHttpClient(
|
||||
Uri baseUrl,
|
||||
HttpMessageHandler pipeline,
|
||||
Boolean disposeHandler)
|
||||
: base(baseUrl, pipeline, disposeHandler)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<Pipelines.AgentJobRequestMessage> GetJobMessageAsync(
|
||||
string messageId,
|
||||
object userState = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
HttpMethod httpMethod = new HttpMethod("GET");
|
||||
Guid locationId = new Guid("25adab70-1379-4186-be8e-b643061ebe3a");
|
||||
object routeValues = new { messageId = messageId };
|
||||
|
||||
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
||||
httpMethod,
|
||||
locationId,
|
||||
routeValues: routeValues,
|
||||
version: new ApiResourceVersion(6.0, 1),
|
||||
userState: userState,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
protected override async Task<T> ReadJsonContentAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,24 +141,6 @@ namespace GitHub.DistributedTask.WebApi
|
||||
return ReplaceAgentAsync(poolId, agent.Id, agent, userState, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Pipelines.AgentJobRequestMessage> GetJobMessageAsync(
|
||||
string messageId,
|
||||
object userState = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
HttpMethod httpMethod = new HttpMethod("GET");
|
||||
Guid locationId = new Guid("25adab70-1379-4186-be8e-b643061ebe3a");
|
||||
object routeValues = new { messageId = messageId };
|
||||
|
||||
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
||||
httpMethod,
|
||||
locationId,
|
||||
routeValues: routeValues,
|
||||
version: new ApiResourceVersion(6.0, 1),
|
||||
userState: userState,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
protected Task<T> SendAsync<T>(
|
||||
HttpMethod method,
|
||||
Guid locationId,
|
||||
|
||||
@@ -9,6 +9,7 @@ using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.OAuth;
|
||||
using GitHub.Services.WebApi;
|
||||
using Newtonsoft.Json;
|
||||
using Sdk.RSWebApi.Contracts;
|
||||
using Sdk.WebApi.WebApi;
|
||||
|
||||
@@ -16,6 +17,15 @@ namespace GitHub.Actions.RunService.WebApi
|
||||
{
|
||||
public class RunServiceHttpClient : RawHttpClientBase
|
||||
{
|
||||
private static readonly JsonSerializerSettings s_serializerSettings;
|
||||
|
||||
static RunServiceHttpClient()
|
||||
{
|
||||
s_serializerSettings = new VssJsonMediaTypeFormatter().SerializerSettings;
|
||||
s_serializerSettings.DateParseHandling = DateParseHandling.None;
|
||||
s_serializerSettings.FloatParseHandling = FloatParseHandling.Double;
|
||||
}
|
||||
|
||||
public RunServiceHttpClient(
|
||||
Uri baseUrl,
|
||||
VssOAuthCredential credentials)
|
||||
@@ -174,5 +184,11 @@ namespace GitHub.Actions.RunService.WebApi
|
||||
throw new Exception($"Failed to renew job: {result.Error}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<T> ReadJsonContentAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,6 +960,33 @@ namespace GitHub.Runner.Common.Tests.Util
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Common")]
|
||||
public void ReplaceInvalidFileNameChars()
|
||||
{
|
||||
Assert.Equal(string.Empty, IOUtil.ReplaceInvalidFileNameChars(null));
|
||||
Assert.Equal(string.Empty, IOUtil.ReplaceInvalidFileNameChars(string.Empty));
|
||||
Assert.Equal("hello.txt", IOUtil.ReplaceInvalidFileNameChars("hello.txt"));
|
||||
#if OS_WINDOWS
|
||||
// Refer https://github.com/dotnet/runtime/blob/ce84f1d8a3f12711bad678a33efbc37b461f684f/src/libraries/System.Private.CoreLib/src/System/IO/Path.Windows.cs#L15
|
||||
Assert.Equal(
|
||||
"1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_ 10_ 11_ 12_ 13_ 14_ 15_ 16_ 17_ 18_ 19_ 20_ 21_ 22_ 23_ 24_ 25_ 26_ 27_ 28_ 29_ 30_ 31_ 32_ 33_ 34_ 35_ 36_ 37_ 38_ 39_ 40_ 41_",
|
||||
IOUtil.ReplaceInvalidFileNameChars($"1\" 2< 3> 4| 5\0 6{(char)1} 7{(char)2} 8{(char)3} 9{(char)4} 10{(char)5} 11{(char)6} 12{(char)7} 13{(char)8} 14{(char)9} 15{(char)10} 16{(char)11} 17{(char)12} 18{(char)13} 19{(char)14} 20{(char)15} 21{(char)16} 22{(char)17} 23{(char)18} 24{(char)19} 25{(char)20} 26{(char)21} 27{(char)22} 28{(char)23} 29{(char)24} 30{(char)25} 31{(char)26} 32{(char)27} 33{(char)28} 34{(char)29} 35{(char)30} 36{(char)31} 37: 38* 39? 40\\ 41/"));
|
||||
#else
|
||||
// Refer https://github.com/dotnet/runtime/blob/ce84f1d8a3f12711bad678a33efbc37b461f684f/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs#L12
|
||||
Assert.Equal("1_ 2_", IOUtil.ReplaceInvalidFileNameChars("1\0 2/"));
|
||||
#endif
|
||||
Assert.Equal("_leading", IOUtil.ReplaceInvalidFileNameChars("/leading"));
|
||||
Assert.Equal("__consecutive leading", IOUtil.ReplaceInvalidFileNameChars("//consecutive leading"));
|
||||
Assert.Equal("trailing_", IOUtil.ReplaceInvalidFileNameChars("trailing/"));
|
||||
Assert.Equal("consecutive trailing__", IOUtil.ReplaceInvalidFileNameChars("consecutive trailing//"));
|
||||
Assert.Equal("middle_middle", IOUtil.ReplaceInvalidFileNameChars("middle/middle"));
|
||||
Assert.Equal("consecutive middle__consecutive middle", IOUtil.ReplaceInvalidFileNameChars("consecutive middle//consecutive middle"));
|
||||
Assert.Equal("_leading_middle_trailing_", IOUtil.ReplaceInvalidFileNameChars("/leading/middle/trailing/"));
|
||||
Assert.Equal("__consecutive leading__consecutive middle__consecutive trailing__", IOUtil.ReplaceInvalidFileNameChars("//consecutive leading//consecutive middle//consecutive trailing//"));
|
||||
}
|
||||
|
||||
private static async Task CreateDirectoryReparsePoint(IHostContext context, string link, string target)
|
||||
{
|
||||
#if OS_WINDOWS
|
||||
|
||||
@@ -2373,10 +2373,6 @@ runs:
|
||||
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
||||
_ec.Setup(x => x.Root).Returns(new GitHub.Runner.Worker.ExecutionContext());
|
||||
var variables = new Dictionary<string, VariableValue>();
|
||||
if (enableComposite)
|
||||
{
|
||||
variables["DistributedTask.EnableCompositeActions"] = "true";
|
||||
}
|
||||
_ec.Object.Global.Variables = new Variables(_hc, variables);
|
||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.315.0
|
||||
2.316.1
|
||||
|
||||
Reference in New Issue
Block a user