Merge branch 'main' into dependabot/npm_and_yarn/src/Misc/expressionFunc/hashFiles/main/lint-staged-16.2.4

This commit is contained in:
Salman Chishti
2025-10-20 12:12:10 +01:00
committed by GitHub
26 changed files with 318 additions and 31 deletions

View File

@@ -7,7 +7,7 @@ NODE_ALPINE_URL=https://github.com/actions/alpine_nodejs/releases/download
# When you update Node versions you must also create a new release of alpine_nodejs at that updated version.
# Follow the instructions here: https://github.com/actions/alpine_nodejs?tab=readme-ov-file#getting-started
NODE20_VERSION="20.19.5"
NODE24_VERSION="24.9.0"
NODE24_VERSION="24.10.0"
get_abs_path() {
# exploits the fact that pwd will print abs path when no args

View File

@@ -170,6 +170,8 @@ namespace GitHub.Runner.Common
public static readonly string AddCheckRunIdToJobContext = "actions_add_check_run_id_to_job_context";
public static readonly string DisplayHelpfulActionsDownloadErrors = "actions_display_helpful_actions_download_errors";
public static readonly string ContainerActionRunnerTemp = "actions_container_action_runner_temp";
public static readonly string SnapshotPreflightHostedRunnerCheck = "actions_snapshot_preflight_hosted_runner_check";
public static readonly string SnapshotPreflightImageGenPoolCheck = "actions_snapshot_preflight_image_gen_pool_check";
}
// Node version migration related constants

View File

@@ -30,6 +30,7 @@ namespace GitHub.Runner.Common
string environmentUrl,
IList<Telemetry> telemetry,
string billingOwnerId,
string infrastructureFailureCategory,
CancellationToken token);
Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken token);
@@ -80,11 +81,12 @@ namespace GitHub.Runner.Common
string environmentUrl,
IList<Telemetry> telemetry,
string billingOwnerId,
string infrastructureFailureCategory,
CancellationToken cancellationToken)
{
CheckConnection();
return RetryRequest(
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, jobAnnotations, environmentUrl, telemetry, billingOwnerId, cancellationToken), cancellationToken,
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, jobAnnotations, environmentUrl, telemetry, billingOwnerId, infrastructureFailureCategory, cancellationToken), cancellationToken,
shouldRetry: ex =>
ex is not VssUnauthorizedException && // HTTP status 401
ex is not TaskOrchestrationJobNotFoundException); // HTTP status 404

View File

@@ -284,6 +284,7 @@ namespace GitHub.Runner.Listener.Configuration
{
var runner = await _dotcomServer.ReplaceRunnerAsync(runnerSettings.PoolId, agent, runnerSettings.GitHubUrl, registerToken, publicKeyXML);
runnerSettings.ServerUrlV2 = runner.RunnerAuthorization.ServerUrl;
runnerSettings.UseV2Flow = true; // if we are using runner admin, we also need to hit broker
agent.Id = runner.Id;
agent.Authorization = new TaskAgentAuthorization()
@@ -291,6 +292,13 @@ namespace GitHub.Runner.Listener.Configuration
AuthorizationUrl = runner.RunnerAuthorization.AuthorizationUrl,
ClientId = new Guid(runner.RunnerAuthorization.ClientId)
};
if (!string.IsNullOrEmpty(runner.RunnerAuthorization.LegacyAuthorizationUrl?.AbsoluteUri))
{
agent.Authorization.AuthorizationUrl = runner.RunnerAuthorization.LegacyAuthorizationUrl;
agent.Properties["EnableAuthMigrationByDefault"] = true;
agent.Properties["AuthorizationUrlV2"] = runner.RunnerAuthorization.AuthorizationUrl.AbsoluteUri;
}
}
else
{
@@ -342,6 +350,13 @@ namespace GitHub.Runner.Listener.Configuration
AuthorizationUrl = runner.RunnerAuthorization.AuthorizationUrl,
ClientId = new Guid(runner.RunnerAuthorization.ClientId)
};
if (!string.IsNullOrEmpty(runner.RunnerAuthorization.LegacyAuthorizationUrl?.AbsoluteUri))
{
agent.Authorization.AuthorizationUrl = runner.RunnerAuthorization.LegacyAuthorizationUrl;
agent.Properties["EnableAuthMigrationByDefault"] = true;
agent.Properties["AuthorizationUrlV2"] = runner.RunnerAuthorization.AuthorizationUrl.AbsoluteUri;
}
}
else
{

View File

@@ -1211,7 +1211,7 @@ namespace GitHub.Runner.Listener
jobAnnotations.Add(annotation.Value);
}
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, telemetry: null, billingOwnerId: message.BillingOwnerId, CancellationToken.None);
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, telemetry: null, billingOwnerId: message.BillingOwnerId, infrastructureFailureCategory: null, CancellationToken.None);
}
catch (Exception ex)
{

View File

@@ -111,7 +111,7 @@ namespace GitHub.Runner.Worker
{
// Log the error and fail the PrepareActionsAsync Initialization.
Trace.Error($"Caught exception from PrepareActionsAsync Initialization: {ex}");
executionContext.InfrastructureError(ex.Message);
executionContext.InfrastructureError(ex.Message, category: "resolve_action");
executionContext.Result = TaskResult.Failed;
throw;
}
@@ -119,7 +119,7 @@ namespace GitHub.Runner.Worker
{
// Log the error and fail the PrepareActionsAsync Initialization.
Trace.Error($"Caught exception from PrepareActionsAsync Initialization: {ex}");
executionContext.InfrastructureError(ex.Message);
executionContext.InfrastructureError(ex.Message, category: "invalid_action_download");
executionContext.Result = TaskResult.Failed;
throw;
}
@@ -777,15 +777,15 @@ namespace GitHub.Runner.Worker
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
Directory.CreateDirectory(destDirectory);
if (downloadInfo.PackageDetails != null)
if (downloadInfo.PackageDetails != null)
{
executionContext.Output($"##[group]Download immutable action package '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}'");
executionContext.Output($"Version: {downloadInfo.PackageDetails.Version}");
executionContext.Output($"Digest: {downloadInfo.PackageDetails.ManifestDigest}");
executionContext.Output($"Source commit SHA: {downloadInfo.ResolvedSha}");
executionContext.Output("##[endgroup]");
}
else
}
else
{
executionContext.Output($"Download action repository '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}' (SHA:{downloadInfo.ResolvedSha})");
}

