mirror of
https://github.com/actions/runner.git
synced 2025-12-12 15:13:30 +00:00
Compare commits
1 Commits
v2.291.0
...
users/eric
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7731bf9ad5 |
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -101,11 +101,11 @@ jobs:
|
|||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
#- name: L0
|
- name: L0
|
||||||
# run: |
|
run: |
|
||||||
# ${{ matrix.devScript }} test
|
${{ matrix.devScript }} test
|
||||||
# working-directory: src
|
working-directory: src
|
||||||
# if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
||||||
|
|
||||||
# Create runner package tar.gz/zip
|
# Create runner package tar.gz/zip
|
||||||
- name: Package Release
|
- name: Package Release
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
## Features
|
## Features
|
||||||
- Relaxed naming requirements for dockerfiles (e.g. `Dockerfile.test` can now be built) (#1738)
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Fixed a bug where windows path separators were used in generated folders (#1617)
|
- Fixed an issue where websockets failed to successfully close when posting log lines (#1790)
|
||||||
- Fixed an issue where runner's invoked via `run.sh` or `run.cmd` did not properly restart after update (#1812). This fix applies to all future updates after installing this version
|
|
||||||
|
|
||||||
## Misc
|
|
||||||
- Relaxed Actions Summary size limit to 1MiB (#1839)
|
|
||||||
|
|
||||||
## Windows x64
|
## 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.
|
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.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.291.0
|
<Update to ./src/runnerversion when creating release>
|
||||||
|
|||||||
@@ -47,6 +47,11 @@
|
|||||||
<DefineConstants>$(DefineConstants);DEBUG</DefineConstants>
|
<DefineConstants>$(DefineConstants);DEBUG</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Set USE_BROKER vars -->
|
||||||
|
<PropertyGroup Condition="'$(USE_BROKER)' == 'true'">
|
||||||
|
<DefineConstants>$(DefineConstants);USE_BROKER</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Set Treat tarnings as errors -->
|
<!-- Set Treat tarnings as errors -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
|||||||
38
src/Runner.Common/BrokerServer.cs
Normal file
38
src/Runner.Common/BrokerServer.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common
|
||||||
|
{
|
||||||
|
[ServiceLocator(Default = typeof(BrokerServer))]
|
||||||
|
public interface IBrokerServer : IRunnerService
|
||||||
|
{
|
||||||
|
Task ConnectAsync(Uri serverUrl);
|
||||||
|
Task<GitHub.DistributedTask.WebApi.TaskAgentMessage> GetMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class BrokerServer : RunnerService, IBrokerServer
|
||||||
|
{
|
||||||
|
private HttpClient _httpClient;
|
||||||
|
|
||||||
|
public async Task ConnectAsync(Uri serverUrl)
|
||||||
|
{
|
||||||
|
_httpClient = new HttpClient();
|
||||||
|
_httpClient.BaseAddress = serverUrl;
|
||||||
|
_httpClient.Timeout = TimeSpan.FromSeconds(50);
|
||||||
|
await _httpClient.GetAsync("health");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GitHub.DistributedTask.WebApi.TaskAgentMessage> GetMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await _httpClient.GetAsync("message");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,7 +86,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static class CommandLine
|
public static class CommandLine
|
||||||
{
|
{
|
||||||
//if you are adding a new arg, please make sure you update the
|
//if you are adding a new arg, please make sure you update the
|
||||||
//validOptions dictionary as well present in the CommandSettings.cs
|
//validArgs array as well present in the CommandSettings.cs
|
||||||
public static class Args
|
public static class Args
|
||||||
{
|
{
|
||||||
public static readonly string Auth = "auth";
|
public static readonly string Auth = "auth";
|
||||||
@@ -121,7 +121,7 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
//if you are adding a new flag, please make sure you update the
|
//if you are adding a new flag, please make sure you update the
|
||||||
//validOptions dictionary as well present in the CommandSettings.cs
|
//validFlags array as well present in the CommandSettings.cs
|
||||||
public static class Flags
|
public static class Flags
|
||||||
{
|
{
|
||||||
public static readonly string Check = "check";
|
public static readonly string Check = "check";
|
||||||
@@ -150,7 +150,6 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
||||||
public static readonly string Node12Warning = "DistributedTask.AddWarningToNode12Action";
|
public static readonly string Node12Warning = "DistributedTask.AddWarningToNode12Action";
|
||||||
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||||
|
|||||||
@@ -17,57 +17,43 @@ namespace GitHub.Runner.Listener
|
|||||||
private readonly IPromptManager _promptManager;
|
private readonly IPromptManager _promptManager;
|
||||||
private readonly Tracing _trace;
|
private readonly Tracing _trace;
|
||||||
|
|
||||||
// Valid flags for all commands
|
private readonly string[] validCommands =
|
||||||
private readonly string[] genericOptions =
|
|
||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Flags.Help,
|
Constants.Runner.CommandLine.Commands.Configure,
|
||||||
Constants.Runner.CommandLine.Flags.Version,
|
Constants.Runner.CommandLine.Commands.Remove,
|
||||||
Constants.Runner.CommandLine.Flags.Commit,
|
Constants.Runner.CommandLine.Commands.Run,
|
||||||
Constants.Runner.CommandLine.Flags.Check
|
Constants.Runner.CommandLine.Commands.Warmup,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Valid flags and args for specific command - key: command, value: array of valid flags and args
|
private readonly string[] validFlags =
|
||||||
private readonly Dictionary<string, string[]> validOptions = new Dictionary<string, string[]>
|
|
||||||
{
|
{
|
||||||
// Valid configure flags and args
|
Constants.Runner.CommandLine.Flags.Check,
|
||||||
[Constants.Runner.CommandLine.Commands.Configure] =
|
Constants.Runner.CommandLine.Flags.Commit,
|
||||||
new string[]
|
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
||||||
{
|
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||||
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
Constants.Runner.CommandLine.Flags.Help,
|
||||||
Constants.Runner.CommandLine.Flags.Ephemeral,
|
Constants.Runner.CommandLine.Flags.Once,
|
||||||
Constants.Runner.CommandLine.Flags.Replace,
|
Constants.Runner.CommandLine.Flags.Replace,
|
||||||
Constants.Runner.CommandLine.Flags.RunAsService,
|
Constants.Runner.CommandLine.Flags.RunAsService,
|
||||||
Constants.Runner.CommandLine.Flags.Unattended,
|
Constants.Runner.CommandLine.Flags.Unattended,
|
||||||
Constants.Runner.CommandLine.Args.Auth,
|
Constants.Runner.CommandLine.Flags.Version
|
||||||
Constants.Runner.CommandLine.Args.Labels,
|
};
|
||||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
|
||||||
Constants.Runner.CommandLine.Args.Name,
|
private readonly string[] validArgs =
|
||||||
Constants.Runner.CommandLine.Args.PAT,
|
{
|
||||||
Constants.Runner.CommandLine.Args.RunnerGroup,
|
Constants.Runner.CommandLine.Args.Auth,
|
||||||
Constants.Runner.CommandLine.Args.Token,
|
Constants.Runner.CommandLine.Args.Labels,
|
||||||
Constants.Runner.CommandLine.Args.Url,
|
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||||
Constants.Runner.CommandLine.Args.UserName,
|
Constants.Runner.CommandLine.Args.Name,
|
||||||
Constants.Runner.CommandLine.Args.WindowsLogonAccount,
|
Constants.Runner.CommandLine.Args.PAT,
|
||||||
Constants.Runner.CommandLine.Args.WindowsLogonPassword,
|
Constants.Runner.CommandLine.Args.RunnerGroup,
|
||||||
Constants.Runner.CommandLine.Args.Work
|
Constants.Runner.CommandLine.Args.StartupType,
|
||||||
},
|
Constants.Runner.CommandLine.Args.Token,
|
||||||
// Valid remove flags and args
|
Constants.Runner.CommandLine.Args.Url,
|
||||||
[Constants.Runner.CommandLine.Commands.Remove] =
|
Constants.Runner.CommandLine.Args.UserName,
|
||||||
new string[]
|
Constants.Runner.CommandLine.Args.WindowsLogonAccount,
|
||||||
{
|
Constants.Runner.CommandLine.Args.WindowsLogonPassword,
|
||||||
Constants.Runner.CommandLine.Args.Token,
|
Constants.Runner.CommandLine.Args.Work
|
||||||
Constants.Runner.CommandLine.Args.PAT
|
|
||||||
},
|
|
||||||
// Valid run flags and args
|
|
||||||
[Constants.Runner.CommandLine.Commands.Run] =
|
|
||||||
new string[]
|
|
||||||
{
|
|
||||||
Constants.Runner.CommandLine.Flags.Once,
|
|
||||||
Constants.Runner.CommandLine.Args.StartupType
|
|
||||||
},
|
|
||||||
// valid warmup flags and args
|
|
||||||
[Constants.Runner.CommandLine.Commands.Warmup] =
|
|
||||||
new string[] { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Commands.
|
// Commands.
|
||||||
@@ -140,48 +126,17 @@ namespace GitHub.Runner.Listener
|
|||||||
List<string> unknowns = new List<string>();
|
List<string> unknowns = new List<string>();
|
||||||
|
|
||||||
// detect unknown commands
|
// detect unknown commands
|
||||||
unknowns.AddRange(_parser.Commands.Where(x => !validOptions.Keys.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
unknowns.AddRange(_parser.Commands.Where(x => !validCommands.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||||
|
|
||||||
if (unknowns.Count == 0)
|
// detect unknown flags
|
||||||
{
|
unknowns.AddRange(_parser.Flags.Where(x => !validFlags.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||||
// detect unknown flags and args for valid commands
|
|
||||||
foreach (var command in _parser.Commands)
|
// detect unknown args
|
||||||
{
|
unknowns.AddRange(_parser.Args.Keys.Where(x => !validArgs.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||||
if (validOptions.TryGetValue(command, out string[] options))
|
|
||||||
{
|
|
||||||
unknowns.AddRange(_parser.Flags.Where(x => !options.Contains(x, StringComparer.OrdinalIgnoreCase) && !genericOptions.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
|
||||||
unknowns.AddRange(_parser.Args.Keys.Where(x => !options.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return unknowns;
|
return unknowns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetCommandName()
|
|
||||||
{
|
|
||||||
string command = string.Empty;
|
|
||||||
|
|
||||||
if (Configure)
|
|
||||||
{
|
|
||||||
command = Constants.Runner.CommandLine.Commands.Configure;
|
|
||||||
}
|
|
||||||
else if (Remove)
|
|
||||||
{
|
|
||||||
command = Constants.Runner.CommandLine.Commands.Remove;
|
|
||||||
}
|
|
||||||
else if (Run)
|
|
||||||
{
|
|
||||||
command = Constants.Runner.CommandLine.Commands.Run;
|
|
||||||
}
|
|
||||||
else if (Warmup)
|
|
||||||
{
|
|
||||||
command = Constants.Runner.CommandLine.Commands.Warmup;
|
|
||||||
}
|
|
||||||
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Interactive flags.
|
// Interactive flags.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return creds;
|
return creds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_BROKER
|
||||||
|
public VssCredentials LoadCredentials()
|
||||||
|
{
|
||||||
|
return new VssCredentials();
|
||||||
|
}
|
||||||
|
#else
|
||||||
public VssCredentials LoadCredentials()
|
public VssCredentials LoadCredentials()
|
||||||
{
|
{
|
||||||
IConfigurationStore store = HostContext.GetService<IConfigurationStore>();
|
IConfigurationStore store = HostContext.GetService<IConfigurationStore>();
|
||||||
@@ -69,6 +75,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
return creds;
|
return creds;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ namespace GitHub.Runner.Listener
|
|||||||
private RunnerSettings _settings;
|
private RunnerSettings _settings;
|
||||||
private ITerminal _term;
|
private ITerminal _term;
|
||||||
private IRunnerServer _runnerServer;
|
private IRunnerServer _runnerServer;
|
||||||
|
private IBrokerServer _brokerServer;
|
||||||
private TaskAgentSession _session;
|
private TaskAgentSession _session;
|
||||||
private TimeSpan _getNextMessageRetryInterval;
|
private TimeSpan _getNextMessageRetryInterval;
|
||||||
private bool _accessTokenRevoked = false;
|
private bool _accessTokenRevoked = false;
|
||||||
@@ -45,8 +46,44 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
_term = HostContext.GetService<ITerminal>();
|
_term = HostContext.GetService<ITerminal>();
|
||||||
_runnerServer = HostContext.GetService<IRunnerServer>();
|
_runnerServer = HostContext.GetService<IRunnerServer>();
|
||||||
|
_brokerServer = HostContext.GetService<IBrokerServer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_BROKER
|
||||||
|
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
var configManager = HostContext.GetService<IConfigurationManager>();
|
||||||
|
_settings = configManager.LoadSettings();
|
||||||
|
var serverUrl = _settings.ServerUrl;
|
||||||
|
Trace.Info(_settings);
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
Trace.Info($"Attempt to create session.");
|
||||||
|
Trace.Info("Connecting to the Runner Server...");
|
||||||
|
_term.WriteLine($"Connecting to {new Uri(serverUrl)}");
|
||||||
|
await _brokerServer.ConnectAsync(new Uri(serverUrl));
|
||||||
|
_term.WriteLine();
|
||||||
|
_term.WriteSuccessMessage("Connected to GitHub");
|
||||||
|
_term.WriteLine();
|
||||||
|
|
||||||
|
// Session info
|
||||||
|
var agent = new TaskAgentReference
|
||||||
|
{
|
||||||
|
Id = _settings.AgentId,
|
||||||
|
Name = _settings.AgentName,
|
||||||
|
Version = BuildConstants.RunnerPackage.Version,
|
||||||
|
OSDescription = RuntimeInformation.OSDescription,
|
||||||
|
};
|
||||||
|
string sessionName = $"{Environment.MachineName ?? "RUNNER"}";
|
||||||
|
_session = new TaskAgentSession(sessionName, agent);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
@@ -151,6 +188,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public async Task DeleteSessionAsync()
|
public async Task DeleteSessionAsync()
|
||||||
{
|
{
|
||||||
@@ -170,6 +208,116 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_BROKER
|
||||||
|
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
ArgUtil.NotNull(_session, nameof(_session));
|
||||||
|
ArgUtil.NotNull(_settings, nameof(_settings));
|
||||||
|
bool encounteringError = false;
|
||||||
|
int continuousError = 0;
|
||||||
|
string errorMessage = string.Empty;
|
||||||
|
Stopwatch heartbeat = new Stopwatch();
|
||||||
|
heartbeat.Restart();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
TaskAgentMessage message = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
message = await _brokerServer.GetMessageAsync(_settings.PoolId, _session.SessionId, _lastMessageId, token);
|
||||||
|
|
||||||
|
// Decrypt the message body if the session is using encryption
|
||||||
|
message = DecryptMessage(message);
|
||||||
|
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
_lastMessageId = message.MessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encounteringError) //print the message once only if there was an error
|
||||||
|
{
|
||||||
|
_term.WriteLine($"{DateTime.UtcNow:u}: Runner reconnected.");
|
||||||
|
encounteringError = false;
|
||||||
|
continuousError = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Trace.Info("Get next message has been cancelled.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (TaskAgentAccessTokenExpiredException)
|
||||||
|
{
|
||||||
|
Trace.Info("Runner OAuth token has been revoked. Unable to pull message.");
|
||||||
|
_accessTokenRevoked = true;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error("Catch exception during get next message.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
|
||||||
|
// don't retry if SkipSessionRecover = true, DT service will delete agent session to stop agent from taking more jobs.
|
||||||
|
if (ex is TaskAgentSessionExpiredException && !_settings.SkipSessionRecover && await CreateSessionAsync(token))
|
||||||
|
{
|
||||||
|
Trace.Info($"{nameof(TaskAgentSessionExpiredException)} received, recovered by recreate session.");
|
||||||
|
}
|
||||||
|
else if (!IsGetNextMessageExceptionRetriable(ex))
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continuousError++;
|
||||||
|
//retry after a random backoff to avoid service throttling
|
||||||
|
//in case of there is a service error happened and all agents get kicked off of the long poll and all agent try to reconnect back at the same time.
|
||||||
|
if (continuousError <= 5)
|
||||||
|
{
|
||||||
|
// random backoff [15, 30]
|
||||||
|
_getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30), _getNextMessageRetryInterval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// more aggressive backoff [30, 60]
|
||||||
|
_getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(60), _getNextMessageRetryInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encounteringError)
|
||||||
|
{
|
||||||
|
//print error only on the first consecutive error
|
||||||
|
_term.WriteError($"{DateTime.UtcNow:u}: Runner connect error: {ex.Message}. Retrying until reconnected.");
|
||||||
|
encounteringError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-create VssConnection before next retry
|
||||||
|
await _runnerServer.RefreshConnectionAsync(RunnerConnectionType.MessageQueue, TimeSpan.FromSeconds(60));
|
||||||
|
|
||||||
|
Trace.Info("Sleeping for {0} seconds before retrying.", _getNextMessageRetryInterval.TotalSeconds);
|
||||||
|
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
if (heartbeat.Elapsed > TimeSpan.FromMinutes(30))
|
||||||
|
{
|
||||||
|
Trace.Info($"No message retrieved from session '{_session.SessionId}' within last 30 minutes.");
|
||||||
|
heartbeat.Restart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.Verbose($"No message retrieved from session '{_session.SessionId}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info($"Message '{message.MessageId}' received from session '{_session.SessionId}'.");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
@@ -281,6 +429,7 @@ namespace GitHub.Runner.Listener
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public async Task DeleteMessageAsync(TaskAgentMessage message)
|
public async Task DeleteMessageAsync(TaskAgentMessage message)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,15 +95,7 @@ namespace GitHub.Runner.Listener
|
|||||||
var unknownCommandlines = command.Validate();
|
var unknownCommandlines = command.Validate();
|
||||||
if (unknownCommandlines.Count > 0)
|
if (unknownCommandlines.Count > 0)
|
||||||
{
|
{
|
||||||
string commandName = command.GetCommandName();
|
terminal.WriteError($"Unrecognized command-line input arguments: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||||
if (string.IsNullOrEmpty(commandName))
|
|
||||||
{
|
|
||||||
terminal.WriteError($"This command does not recognize the command-line input arguments: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
terminal.WriteError($"Unrecognized command-line input arguments for command {commandName}: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defer to the Runner class to execute the command.
|
// Defer to the Runner class to execute the command.
|
||||||
|
|||||||
@@ -1004,7 +1004,7 @@ namespace GitHub.Runner.Worker
|
|||||||
if (actionDefinitionData.Execution.ExecutionType == ActionExecutionType.Container)
|
if (actionDefinitionData.Execution.ExecutionType == ActionExecutionType.Container)
|
||||||
{
|
{
|
||||||
var containerAction = actionDefinitionData.Execution as ContainerActionExecutionData;
|
var containerAction = actionDefinitionData.Execution as ContainerActionExecutionData;
|
||||||
if (DockerUtil.IsDockerfile(containerAction.Image))
|
if (containerAction.Image.EndsWith("Dockerfile") || containerAction.Image.EndsWith("dockerfile"))
|
||||||
{
|
{
|
||||||
var dockerFileFullPath = Path.Combine(actionEntryDirectory, containerAction.Image);
|
var dockerFileFullPath = Path.Combine(actionEntryDirectory, containerAction.Image);
|
||||||
executionContext.Debug($"Dockerfile for action: '{dockerFileFullPath}'.");
|
executionContext.Debug($"Dockerfile for action: '{dockerFileFullPath}'.");
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
using GitHub.DistributedTask.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
@@ -10,6 +9,7 @@ using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
@@ -171,16 +171,8 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Load the inputs.
|
// Load the inputs.
|
||||||
ExecutionContext.Debug("Loading inputs");
|
ExecutionContext.Debug("Loading inputs");
|
||||||
Dictionary<string, string> inputs;
|
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
if (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.UseContainerPathForTemplate) ?? false)
|
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
||||||
{
|
|
||||||
inputs = EvaluateStepInputs(stepHost);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
|
||||||
inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
|
||||||
}
|
|
||||||
|
|
||||||
var userInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var userInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
foreach (KeyValuePair<string, string> input in inputs)
|
foreach (KeyValuePair<string, string> input in inputs)
|
||||||
@@ -307,15 +299,6 @@ namespace GitHub.Runner.Worker
|
|||||||
return didFullyEvaluate;
|
return didFullyEvaluate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<String, String> EvaluateStepInputs(IStepHost stepHost)
|
|
||||||
{
|
|
||||||
DictionaryContextData expressionValues = ExecutionContext.GetExpressionValues(stepHost);
|
|
||||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
|
||||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, expressionValues, ExecutionContext.ExpressionFunctions);
|
|
||||||
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GenerateDisplayName(ActionStep action, DictionaryContextData contextData, IExecutionContext context, out bool didFullyEvaluate)
|
private string GenerateDisplayName(ActionStep action, DictionaryContextData contextData, IExecutionContext context, out bool didFullyEvaluate)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(context, nameof(context));
|
ArgUtil.NotNull(context, nameof(context));
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Container
|
namespace GitHub.Runner.Worker.Container
|
||||||
@@ -18,7 +17,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
string pattern = $"^(?<{targetPort}>\\d+)/(?<{proto}>\\w+) -> (?<{host}>.+):(?<{hostPort}>\\d+)$";
|
string pattern = $"^(?<{targetPort}>\\d+)/(?<{proto}>\\w+) -> (?<{host}>.+):(?<{hostPort}>\\d+)$";
|
||||||
|
|
||||||
List<PortMapping> portMappings = new List<PortMapping>();
|
List<PortMapping> portMappings = new List<PortMapping>();
|
||||||
foreach (var line in portMappingLines)
|
foreach(var line in portMappingLines)
|
||||||
{
|
{
|
||||||
Match m = Regex.Match(line, pattern, RegexOptions.None, TimeSpan.FromSeconds(1));
|
Match m = Regex.Match(line, pattern, RegexOptions.None, TimeSpan.FromSeconds(1));
|
||||||
if (m.Success)
|
if (m.Success)
|
||||||
@@ -62,15 +61,5 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsDockerfile(string image)
|
|
||||||
{
|
|
||||||
if (image.StartsWith("docker://", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var imageWithoutPath = image.Split('/').Last();
|
|
||||||
return imageWithoutPath.StartsWith("Dockerfile.") || imageWithoutPath.StartsWith("dockerfile.") || imageWithoutPath.EndsWith("Dockerfile") || imageWithoutPath.EndsWith("dockerfile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
@@ -15,7 +20,7 @@ using GitHub.Runner.Common;
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Services.WebApi;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
@@ -110,6 +115,7 @@ namespace GitHub.Runner.Worker
|
|||||||
void UpdateGlobalStepsContext();
|
void UpdateGlobalStepsContext();
|
||||||
|
|
||||||
void WriteWebhookPayload();
|
void WriteWebhookPayload();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ExecutionContext : RunnerService, IExecutionContext
|
public sealed class ExecutionContext : RunnerService, IExecutionContext
|
||||||
@@ -1193,66 +1199,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
return new TemplateTraceWriter(context);
|
return new TemplateTraceWriter(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DictionaryContextData GetExpressionValues(this IExecutionContext context, IStepHost stepHost)
|
|
||||||
{
|
|
||||||
if (stepHost is ContainerStepHost)
|
|
||||||
{
|
|
||||||
|
|
||||||
var expressionValues = context.ExpressionValues.Clone() as DictionaryContextData;
|
|
||||||
context.UpdatePathsInExpressionValues("github", expressionValues, stepHost);
|
|
||||||
context.UpdatePathsInExpressionValues("runner", expressionValues, stepHost);
|
|
||||||
return expressionValues;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return context.ExpressionValues.Clone() as DictionaryContextData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdatePathsInExpressionValues(this IExecutionContext context, string contextName, DictionaryContextData expressionValues, IStepHost stepHost)
|
|
||||||
{
|
|
||||||
var dict = expressionValues[contextName].AssertDictionary($"expected context {contextName} to be a dictionary");
|
|
||||||
context.ResolvePathsInExpressionValuesDictionary(dict, stepHost);
|
|
||||||
expressionValues[contextName] = dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ResolvePathsInExpressionValuesDictionary(this IExecutionContext context, DictionaryContextData dict, IStepHost stepHost)
|
|
||||||
{
|
|
||||||
foreach (var key in dict.Keys.ToList())
|
|
||||||
{
|
|
||||||
if (dict[key] is StringContextData)
|
|
||||||
{
|
|
||||||
var value = dict[key].ToString();
|
|
||||||
if (!string.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
dict[key] = new StringContextData(stepHost.ResolvePathForStepHost(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dict[key] is DictionaryContextData)
|
|
||||||
{
|
|
||||||
var innerDict = dict[key].AssertDictionary("expected dictionary");
|
|
||||||
context.ResolvePathsInExpressionValuesDictionary(innerDict, stepHost);
|
|
||||||
var updatedDict = new DictionaryContextData();
|
|
||||||
foreach (var k in innerDict.Keys.ToList())
|
|
||||||
{
|
|
||||||
updatedDict[k] = innerDict[k];
|
|
||||||
}
|
|
||||||
dict[key] = updatedDict;
|
|
||||||
}
|
|
||||||
else if (dict[key] is CaseSensitiveDictionaryContextData)
|
|
||||||
{
|
|
||||||
var innerDict = dict[key].AssertDictionary("expected dictionary");
|
|
||||||
context.ResolvePathsInExpressionValuesDictionary(innerDict, stepHost);
|
|
||||||
var updatedDict = new CaseSensitiveDictionaryContextData();
|
|
||||||
foreach (var k in innerDict.Keys.ToList())
|
|
||||||
{
|
|
||||||
updatedDict[k] = innerDict[k];
|
|
||||||
}
|
|
||||||
dict[key] = updatedDict;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class TemplateTraceWriter : ObjectTemplating.ITraceWriter
|
internal sealed class TemplateTraceWriter : ObjectTemplating.ITraceWriter
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
void InitializeFiles(IExecutionContext context, ContainerInfo container);
|
void InitializeFiles(IExecutionContext context, ContainerInfo container);
|
||||||
void ProcessFiles(IExecutionContext context, ContainerInfo container);
|
void ProcessFiles(IExecutionContext context, ContainerInfo container);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class FileCommandManager : RunnerService, IFileCommandManager
|
public sealed class FileCommandManager : RunnerService, IFileCommandManager
|
||||||
@@ -57,7 +57,7 @@ namespace GitHub.Runner.Worker
|
|||||||
TryDeleteFile(newPath);
|
TryDeleteFile(newPath);
|
||||||
File.Create(newPath).Dispose();
|
File.Create(newPath).Dispose();
|
||||||
|
|
||||||
var pathToSet = container != null ? container.TranslateToContainerPath(newPath) : newPath;
|
var pathToSet = container != null ? container.TranslateToContainerPath(newPath) : newPath;
|
||||||
context.SetGitHubContext(fileCommand.ContextName, pathToSet);
|
context.SetGitHubContext(fileCommand.ContextName, pathToSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
foreach (var fileCommand in _commandExtensions)
|
foreach (var fileCommand in _commandExtensions)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
fileCommand.ProcessCommand(context, Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix),container);
|
fileCommand.ProcessCommand(context, Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix),container);
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension
|
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension
|
||||||
{
|
{
|
||||||
public const int AttachmentSizeLimit = 1024 * 1024;
|
private const int _attachmentSizeLimit = 128 * 1024;
|
||||||
|
|
||||||
public string ContextName => "step_summary";
|
public string ContextName => "step_summary";
|
||||||
public string FilePrefix => "step_summary_";
|
public string FilePrefix => "step_summary_";
|
||||||
@@ -296,9 +296,9 @@ namespace GitHub.Runner.Worker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileSize > AttachmentSizeLimit)
|
if (fileSize > _attachmentSizeLimit)
|
||||||
{
|
{
|
||||||
context.Error(String.Format(Constants.Runner.UnsupportedSummarySize, AttachmentSizeLimit / 1024, fileSize / 1024));
|
context.Error(String.Format(Constants.Runner.UnsupportedSummarySize, _attachmentSizeLimit / 1024, fileSize / 1024));
|
||||||
Trace.Info($"Step Summary file ({filePath}) is too large ({fileSize} bytes); skipping attachment upload");
|
Trace.Info($"Step Summary file ({filePath}) is too large ({fileSize} bytes); skipping attachment upload");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -44,8 +44,9 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
Data.Image = Data.Image.Substring("docker://".Length);
|
Data.Image = Data.Image.Substring("docker://".Length);
|
||||||
}
|
}
|
||||||
else if (DockerUtil.IsDockerfile(Data.Image))
|
else if (Data.Image.EndsWith("Dockerfile") || Data.Image.EndsWith("dockerfile"))
|
||||||
{
|
{
|
||||||
|
// ensure docker file exist
|
||||||
var dockerFile = Path.Combine(ActionDirectory, Data.Image);
|
var dockerFile = Path.Combine(ActionDirectory, Data.Image);
|
||||||
ArgUtil.File(dockerFile, nameof(Data.Image));
|
ArgUtil.File(dockerFile, nameof(Data.Image));
|
||||||
|
|
||||||
@@ -67,10 +68,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
Data.Image = imageName;
|
Data.Image = imageName;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"'{Data.Image}' should be either '[path]/Dockerfile' or 'docker://image[:tag]'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
string type = Action.Type == Pipelines.ActionSourceType.Repository ? "Dockerfile" : "DockerHub";
|
string type = Action.Type == Pipelines.ActionSourceType.Repository ? "Dockerfile" : "DockerHub";
|
||||||
// Set extra telemetry base on the current context.
|
// Set extra telemetry base on the current context.
|
||||||
|
|||||||
@@ -151,11 +151,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.Contains("fatal: unsafe repository", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
_executionContext.StepTelemetry.ErrorMessages.Add(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular output
|
// Regular output
|
||||||
_executionContext.Output(line);
|
_executionContext.Output(line);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -132,7 +132,7 @@
|
|||||||
"continue-on-error": "boolean-steps-context",
|
"continue-on-error": "boolean-steps-context",
|
||||||
"working-directory": "string-steps-context",
|
"working-directory": "string-steps-context",
|
||||||
"shell": {
|
"shell": {
|
||||||
"type": "string-steps-context",
|
"type": "non-empty-string",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace GitHub.Services.Common.ClientStorage
|
|||||||
private readonly string m_filePath;
|
private readonly string m_filePath;
|
||||||
private readonly VssFileStorageReader m_reader;
|
private readonly VssFileStorageReader m_reader;
|
||||||
private readonly IVssClientStorageWriter m_writer;
|
private readonly IVssClientStorageWriter m_writer;
|
||||||
|
|
||||||
private const char c_defaultPathSeparator = '\\';
|
private const char c_defaultPathSeparator = '\\';
|
||||||
private const bool c_defaultIgnoreCaseInPaths = false;
|
private const bool c_defaultIgnoreCaseInPaths = false;
|
||||||
|
|
||||||
@@ -191,7 +192,7 @@ namespace GitHub.Services.Common.ClientStorage
|
|||||||
// Windows Impersonation is being used.
|
// Windows Impersonation is being used.
|
||||||
|
|
||||||
// Check to see if we can find the user's local application data directory.
|
// Check to see if we can find the user's local application data directory.
|
||||||
string subDir = Path.Combine("GitHub", "ActionsService");
|
string subDir = "GitHub\\ActionsService";
|
||||||
string path = Environment.GetEnvironmentVariable("localappdata");
|
string path = Environment.GetEnvironmentVariable("localappdata");
|
||||||
SafeGetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
SafeGetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
|
|||||||
@@ -144,48 +144,5 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
|
|||||||
var actual = DockerUtil.ParseRegistryHostnameFromImageName(input);
|
var actual = DockerUtil.ParseRegistryHostnameFromImageName(input);
|
||||||
Assert.Equal(expected, actual);
|
Assert.Equal(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
[InlineData("dockerhub/repo", false)]
|
|
||||||
[InlineData("debian:latest", false)]
|
|
||||||
[InlineData("something/dockerfileimage", false)]
|
|
||||||
[InlineData("ghcr.io/docker/dockerfile", true)] // should be false but might break the current workflows
|
|
||||||
[InlineData("Dockerfile", true)]
|
|
||||||
[InlineData("Dockerfile.", true)]
|
|
||||||
[InlineData(".Dockerfile", true)]
|
|
||||||
[InlineData(".Dockerfile.", false)]
|
|
||||||
[InlineData("dockerfile", true)]
|
|
||||||
[InlineData("dockerfile.", true)]
|
|
||||||
[InlineData(".dockerfile", true)]
|
|
||||||
[InlineData(".dockerfile.", false)]
|
|
||||||
[InlineData("Dockerfile.test", true)]
|
|
||||||
[InlineData("test.Dockerfile", true)]
|
|
||||||
[InlineData("docker/dockerfile:latest", false)]
|
|
||||||
[InlineData("/some/path/dockerfile:latest", false)]
|
|
||||||
[InlineData("dockerfile:latest", false)]
|
|
||||||
[InlineData("Dockerfile:latest", false)]
|
|
||||||
[InlineData("dockerfile-latest", false)]
|
|
||||||
[InlineData("Dockerfile-latest", false)]
|
|
||||||
[InlineData("dockerfile.latest", true)]
|
|
||||||
[InlineData("Dockerfile.latest", true)]
|
|
||||||
[InlineData("../dockerfile/dockerfileone", false)]
|
|
||||||
[InlineData("../Dockerfile/dockerfileone", false)]
|
|
||||||
[InlineData("../dockerfile.test", true)]
|
|
||||||
[InlineData("../Dockerfile.test", true)]
|
|
||||||
[InlineData("./dockerfile/image", false)]
|
|
||||||
[InlineData("./Dockerfile/image", false)]
|
|
||||||
[InlineData("example/Dockerfile.test", true)]
|
|
||||||
[InlineData("./example/Dockerfile.test", true)]
|
|
||||||
[InlineData("example/test.dockerfile", true)]
|
|
||||||
[InlineData("./example/test.dockerfile", true)]
|
|
||||||
[InlineData("docker://Dockerfile", false)]
|
|
||||||
[InlineData("docker://ubuntu:latest", false)]
|
|
||||||
public void IsDockerfile(string input, bool expected)
|
|
||||||
{
|
|
||||||
var actual = DockerUtil.IsDockerfile(input);
|
|
||||||
Assert.Equal(expected, actual);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -708,85 +708,33 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData("configure", "once")]
|
|
||||||
[InlineData("remove", "disableupdate")]
|
|
||||||
[InlineData("remove", "ephemeral")]
|
|
||||||
[InlineData("remove", "once")]
|
|
||||||
[InlineData("remove", "replace")]
|
|
||||||
[InlineData("remove", "runasservice")]
|
|
||||||
[InlineData("remove", "unattended")]
|
|
||||||
[InlineData("run", "disableupdate")]
|
|
||||||
[InlineData("run", "ephemeral")]
|
|
||||||
[InlineData("run", "replace")]
|
|
||||||
[InlineData("run", "runasservice")]
|
|
||||||
[InlineData("run", "unattended")]
|
|
||||||
[InlineData("warmup", "disableupdate")]
|
|
||||||
[InlineData("warmup", "ephemeral")]
|
|
||||||
[InlineData("warmup", "once")]
|
|
||||||
[InlineData("warmup", "replace")]
|
|
||||||
[InlineData("warmup", "runasservice")]
|
|
||||||
[InlineData("warmup", "unattended")]
|
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", nameof(CommandSettings))]
|
[Trait("Category", nameof(CommandSettings))]
|
||||||
public void ValidateInvalidFlagCommandCombination(string validCommand, string flag)
|
public void ValidateFlags()
|
||||||
{
|
{
|
||||||
using (TestHostContext hc = CreateTestContext())
|
using (TestHostContext hc = CreateTestContext())
|
||||||
{
|
{
|
||||||
// Arrange.
|
// Arrange.
|
||||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
var command = new CommandSettings(hc, args: new string[] { "--badflag" });
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Contains(flag, command.Validate());
|
Assert.Contains("badflag", command.Validate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData("remove", "auth", "bar arg value")]
|
|
||||||
[InlineData("remove", "labels", "bar arg value")]
|
|
||||||
[InlineData("remove", "monitorsocketaddress", "bar arg value")]
|
|
||||||
[InlineData("remove", "name", "bar arg value")]
|
|
||||||
[InlineData("remove", "runnergroup", "bar arg value")]
|
|
||||||
[InlineData("remove", "url", "bar arg value")]
|
|
||||||
[InlineData("remove", "username", "bar arg value")]
|
|
||||||
[InlineData("remove", "windowslogonaccount", "bar arg value")]
|
|
||||||
[InlineData("remove", "windowslogonpassword", "bar arg value")]
|
|
||||||
[InlineData("remove", "work", "bar arg value")]
|
|
||||||
[InlineData("run", "auth", "bad arg value")]
|
|
||||||
[InlineData("run", "labels", "bad arg value")]
|
|
||||||
[InlineData("run", "monitorsocketaddress", "bad arg value")]
|
|
||||||
[InlineData("run", "name", "bad arg value")]
|
|
||||||
[InlineData("run", "pat", "bad arg value")]
|
|
||||||
[InlineData("run", "runnergroup", "bad arg value")]
|
|
||||||
[InlineData("run", "token", "bad arg value")]
|
|
||||||
[InlineData("run", "url", "bad arg value")]
|
|
||||||
[InlineData("run", "username", "bad arg value")]
|
|
||||||
[InlineData("run", "windowslogonaccount", "bad arg value")]
|
|
||||||
[InlineData("run", "windowslogonpassword", "bad arg value")]
|
|
||||||
[InlineData("run", "work", "bad arg value")]
|
|
||||||
[InlineData("warmup", "auth", "bad arg value")]
|
|
||||||
[InlineData("warmup", "labels", "bad arg value")]
|
|
||||||
[InlineData("warmup", "monitorsocketaddress", "bad arg value")]
|
|
||||||
[InlineData("warmup", "name", "bad arg value")]
|
|
||||||
[InlineData("warmup", "pat", "bad arg value")]
|
|
||||||
[InlineData("warmup", "runnergroup", "bad arg value")]
|
|
||||||
[InlineData("warmup", "token", "bad arg value")]
|
|
||||||
[InlineData("warmup", "url", "bad arg value")]
|
|
||||||
[InlineData("warmup", "username", "bad arg value")]
|
|
||||||
[InlineData("warmup", "windowslogonaccount", "bad arg value")]
|
|
||||||
[InlineData("warmup", "windowslogonpassword", "bad arg value")]
|
|
||||||
[InlineData("warmup", "work", "bad arg value")]
|
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", nameof(CommandSettings))]
|
[Trait("Category", nameof(CommandSettings))]
|
||||||
public void ValidateInvalidArgCommandCombination(string validCommand, string arg, string argValue)
|
public void ValidateArgs()
|
||||||
{
|
{
|
||||||
using (TestHostContext hc = CreateTestContext())
|
using (TestHostContext hc = CreateTestContext())
|
||||||
{
|
{
|
||||||
// Arrange.
|
// Arrange.
|
||||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
var command = new CommandSettings(hc, args: new string[] { "--badargname", "bad arg value" });
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Contains(arg, command.Validate());
|
Assert.Contains("badargname", command.Validate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,73 +758,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData("configure", "help")]
|
|
||||||
[InlineData("configure", "version")]
|
|
||||||
[InlineData("configure", "commit")]
|
|
||||||
[InlineData("configure", "check")]
|
|
||||||
[InlineData("configure", "disableupdate")]
|
|
||||||
[InlineData("configure", "ephemeral")]
|
|
||||||
[InlineData("configure", "replace")]
|
|
||||||
[InlineData("configure", "runasservice")]
|
|
||||||
[InlineData("configure", "unattended")]
|
|
||||||
[InlineData("remove", "help")]
|
|
||||||
[InlineData("remove", "version")]
|
|
||||||
[InlineData("remove", "commit")]
|
|
||||||
[InlineData("remove", "check")]
|
|
||||||
[InlineData("run", "help")]
|
|
||||||
[InlineData("run", "version")]
|
|
||||||
[InlineData("run", "commit")]
|
|
||||||
[InlineData("run", "check")]
|
|
||||||
[InlineData("run", "once")]
|
|
||||||
[InlineData("warmup", "help")]
|
|
||||||
[InlineData("warmup", "version")]
|
|
||||||
[InlineData("warmup", "commit")]
|
|
||||||
[InlineData("warmup", "check")]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", nameof(CommandSettings))]
|
|
||||||
public void ValidateGoodFlagCommandCombination(string validCommand, string flag)
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
// Arrange.
|
|
||||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
|
||||||
|
|
||||||
// Assert.
|
|
||||||
Assert.True(command.Validate().Count == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData("configure", "auth", "good arg value")]
|
|
||||||
[InlineData("configure", "labels", "good arg value")]
|
|
||||||
[InlineData("configure", "monitorsocketaddress", "good arg value")]
|
|
||||||
[InlineData("configure", "name", "good arg value")]
|
|
||||||
[InlineData("configure", "pat", "good arg value")]
|
|
||||||
[InlineData("configure", "runnergroup", "good arg value")]
|
|
||||||
[InlineData("configure", "token", "good arg value")]
|
|
||||||
[InlineData("configure", "url", "good arg value")]
|
|
||||||
[InlineData("configure", "username", "good arg value")]
|
|
||||||
[InlineData("configure", "windowslogonaccount", "good arg value")]
|
|
||||||
[InlineData("configure", "windowslogonpassword", "good arg value")]
|
|
||||||
[InlineData("configure", "work", "good arg value")]
|
|
||||||
[InlineData("remove", "token", "good arg value")]
|
|
||||||
[InlineData("remove", "pat", "good arg value")]
|
|
||||||
[InlineData("run", "startuptype", "good arg value")]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", nameof(CommandSettings))]
|
|
||||||
public void ValidateGoodArgCommandCombination(string validCommand, string arg, string argValue)
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
// Arrange.
|
|
||||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
|
||||||
|
|
||||||
// Assert.
|
|
||||||
Assert.True(command.Validate().Count == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TestHostContext CreateTestContext([CallerMemberName] string testName = "")
|
private TestHostContext CreateTestContext([CallerMemberName] string testName = "")
|
||||||
{
|
{
|
||||||
TestHostContext hc = new TestHostContext(this, testName);
|
TestHostContext hc = new TestHostContext(this, testName);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
using (var hostContext = Setup(featureFlagState: "false"))
|
using (var hostContext = Setup(featureFlagState: "false"))
|
||||||
{
|
{
|
||||||
var stepSummaryFile = Path.Combine(_rootDirectory, "feature-off");
|
var stepSummaryFile = Path.Combine(_rootDirectory, "feature-off");
|
||||||
|
|
||||||
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
||||||
_jobExecutionContext.Complete();
|
_jobExecutionContext.Complete();
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
using (var hostContext = Setup())
|
using (var hostContext = Setup())
|
||||||
{
|
{
|
||||||
var stepSummaryFile = Path.Combine(_rootDirectory, "empty-file");
|
var stepSummaryFile = Path.Combine(_rootDirectory, "empty-file");
|
||||||
File.WriteAllBytes(stepSummaryFile, new byte[CreateStepSummaryCommand.AttachmentSizeLimit + 1]);
|
File.WriteAllBytes(stepSummaryFile, new byte[128 * 1024 + 1]);
|
||||||
|
|
||||||
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
||||||
_jobExecutionContext.Complete();
|
_jobExecutionContext.Complete();
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ using System.Threading;
|
|||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Worker.Handlers;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
@@ -726,149 +724,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
return hc;
|
return hc;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void GetExpressionValues_ContainerStepHost()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
const string source = "/home/username/Projects/work/runner/_layout";
|
|
||||||
var containerInfo = new ContainerInfo();
|
|
||||||
containerInfo.ContainerId = "test";
|
|
||||||
|
|
||||||
containerInfo.AddPathTranslateMapping($"{source}/_work", "/__w");
|
|
||||||
containerInfo.AddPathTranslateMapping($"{source}/_temp", "/__t");
|
|
||||||
containerInfo.AddPathTranslateMapping($"{source}/externals", "/__e");
|
|
||||||
|
|
||||||
containerInfo.AddPathTranslateMapping($"{source}/_work/_temp/_github_home", "/github/home");
|
|
||||||
containerInfo.AddPathTranslateMapping($"{source}/_work/_temp/_github_workflow", "/github/workflow");
|
|
||||||
|
|
||||||
foreach (var v in new List<string>() {
|
|
||||||
$"{source}/_work",
|
|
||||||
$"{source}/externals",
|
|
||||||
$"{source}/_work/_temp",
|
|
||||||
$"{source}/_work/_actions",
|
|
||||||
$"{source}/_work/_tool",
|
|
||||||
})
|
|
||||||
{
|
|
||||||
containerInfo.MountVolumes.Add(new MountVolume(v, containerInfo.TranslateToContainerPath(v)));
|
|
||||||
};
|
|
||||||
|
|
||||||
var stepHost = new ContainerStepHost();
|
|
||||||
stepHost.Container = containerInfo;
|
|
||||||
|
|
||||||
var ec = new Runner.Worker.ExecutionContext();
|
|
||||||
ec.Initialize(hc);
|
|
||||||
|
|
||||||
var inputGithubContext = new GitHubContext();
|
|
||||||
var inputeRunnerContext = new RunnerContext();
|
|
||||||
|
|
||||||
// string context data
|
|
||||||
inputGithubContext["action_path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_actions/owner/composite/main");
|
|
||||||
inputGithubContext["action"] = new StringContextData("__owner_composite");
|
|
||||||
inputGithubContext["api_url"] = new StringContextData("https://api.github.com/custom/path");
|
|
||||||
inputGithubContext["env"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_runner_file_commands/set_env_265698aa-7f38-40f5-9316-5c01a3153672");
|
|
||||||
inputGithubContext["path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_runner_file_commands/add_path_265698aa-7f38-40f5-9316-5c01a3153672");
|
|
||||||
inputGithubContext["event_path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_github_workflow/event.json");
|
|
||||||
inputGithubContext["repository"] = new StringContextData("owner/repo-name");
|
|
||||||
inputGithubContext["run_id"] = new StringContextData("2033211332");
|
|
||||||
inputGithubContext["workflow"] = new StringContextData("Name of Workflow");
|
|
||||||
inputGithubContext["workspace"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/step-order/step-order");
|
|
||||||
inputeRunnerContext["temp"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp");
|
|
||||||
inputeRunnerContext["tool_cache"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_tool");
|
|
||||||
|
|
||||||
// dictionary context data
|
|
||||||
var githubEvent = new DictionaryContextData();
|
|
||||||
githubEvent["inputs"] = null;
|
|
||||||
githubEvent["ref"] = new StringContextData("refs/heads/main");
|
|
||||||
githubEvent["repository"] = new DictionaryContextData();
|
|
||||||
githubEvent["sender"] = new DictionaryContextData();
|
|
||||||
githubEvent["workflow"] = new StringContextData(".github/workflows/composite_step_host_translate.yaml");
|
|
||||||
|
|
||||||
inputGithubContext["event"] = githubEvent;
|
|
||||||
|
|
||||||
ec.ExpressionValues["github"] = inputGithubContext;
|
|
||||||
ec.ExpressionValues["runner"] = inputeRunnerContext;
|
|
||||||
|
|
||||||
var ecExpect = new Runner.Worker.ExecutionContext();
|
|
||||||
ecExpect.Initialize(hc);
|
|
||||||
|
|
||||||
var expectedGithubEvent = new DictionaryContextData();
|
|
||||||
expectedGithubEvent["inputs"] = null;
|
|
||||||
expectedGithubEvent["ref"] = new StringContextData("refs/heads/main");
|
|
||||||
expectedGithubEvent["repository"] = new DictionaryContextData();
|
|
||||||
expectedGithubEvent["sender"] = new DictionaryContextData();
|
|
||||||
expectedGithubEvent["workflow"] = new StringContextData(".github/workflows/composite_step_host_translate.yaml");
|
|
||||||
var expectedGithubContext = new GitHubContext();
|
|
||||||
var expectedRunnerContext = new RunnerContext();
|
|
||||||
expectedGithubContext["action_path"] = new StringContextData("/__w/_actions/owner/composite/main");
|
|
||||||
expectedGithubContext["action"] = new StringContextData("__owner_composite");
|
|
||||||
expectedGithubContext["api_url"] = new StringContextData("https://api.github.com/custom/path");
|
|
||||||
expectedGithubContext["env"] = new StringContextData("/__w/_temp/_runner_file_commands/set_env_265698aa-7f38-40f5-9316-5c01a3153672");
|
|
||||||
expectedGithubContext["path"] = new StringContextData("/__w/_temp/_runner_file_commands/add_path_265698aa-7f38-40f5-9316-5c01a3153672");
|
|
||||||
expectedGithubContext["event_path"] = new StringContextData("/github/workflow/event.json");
|
|
||||||
expectedGithubContext["repository"] = new StringContextData("owner/repo-name");
|
|
||||||
expectedGithubContext["run_id"] = new StringContextData("2033211332");
|
|
||||||
expectedGithubContext["workflow"] = new StringContextData("Name of Workflow");
|
|
||||||
expectedGithubContext["workspace"] = new StringContextData("/__w/step-order/step-order");
|
|
||||||
expectedGithubContext["event"] = expectedGithubEvent;
|
|
||||||
expectedRunnerContext["temp"] = new StringContextData("/__w/_temp");
|
|
||||||
expectedRunnerContext["tool_cache"] = new StringContextData("/__w/_tool");
|
|
||||||
|
|
||||||
ecExpect.ExpressionValues["github"] = expectedGithubContext;
|
|
||||||
ecExpect.ExpressionValues["runner"] = expectedRunnerContext;
|
|
||||||
|
|
||||||
var translatedExpressionValues = ec.GetExpressionValues(stepHost);
|
|
||||||
|
|
||||||
foreach (var contextName in new string[] { "github", "runner" })
|
|
||||||
{
|
|
||||||
var dict = translatedExpressionValues[contextName].AssertDictionary($"expected context github to be a dictionary");
|
|
||||||
var expectedExpressionValues = ecExpect.ExpressionValues[contextName].AssertDictionary("expect dict");
|
|
||||||
foreach (var key in dict.Keys.ToList())
|
|
||||||
{
|
|
||||||
if (dict[key] is StringContextData)
|
|
||||||
{
|
|
||||||
var expect = dict[key].AssertString("expect string");
|
|
||||||
var outcome = expectedExpressionValues[key].AssertString("expect string");
|
|
||||||
Assert.Equal(expect.Value, outcome.Value);
|
|
||||||
}
|
|
||||||
else if (dict[key] is DictionaryContextData || dict[key] is CaseSensitiveDictionaryContextData)
|
|
||||||
{
|
|
||||||
var expectDict = dict[key].AssertDictionary("expect dict");
|
|
||||||
var actualDict = expectedExpressionValues[key].AssertDictionary("expect dict");
|
|
||||||
Assert.True(ExpressionValuesAssertEqual(expectDict, actualDict));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ExpressionValuesAssertEqual(DictionaryContextData expect, DictionaryContextData actual)
|
|
||||||
{
|
|
||||||
foreach (var key in expect.Keys.ToList())
|
|
||||||
{
|
|
||||||
if (expect[key] is StringContextData)
|
|
||||||
{
|
|
||||||
var expectValue = expect[key].AssertString("expect string");
|
|
||||||
var actualValue = actual[key].AssertString("expect string");
|
|
||||||
if (expectValue.Equals(actualValue))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (expect[key] is DictionaryContextData || expect[key] is CaseSensitiveDictionaryContextData)
|
|
||||||
{
|
|
||||||
var expectDict = expect[key].AssertDictionary("expect dict");
|
|
||||||
var actualDict = actual[key].AssertDictionary("expect dict");
|
|
||||||
if (!ExpressionValuesAssertEqual(expectDict, actualDict))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
@@ -937,19 +937,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void CaptureTelemetryForGitUnsafeRepository()
|
|
||||||
{
|
|
||||||
using (Setup())
|
|
||||||
using (_outputManager)
|
|
||||||
{
|
|
||||||
Process("fatal: unsafe repository ('/github/workspace' is owned by someone else)");
|
|
||||||
Assert.Contains("fatal: unsafe repository ('/github/workspace' is owned by someone else)", _executionContext.Object.StepTelemetry.ErrorMessages);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TestHostContext Setup(
|
private TestHostContext Setup(
|
||||||
[CallerMemberName] string name = "",
|
[CallerMemberName] string name = "",
|
||||||
IssueMatchersConfig matchers = null,
|
IssueMatchersConfig matchers = null,
|
||||||
@@ -975,8 +962,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Variables = _variables,
|
Variables = _variables,
|
||||||
WriteDebug = true,
|
WriteDebug = true,
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.StepTelemetry)
|
|
||||||
.Returns(new DTWebApi.ActionsStepTelemetry());
|
|
||||||
_executionContext.Setup(x => x.GetMatchers())
|
_executionContext.Setup(x => x.GetMatchers())
|
||||||
.Returns(matchers?.Matchers ?? new List<IssueMatcherConfig>());
|
.Returns(matchers?.Matchers ?? new List<IssueMatcherConfig>());
|
||||||
_executionContext.Setup(x => x.Add(It.IsAny<OnMatcherChanged>()))
|
_executionContext.Setup(x => x.Add(It.IsAny<OnMatcherChanged>()))
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ using Xunit;
|
|||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using System.Linq;
|
|
||||||
using GitHub.DistributedTask.Pipelines;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
{
|
{
|
||||||
|
|||||||
14
src/dev.sh
14
src/dev.sh
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
# ./dev.sh build/layout/test/package [Debug/Release]
|
# ./dev.sh build/layout/test/package [Debug/Release] [linux-x64|linux-x86|linux-arm64|linux-arm|osx-x64|win-x64|win-x86] [use-broker]
|
||||||
#
|
#
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ set -e
|
|||||||
DEV_CMD=$1
|
DEV_CMD=$1
|
||||||
DEV_CONFIG=$2
|
DEV_CONFIG=$2
|
||||||
DEV_TARGET_RUNTIME=$3
|
DEV_TARGET_RUNTIME=$3
|
||||||
|
DEV_USE_BROKER=$4
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
||||||
@@ -81,6 +82,13 @@ elif [[ "$CURRENT_PLATFORM" == 'darwin' ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$DEV_USE_BROKER" ]; then
|
||||||
|
USE_BROKER='-p:USE_BROKER="true"'
|
||||||
|
else
|
||||||
|
USE_BROKER=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
function failed()
|
function failed()
|
||||||
{
|
{
|
||||||
local error=${1:-Undefined error}
|
local error=${1:-Undefined error}
|
||||||
@@ -114,13 +122,13 @@ function heading()
|
|||||||
function build ()
|
function build ()
|
||||||
{
|
{
|
||||||
heading "Building ..."
|
heading "Building ..."
|
||||||
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" $USE_BROKER ./dir.proj || failed build
|
||||||
}
|
}
|
||||||
|
|
||||||
function layout ()
|
function layout ()
|
||||||
{
|
{
|
||||||
heading "Create layout ..."
|
heading "Create layout ..."
|
||||||
dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" $USE_BROKER ./dir.proj || failed build
|
||||||
|
|
||||||
#change execution flag to allow running with sudo
|
#change execution flag to allow running with sudo
|
||||||
if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then
|
if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.291.0
|
2.289.2
|
||||||
|
|||||||
Reference in New Issue
Block a user