View File

@@ -522,6 +522,10 @@ namespace GitHub.Runner.Worker
if (annotation != null)
{
stepResult.Annotations.Add(annotation.Value);
if (annotation.Value.IsInfrastructureIssue && string.IsNullOrEmpty(Global.InfrastructureFailureCategory))
{
Global.InfrastructureFailureCategory = issue.Category;
}
}
});
@@ -1335,9 +1339,9 @@ namespace GitHub.Runner.Worker
}
// Do not add a format string overload. See comment on ExecutionContext.Write().
public static void InfrastructureError(this IExecutionContext context, string message)
public static void InfrastructureError(this IExecutionContext context, string message, string category = null)
{
var issue = new Issue() { Type = IssueType.Error, Message = message, IsInfrastructureIssue = true };
var issue = new Issue() { Type = IssueType.Error, Message = message, IsInfrastructureIssue = true, Category = category };
context.AddIssue(issue, ExecutionContextLogOptions.Default);
}

View File

@@ -27,6 +27,7 @@ namespace GitHub.Runner.Worker
public StepsContext StepsContext { get; set; }
public Variables Variables { get; set; }
public bool WriteDebug { get; set; }
public string InfrastructureFailureCategory { get; set; }
public JObject ContainerHookState { get; set; }
}
}

View File

@@ -400,6 +400,10 @@ namespace GitHub.Runner.Worker
if (snapshotRequest != null)
{
var snapshotOperationProvider = HostContext.GetService<ISnapshotOperationProvider>();
// Check that that runner is capable of taking a snapshot
snapshotOperationProvider.RunSnapshotPreflightChecks(context);
// Add postjob step to write snapshot file
jobContext.RegisterPostJobStep(new JobExtensionRunner(
runAsync: (executionContext, _) => snapshotOperationProvider.CreateSnapshotRequestAsync(executionContext, snapshotRequest),
condition: snapshotRequest.Condition,

View File

@@ -321,7 +321,7 @@ namespace GitHub.Runner.Worker
{
try
{
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, jobContext.Global.JobAnnotations, environmentUrl, telemetry, billingOwnerId: message.BillingOwnerId, default);
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, jobContext.Global.JobAnnotations, environmentUrl, telemetry, billingOwnerId: message.BillingOwnerId, infrastructureFailureCategory: jobContext.Global.InfrastructureFailureCategory, default);
return result;
}
catch (VssUnauthorizedException ex)

View File

@@ -1,15 +1,19 @@
#nullable enable
using System;
using System.IO;
using System.Threading.Tasks;
using GitHub.DistributedTask.Pipelines;
using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Common;
using GitHub.Runner.Sdk;
using GitHub.Runner.Worker.Handlers;
namespace GitHub.Runner.Worker;
[ServiceLocator(Default = typeof(SnapshotOperationProvider))]
public interface ISnapshotOperationProvider : IRunnerService
{
Task CreateSnapshotRequestAsync(IExecutionContext executionContext, Snapshot snapshotRequest);
void RunSnapshotPreflightChecks(IExecutionContext jobContext);
}
public class SnapshotOperationProvider : RunnerService, ISnapshotOperationProvider
@@ -24,9 +28,32 @@ public class SnapshotOperationProvider : RunnerService, ISnapshotOperationProvid
}
IOUtil.SaveObject(snapshotRequest, snapshotRequestFilePath);
executionContext.Output($"Image Name: {snapshotRequest.ImageName} Version: {snapshotRequest.Version}");
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;
}
public void RunSnapshotPreflightChecks(IExecutionContext context)
{
var shouldCheckRunnerEnvironment = context.Global.Variables.GetBoolean(Constants.Runner.Features.SnapshotPreflightHostedRunnerCheck) ?? false;
if (shouldCheckRunnerEnvironment &&
context.Global.Variables.TryGetValue(WellKnownDistributedTaskVariables.RunnerEnvironment, out var runnerEnvironment) &&
!string.IsNullOrEmpty(runnerEnvironment))
{
context.Debug($"Snapshot: RUNNER_ENVIRONMENT={runnerEnvironment}");
if (!string.Equals(runnerEnvironment, "github-hosted", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Snapshot workflows must be run on a GitHub Hosted Runner");
}
}
var imageGenEnabled = StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED"));
context.Debug($"Snapshot: GITHUB_ACTIONS_IMAGE_GEN_ENABLED={imageGenEnabled}");
var shouldCheckImageGenPool = context.Global.Variables.GetBoolean(Constants.Runner.Features.SnapshotPreflightImageGenPoolCheck) ?? false;
if (shouldCheckImageGenPool && !imageGenEnabled)
{
throw new ArgumentException("Snapshot workflows must be run a hosted runner with Image Generation enabled");
}
}
}

View File

@@ -18,6 +18,16 @@ namespace GitHub.DistributedTask.WebApi
internal set;
}
/// <summary>
/// The url to refresh tokens with legacy service
/// </summary>
[JsonProperty("legacy_authorization_url")]
public Uri LegacyAuthorizationUrl
{
get;
internal set;
}
/// <summary>
/// The url to connect to poll for messages
/// </summary>

View File

@@ -35,5 +35,8 @@ namespace GitHub.Actions.RunService.WebApi
[DataMember(Name = "billingOwnerId", EmitDefaultValue = false)]
public string BillingOwnerId { get; set; }
[DataMember(Name = "infrastructureFailureCategory", EmitDefaultValue = false)]
public string InfrastructureFailureCategory { get; set; }
}
}

View File

@@ -42,6 +42,7 @@ namespace Sdk.RSWebApi.Contracts
StartColumn = columnNumber,
EndColumn = endColumnNumber,
StepNumber = stepNumber,
IsInfrastructureIssue = issue.IsInfrastructureIssue ?? false
};
}

View File

@@ -131,6 +131,7 @@ namespace GitHub.Actions.RunService.WebApi
string environmentUrl,
IList<Telemetry> telemetry,
string billingOwnerId,
string infrastructureFailureCategory,
CancellationToken cancellationToken = default)
{
HttpMethod httpMethod = new HttpMethod("POST");
@@ -145,6 +146,7 @@ namespace GitHub.Actions.RunService.WebApi
EnvironmentUrl = environmentUrl,
Telemetry = telemetry,
BillingOwnerId = billingOwnerId,
InfrastructureFailureCategory = infrastructureFailureCategory
};
requestUri = new Uri(requestUri, "completejob");

View File

@@ -567,5 +567,193 @@ namespace GitHub.Runner.Common.Tests.Worker
}
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SnapshotPreflightChecks_HostedRunnerCheck_Enabled_GitHubHosted_Success()
{
using (TestHostContext hc = CreateTestContext())
{
_jobEc.Global.Variables.Set(WellKnownDistributedTaskVariables.RunnerEnvironment, "github-hosted");
hc.SetSingleton<ISnapshotOperationProvider>(new SnapshotOperationProvider());
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightHostedRunnerCheck, "true");
var jobExtension = new JobExtension();
jobExtension.Initialize(hc);
var snapshot = new Pipelines.Snapshot("TestImageNameForPreflightCheck");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
_message.Snapshot = imageNameValueStringToken;
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>(), It.IsAny<Guid>()))
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>(), new Dictionary<Guid, IActionRunner>())));
await jobExtension.InitializeJob(_jobEc, _message);
var postJobSteps = _jobEc.PostJobSteps;
Assert.Equal(1, postJobSteps.Count);
}
Environment.SetEnvironmentVariable("RUNNER_ENVIRONMENT", null);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SnapshotPreflightChecks_HostedRunnerCheck_Enabled_SelfHosted_ThrowsException()
{
using (TestHostContext hc = CreateTestContext())
{
_jobEc.Global.Variables.Set(WellKnownDistributedTaskVariables.RunnerEnvironment, "self-hosted");
hc.SetSingleton<ISnapshotOperationProvider>(new SnapshotOperationProvider());
var jobExtension = new JobExtension();
jobExtension.Initialize(hc);
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightHostedRunnerCheck, "true");
var snapshot = new Pipelines.Snapshot("TestImageNameForPreflightCheck");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
_message.Snapshot = imageNameValueStringToken;
_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>())));
var exception = await Assert.ThrowsAsync<ArgumentException>(() => jobExtension.InitializeJob(_jobEc, _message));
Assert.Contains("Snapshot workflows must be run on a GitHub Hosted Runner", exception.Message);
}
Environment.SetEnvironmentVariable("RUNNER_ENVIRONMENT", null);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SnapshotPreflightChecks_ImageGenPoolCheck_Enabled_ImageGenEnabled_Success()
{
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", "true");
using (TestHostContext hc = CreateTestContext())
{
hc.SetSingleton<ISnapshotOperationProvider>(new SnapshotOperationProvider());
var jobExtension = new JobExtension();
jobExtension.Initialize(hc);
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightImageGenPoolCheck, "true");
var snapshot = new Pipelines.Snapshot("TestImageNameForPreflightCheck");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
_message.Snapshot = imageNameValueStringToken;
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>(), It.IsAny<Guid>()))
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>(), new Dictionary<Guid, IActionRunner>())));
await jobExtension.InitializeJob(_jobEc, _message);
var postJobSteps = _jobEc.PostJobSteps;
Assert.Equal(1, postJobSteps.Count);
}
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", null);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SnapshotPreflightChecks_ImageGenPoolCheck_Enabled_ImageGen_False_ThrowsException()
{
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", "false");
using (TestHostContext hc = CreateTestContext())
{
hc.SetSingleton<ISnapshotOperationProvider>(new SnapshotOperationProvider());
_jobEc.SetRunnerContext("environment", "github-hosted");
var jobExtension = new JobExtension();
jobExtension.Initialize(hc);
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightImageGenPoolCheck, "true");
var snapshot = new Pipelines.Snapshot("TestImageNameForPreflightCheck");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
_message.Snapshot = imageNameValueStringToken;
_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>())));
var exception = await Assert.ThrowsAsync<ArgumentException>(() => jobExtension.InitializeJob(_jobEc, _message));
Assert.Contains("Snapshot workflows must be run a hosted runner with Image Generation enabled", exception.Message);
}
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", null);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SnapshotPreflightChecks_ImageGenPoolCheck_Enabled_ImageGen_Missing_ThrowsException()
{
using (TestHostContext hc = CreateTestContext())
{
hc.SetSingleton<ISnapshotOperationProvider>(new SnapshotOperationProvider());
var jobExtension = new JobExtension();
jobExtension.Initialize(hc);
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightImageGenPoolCheck, "true");
var snapshot = new Pipelines.Snapshot("TestImageNameForPreflightCheck");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
_message.Snapshot = imageNameValueStringToken;
_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>())));
var exception = await Assert.ThrowsAsync<ArgumentException>(() => jobExtension.InitializeJob(_jobEc, _message));
Assert.Contains("Snapshot workflows must be run a hosted runner with Image Generation enabled", exception.Message);
}
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", null);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SnapshotPreflightChecks_BothChecks_Enabled_AllConditionsMet_Success()
{
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", "true");
using (TestHostContext hc = CreateTestContext())
{
hc.SetSingleton<ISnapshotOperationProvider>(new SnapshotOperationProvider());
var jobExtension = new JobExtension();
jobExtension.Initialize(hc);
// Enable both preflight checks
_jobEc.Global.Variables.Set(WellKnownDistributedTaskVariables.RunnerEnvironment, "github-hosted");
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightHostedRunnerCheck, "true");
_jobEc.Global.Variables.Set(Constants.Runner.Features.SnapshotPreflightImageGenPoolCheck, "true");
var snapshot = new Pipelines.Snapshot("TestImageNameForPreflightCheck");
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
_message.Snapshot = imageNameValueStringToken;
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>(), It.IsAny<Guid>()))
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>(), new Dictionary<Guid, IActionRunner>())));
await jobExtension.InitializeJob(_jobEc, _message);
var postJobSteps = _jobEc.PostJobSteps;
Assert.Equal(1, postJobSteps.Count);
}
Environment.SetEnvironmentVariable("RUNNER_ENVIRONMENT", null);
Environment.SetEnvironmentVariable("GITHUB_ACTIONS_IMAGE_GEN_ENABLED", null);
}
}
}

View File

@@ -38,6 +38,7 @@ public class SnapshotOperationProviderL0
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, $"Image Name: {expectedSnapshot.ImageName} Version: {expectedSnapshot.Version}"), 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();

View File

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

View File

@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.413"
"version": "8.0.415"
}
}

View File

@@ -1 +1 @@
2.328.0
2.329.0