mirror of
https://github.com/actions/runner.git
synced 2025-12-10 12:36:23 +00:00
Compare commits
7 Commits
users/tihu
...
v2.169.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c126b52fe5 | ||
|
|
117ec1fff9 | ||
|
|
d5c7097d2c | ||
|
|
f9baec4b32 | ||
|
|
a20ad4e121 | ||
|
|
2bd0b1af0e | ||
|
|
baa6ded3bc |
@@ -1 +1 @@
|
|||||||
2.164.0
|
2.168.0
|
||||||
|
|||||||
13
src/Misc/layoutbin/macos-run-invoker.js
Normal file
13
src/Misc/layoutbin/macos-run-invoker.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const { spawn } = require('child_process');
|
||||||
|
// argv[0] = node
|
||||||
|
// argv[1] = macos-run-invoker.js
|
||||||
|
var shell = process.argv[2];
|
||||||
|
var args = process.argv.slice(3);
|
||||||
|
console.log(`::debug::macos-run-invoker: ${shell}`);
|
||||||
|
console.log(`::debug::macos-run-invoker: ${JSON.stringify(args)}`);
|
||||||
|
var launch = spawn(shell, args, { stdio: 'inherit' });
|
||||||
|
launch.on('exit', function (code) {
|
||||||
|
if (code !== 0) {
|
||||||
|
process.exit(code);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -87,6 +87,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static class Args
|
public static class Args
|
||||||
{
|
{
|
||||||
public static readonly string Auth = "auth";
|
public static readonly string Auth = "auth";
|
||||||
|
public static readonly string Labels = "labels";
|
||||||
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
||||||
public static readonly string Name = "name";
|
public static readonly string Name = "name";
|
||||||
public static readonly string Pool = "pool";
|
public static readonly string Pool = "pool";
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace GitHub.Runner.Common
|
|||||||
CancellationToken RunnerShutdownToken { get; }
|
CancellationToken RunnerShutdownToken { get; }
|
||||||
ShutdownReason RunnerShutdownReason { get; }
|
ShutdownReason RunnerShutdownReason { get; }
|
||||||
ISecretMasker SecretMasker { get; }
|
ISecretMasker SecretMasker { get; }
|
||||||
ProductInfoHeaderValue UserAgent { get; }
|
List<ProductInfoHeaderValue> UserAgents { get; }
|
||||||
RunnerWebProxy WebProxy { get; }
|
RunnerWebProxy WebProxy { get; }
|
||||||
string GetDirectory(WellKnownDirectory directory);
|
string GetDirectory(WellKnownDirectory directory);
|
||||||
string GetConfigFile(WellKnownConfigFile configFile);
|
string GetConfigFile(WellKnownConfigFile configFile);
|
||||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Common
|
|||||||
private readonly ConcurrentDictionary<Type, object> _serviceInstances = new ConcurrentDictionary<Type, object>();
|
private readonly ConcurrentDictionary<Type, object> _serviceInstances = new ConcurrentDictionary<Type, object>();
|
||||||
private readonly ConcurrentDictionary<Type, Type> _serviceTypes = new ConcurrentDictionary<Type, Type>();
|
private readonly ConcurrentDictionary<Type, Type> _serviceTypes = new ConcurrentDictionary<Type, Type>();
|
||||||
private readonly ISecretMasker _secretMasker = new SecretMasker();
|
private readonly ISecretMasker _secretMasker = new SecretMasker();
|
||||||
private readonly ProductInfoHeaderValue _userAgent = new ProductInfoHeaderValue($"GitHubActionsRunner-{BuildConstants.RunnerPackage.PackageName}", BuildConstants.RunnerPackage.Version);
|
private readonly List<ProductInfoHeaderValue> _userAgents = new List<ProductInfoHeaderValue>() { new ProductInfoHeaderValue($"GitHubActionsRunner-{BuildConstants.RunnerPackage.PackageName}", BuildConstants.RunnerPackage.Version) };
|
||||||
private CancellationTokenSource _runnerShutdownTokenSource = new CancellationTokenSource();
|
private CancellationTokenSource _runnerShutdownTokenSource = new CancellationTokenSource();
|
||||||
private object _perfLock = new object();
|
private object _perfLock = new object();
|
||||||
private Tracing _trace;
|
private Tracing _trace;
|
||||||
@@ -72,7 +72,7 @@ namespace GitHub.Runner.Common
|
|||||||
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
||||||
public ShutdownReason RunnerShutdownReason { get; private set; }
|
public ShutdownReason RunnerShutdownReason { get; private set; }
|
||||||
public ISecretMasker SecretMasker => _secretMasker;
|
public ISecretMasker SecretMasker => _secretMasker;
|
||||||
public ProductInfoHeaderValue UserAgent => _userAgent;
|
public List<ProductInfoHeaderValue> UserAgents => _userAgents;
|
||||||
public RunnerWebProxy WebProxy => _webProxy;
|
public RunnerWebProxy WebProxy => _webProxy;
|
||||||
public HostContext(string hostType, string logFile = null)
|
public HostContext(string hostType, string logFile = null)
|
||||||
{
|
{
|
||||||
@@ -189,6 +189,17 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
_trace.Info($"No proxy settings were found based on environmental variables (http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY)");
|
_trace.Info($"No proxy settings were found based on environmental variables (http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var credFile = GetConfigFile(WellKnownConfigFile.Credentials);
|
||||||
|
if (File.Exists(credFile))
|
||||||
|
{
|
||||||
|
var credData = IOUtil.LoadObject<CredentialData>(credFile);
|
||||||
|
if (credData != null &&
|
||||||
|
credData.Data.TryGetValue("clientId", out var clientId))
|
||||||
|
{
|
||||||
|
_userAgents.Add(new ProductInfoHeaderValue($"RunnerId", clientId));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetDirectory(WellKnownDirectory directory)
|
public string GetDirectory(WellKnownDirectory directory)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
// job request
|
// job request
|
||||||
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
||||||
Task<TaskAgentJobRequest> RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, CancellationToken cancellationToken);
|
Task<TaskAgentJobRequest> RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId, CancellationToken cancellationToken);
|
||||||
Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken);
|
Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken);
|
||||||
|
|
||||||
// agent package
|
// agent package
|
||||||
@@ -300,10 +300,10 @@ namespace GitHub.Runner.Common
|
|||||||
// JobRequest
|
// JobRequest
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
|
|
||||||
public Task<TaskAgentJobRequest> RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, CancellationToken cancellationToken = default(CancellationToken))
|
public Task<TaskAgentJobRequest> RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.JobRequest);
|
CheckConnection(RunnerConnectionType.JobRequest);
|
||||||
return _requestTaskAgentClient.RenewAgentRequestAsync(poolId, requestId, lockToken, cancellationToken: cancellationToken);
|
return _requestTaskAgentClient.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId: orchestrationId, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken = default(CancellationToken))
|
public Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace GitHub.Runner.Listener
|
|||||||
private readonly string[] validArgs =
|
private readonly string[] validArgs =
|
||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Args.Auth,
|
Constants.Runner.CommandLine.Args.Auth,
|
||||||
|
Constants.Runner.CommandLine.Args.Labels,
|
||||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||||
Constants.Runner.CommandLine.Args.Name,
|
Constants.Runner.CommandLine.Args.Name,
|
||||||
Constants.Runner.CommandLine.Args.Pool,
|
Constants.Runner.CommandLine.Args.Pool,
|
||||||
@@ -249,6 +250,24 @@ namespace GitHub.Runner.Listener
|
|||||||
return GetArg(Constants.Runner.CommandLine.Args.StartupType);
|
return GetArg(Constants.Runner.CommandLine.Args.StartupType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ISet<string> GetLabels()
|
||||||
|
{
|
||||||
|
var labelSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
string labels = GetArgOrPrompt(
|
||||||
|
name: Constants.Runner.CommandLine.Args.Labels,
|
||||||
|
description: $"This runner will have the following labels: 'self-hosted', '{VarUtil.OS}', '{VarUtil.OSArchitecture}' \nEnter any additional labels (ex. label-1,label-2):",
|
||||||
|
defaultValue: string.Empty,
|
||||||
|
validator: Validators.LabelsValidator,
|
||||||
|
isOptional: true);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(labels))
|
||||||
|
{
|
||||||
|
labelSet = labels.Split(',').Where(x => !string.IsNullOrEmpty(x)).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return labelSet;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Private helpers.
|
// Private helpers.
|
||||||
//
|
//
|
||||||
@@ -280,7 +299,8 @@ namespace GitHub.Runner.Listener
|
|||||||
string name,
|
string name,
|
||||||
string description,
|
string description,
|
||||||
string defaultValue,
|
string defaultValue,
|
||||||
Func<string, bool> validator)
|
Func<string, bool> validator,
|
||||||
|
bool isOptional = false)
|
||||||
{
|
{
|
||||||
// Check for the arg in the command line parser.
|
// Check for the arg in the command line parser.
|
||||||
ArgUtil.NotNull(validator, nameof(validator));
|
ArgUtil.NotNull(validator, nameof(validator));
|
||||||
@@ -311,7 +331,8 @@ namespace GitHub.Runner.Listener
|
|||||||
secret: Constants.Runner.CommandLine.Args.Secrets.Any(x => string.Equals(x, name, StringComparison.OrdinalIgnoreCase)),
|
secret: Constants.Runner.CommandLine.Args.Secrets.Any(x => string.Equals(x, name, StringComparison.OrdinalIgnoreCase)),
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
unattended: Unattended);
|
unattended: Unattended,
|
||||||
|
isOptional: isOptional);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetEnvArg(string name)
|
private string GetEnvArg(string name)
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
|
|
||||||
|
var userLabels = command.GetLabels();
|
||||||
|
_term.WriteLine();
|
||||||
|
|
||||||
var agents = await _runnerServer.GetAgentsAsync(runnerSettings.PoolId, runnerSettings.AgentName);
|
var agents = await _runnerServer.GetAgentsAsync(runnerSettings.PoolId, runnerSettings.AgentName);
|
||||||
Trace.Verbose("Returns {0} agents", agents.Count);
|
Trace.Verbose("Returns {0} agents", agents.Count);
|
||||||
agent = agents.FirstOrDefault();
|
agent = agents.FirstOrDefault();
|
||||||
@@ -175,7 +178,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
if (command.GetReplace())
|
if (command.GetReplace())
|
||||||
{
|
{
|
||||||
// Update existing agent with new PublicKey, agent version.
|
// Update existing agent with new PublicKey, agent version.
|
||||||
agent = UpdateExistingAgent(agent, publicKey);
|
agent = UpdateExistingAgent(agent, publicKey, userLabels);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -198,7 +201,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create a new agent.
|
// Create a new agent.
|
||||||
agent = CreateNewAgent(runnerSettings.AgentName, publicKey);
|
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -448,7 +451,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey)
|
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(agent, nameof(agent));
|
ArgUtil.NotNull(agent, nameof(agent));
|
||||||
agent.Authorization = new TaskAgentAuthorization
|
agent.Authorization = new TaskAgentAuthorization
|
||||||
@@ -456,18 +459,25 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
PublicKey = new TaskAgentPublicKey(publicKey.Exponent, publicKey.Modulus),
|
PublicKey = new TaskAgentPublicKey(publicKey.Exponent, publicKey.Modulus),
|
||||||
};
|
};
|
||||||
|
|
||||||
// update - update instead of delete so we don't lose labels etc...
|
// update should replace the existing labels
|
||||||
agent.Version = BuildConstants.RunnerPackage.Version;
|
agent.Version = BuildConstants.RunnerPackage.Version;
|
||||||
agent.OSDescription = RuntimeInformation.OSDescription;
|
agent.OSDescription = RuntimeInformation.OSDescription;
|
||||||
|
|
||||||
|
agent.Labels.Clear();
|
||||||
|
|
||||||
agent.Labels.Add("self-hosted");
|
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
||||||
agent.Labels.Add(VarUtil.OS);
|
agent.Labels.Add(new AgentLabel(VarUtil.OS, LabelType.System));
|
||||||
agent.Labels.Add(VarUtil.OSArchitecture);
|
agent.Labels.Add(new AgentLabel(VarUtil.OSArchitecture, LabelType.System));
|
||||||
|
|
||||||
|
foreach (var userLabel in userLabels)
|
||||||
|
{
|
||||||
|
agent.Labels.Add(new AgentLabel(userLabel, LabelType.User));
|
||||||
|
}
|
||||||
|
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey)
|
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels)
|
||||||
{
|
{
|
||||||
TaskAgent agent = new TaskAgent(agentName)
|
TaskAgent agent = new TaskAgent(agentName)
|
||||||
{
|
{
|
||||||
@@ -480,9 +490,14 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
OSDescription = RuntimeInformation.OSDescription,
|
OSDescription = RuntimeInformation.OSDescription,
|
||||||
};
|
};
|
||||||
|
|
||||||
agent.Labels.Add("self-hosted");
|
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
||||||
agent.Labels.Add(VarUtil.OS);
|
agent.Labels.Add(new AgentLabel(VarUtil.OS, LabelType.System));
|
||||||
agent.Labels.Add(VarUtil.OSArchitecture);
|
agent.Labels.Add(new AgentLabel(VarUtil.OSArchitecture, LabelType.System));
|
||||||
|
|
||||||
|
foreach (var userLabel in userLabels)
|
||||||
|
{
|
||||||
|
agent.Labels.Add(new AgentLabel(userLabel, LabelType.User));
|
||||||
|
}
|
||||||
|
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
@@ -511,7 +526,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
{
|
{
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("RemoteAuth", githubToken);
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("RemoteAuth", githubToken);
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.Add(HostContext.UserAgent);
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
|
||||||
var bodyObject = new Dictionary<string, string>()
|
var bodyObject = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
bool secret,
|
bool secret,
|
||||||
string defaultValue,
|
string defaultValue,
|
||||||
Func<String, bool> validator,
|
Func<String, bool> validator,
|
||||||
bool unattended);
|
bool unattended,
|
||||||
|
bool isOptional = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class PromptManager : RunnerService, IPromptManager
|
public sealed class PromptManager : RunnerService, IPromptManager
|
||||||
@@ -56,7 +57,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
bool secret,
|
bool secret,
|
||||||
string defaultValue,
|
string defaultValue,
|
||||||
Func<string, bool> validator,
|
Func<string, bool> validator,
|
||||||
bool unattended)
|
bool unattended,
|
||||||
|
bool isOptional = false)
|
||||||
{
|
{
|
||||||
Trace.Info(nameof(ReadValue));
|
Trace.Info(nameof(ReadValue));
|
||||||
ArgUtil.NotNull(validator, nameof(validator));
|
ArgUtil.NotNull(validator, nameof(validator));
|
||||||
@@ -70,6 +72,10 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
else if (isOptional)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise throw.
|
// Otherwise throw.
|
||||||
throw new Exception($"Invalid configuration provided for {argName}. Terminating unattended configuration.");
|
throw new Exception($"Invalid configuration provided for {argName}. Terminating unattended configuration.");
|
||||||
@@ -85,18 +91,28 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
_terminal.Write($"[press Enter for {defaultValue}] ");
|
_terminal.Write($"[press Enter for {defaultValue}] ");
|
||||||
}
|
}
|
||||||
|
else if (isOptional){
|
||||||
|
_terminal.Write($"[press Enter to skip] ");
|
||||||
|
}
|
||||||
|
|
||||||
// Read and trim the value.
|
// Read and trim the value.
|
||||||
value = secret ? _terminal.ReadSecret() : _terminal.ReadLine();
|
value = secret ? _terminal.ReadSecret() : _terminal.ReadLine();
|
||||||
value = value?.Trim() ?? string.Empty;
|
value = value?.Trim() ?? string.Empty;
|
||||||
|
|
||||||
// Return the default if not specified.
|
// Return the default if not specified.
|
||||||
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(defaultValue))
|
if (string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
Trace.Info($"Falling back to the default: '{defaultValue}'");
|
if (!string.IsNullOrEmpty(defaultValue))
|
||||||
return defaultValue;
|
{
|
||||||
|
Trace.Info($"Falling back to the default: '{defaultValue}'");
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
else if (isOptional)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the value if it is not empty and it is valid.
|
// Return the value if it is not empty and it is valid.
|
||||||
// Otherwise try the loop again.
|
// Otherwise try the loop again.
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrEmpty(value))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
|
|
||||||
@@ -46,6 +47,21 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
string.Equals(value, "N", StringComparison.CurrentCultureIgnoreCase);
|
string.Equals(value, "N", StringComparison.CurrentCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool LabelsValidator(string labels)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(labels))
|
||||||
|
{
|
||||||
|
var labelSet = labels.Split(',').Where(x => !string.IsNullOrEmpty(x)).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (labelSet.Any(x => x.Length > 256))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool NonEmptyValidator(string value)
|
public static bool NonEmptyValidator(string value)
|
||||||
{
|
{
|
||||||
return !string.IsNullOrEmpty(value);
|
return !string.IsNullOrEmpty(value);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using System.Linq;
|
|||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.WebApi.Jwt;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -86,15 +87,30 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var orchestrationId = string.Empty;
|
||||||
|
var systemConnection = jobRequestMessage.Resources.Endpoints.SingleOrDefault(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (systemConnection?.Authorization != null &&
|
||||||
|
systemConnection.Authorization.Parameters.TryGetValue("AccessToken", out var accessToken) &&
|
||||||
|
!string.IsNullOrEmpty(accessToken))
|
||||||
|
{
|
||||||
|
var jwt = JsonWebToken.Create(accessToken);
|
||||||
|
var claims = jwt.ExtractClaims();
|
||||||
|
orchestrationId = claims.FirstOrDefault(x => string.Equals(x.Type, "orchid", StringComparison.OrdinalIgnoreCase))?.Value;
|
||||||
|
if (!string.IsNullOrEmpty(orchestrationId))
|
||||||
|
{
|
||||||
|
Trace.Info($"Pull OrchestrationId {orchestrationId} from JWT claims");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WorkerDispatcher newDispatch = new WorkerDispatcher(jobRequestMessage.JobId, jobRequestMessage.RequestId);
|
WorkerDispatcher newDispatch = new WorkerDispatcher(jobRequestMessage.JobId, jobRequestMessage.RequestId);
|
||||||
if (runOnce)
|
if (runOnce)
|
||||||
{
|
{
|
||||||
Trace.Info("Start dispatcher for one time used runner.");
|
Trace.Info("Start dispatcher for one time used runner.");
|
||||||
newDispatch.WorkerDispatch = RunOnceAsync(jobRequestMessage, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
newDispatch.WorkerDispatch = RunOnceAsync(jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newDispatch.WorkerDispatch = RunAsync(jobRequestMessage, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
newDispatch.WorkerDispatch = RunAsync(jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
_jobInfos.TryAdd(newDispatch.JobId, newDispatch);
|
_jobInfos.TryAdd(newDispatch.JobId, newDispatch);
|
||||||
@@ -284,11 +300,11 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunOnceAsync(Pipelines.AgentJobRequestMessage message, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
private async Task RunOnceAsync(Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await RunAsync(message, previousJobDispatch, jobRequestCancellationToken, workerCancelTimeoutKillToken);
|
await RunAsync(message, orchestrationId, previousJobDispatch, jobRequestCancellationToken, workerCancelTimeoutKillToken);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -297,7 +313,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunAsync(Pipelines.AgentJobRequestMessage message, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
private async Task RunAsync(Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
||||||
{
|
{
|
||||||
Busy = true;
|
Busy = true;
|
||||||
try
|
try
|
||||||
@@ -328,7 +344,7 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
// start renew job request
|
// start renew job request
|
||||||
Trace.Info($"Start renew job request {requestId} for job {message.JobId}.");
|
Trace.Info($"Start renew job request {requestId} for job {message.JobId}.");
|
||||||
Task renewJobRequest = RenewJobRequestAsync(_poolId, requestId, lockToken, firstJobRequestRenewed, lockRenewalTokenSource.Token);
|
Task renewJobRequest = RenewJobRequestAsync(_poolId, requestId, lockToken, orchestrationId, firstJobRequestRenewed, lockRenewalTokenSource.Token);
|
||||||
|
|
||||||
// wait till first renew succeed or job request is canceled
|
// wait till first renew succeed or job request is canceled
|
||||||
// not even start worker if the first renew fail
|
// not even start worker if the first renew fail
|
||||||
@@ -607,7 +623,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RenewJobRequestAsync(int poolId, long requestId, Guid lockToken, TaskCompletionSource<int> firstJobRequestRenewed, CancellationToken token)
|
public async Task RenewJobRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId, TaskCompletionSource<int> firstJobRequestRenewed, CancellationToken token)
|
||||||
{
|
{
|
||||||
var runnerServer = HostContext.GetService<IRunnerServer>();
|
var runnerServer = HostContext.GetService<IRunnerServer>();
|
||||||
TaskAgentJobRequest request = null;
|
TaskAgentJobRequest request = null;
|
||||||
@@ -620,7 +636,7 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, token);
|
request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token);
|
||||||
|
|
||||||
Trace.Info($"Successfully renew job request {requestId}, job is valid till {request.LockedUntil.Value}");
|
Trace.Info($"Successfully renew job request {requestId}, job is valid till {request.LockedUntil.Value}");
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
VssUtil.InitializeVssClientSettings(HostContext.UserAgent, HostContext.WebProxy);
|
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
|
||||||
|
|
||||||
_inConfigStage = true;
|
_inConfigStage = true;
|
||||||
_completedCommand.Reset();
|
_completedCommand.Reset();
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ namespace GitHub.Runner.Sdk
|
|||||||
{
|
{
|
||||||
public static class VssUtil
|
public static class VssUtil
|
||||||
{
|
{
|
||||||
public static void InitializeVssClientSettings(ProductInfoHeaderValue additionalUserAgent, IWebProxy proxy)
|
public static void InitializeVssClientSettings(List<ProductInfoHeaderValue> additionalUserAgents, IWebProxy proxy)
|
||||||
{
|
{
|
||||||
var headerValues = new List<ProductInfoHeaderValue>();
|
var headerValues = new List<ProductInfoHeaderValue>();
|
||||||
headerValues.Add(additionalUserAgent);
|
headerValues.AddRange(additionalUserAgents);
|
||||||
headerValues.Add(new ProductInfoHeaderValue($"({RuntimeInformation.OSDescription.Trim()})"));
|
headerValues.Add(new ProductInfoHeaderValue($"({RuntimeInformation.OSDescription.Trim()})"));
|
||||||
|
|
||||||
if (VssClientHttpRequestSettings.Default.UserAgent != null && VssClientHttpRequestSettings.Default.UserAgent.Count > 0)
|
if (VssClientHttpRequestSettings.Default.UserAgent != null && VssClientHttpRequestSettings.Default.UserAgent.Count > 0)
|
||||||
|
|||||||
@@ -21,11 +21,24 @@ using PipelineTemplateConstants = GitHub.DistributedTask.Pipelines.ObjectTemplat
|
|||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
|
public class PrepareResult
|
||||||
|
{
|
||||||
|
public PrepareResult(List<JobExtensionRunner> containerSetupSteps, Dictionary<Guid, IActionRunner> preStepTracker)
|
||||||
|
{
|
||||||
|
this.ContainerSetupSteps = containerSetupSteps;
|
||||||
|
this.PreStepTracker = preStepTracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<JobExtensionRunner> ContainerSetupSteps { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<Guid, IActionRunner> PreStepTracker { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[ServiceLocator(Default = typeof(ActionManager))]
|
[ServiceLocator(Default = typeof(ActionManager))]
|
||||||
public interface IActionManager : IRunnerService
|
public interface IActionManager : IRunnerService
|
||||||
{
|
{
|
||||||
Dictionary<Guid, ContainerInfo> CachedActionContainers { get; }
|
Dictionary<Guid, ContainerInfo> CachedActionContainers { get; }
|
||||||
Task<List<JobExtensionRunner>> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps);
|
Task<PrepareResult> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps);
|
||||||
Definition LoadAction(IExecutionContext executionContext, Pipelines.ActionStep action);
|
Definition LoadAction(IExecutionContext executionContext, Pipelines.ActionStep action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +52,7 @@ namespace GitHub.Runner.Worker
|
|||||||
private readonly Dictionary<Guid, ContainerInfo> _cachedActionContainers = new Dictionary<Guid, ContainerInfo>();
|
private readonly Dictionary<Guid, ContainerInfo> _cachedActionContainers = new Dictionary<Guid, ContainerInfo>();
|
||||||
|
|
||||||
public Dictionary<Guid, ContainerInfo> CachedActionContainers => _cachedActionContainers;
|
public Dictionary<Guid, ContainerInfo> CachedActionContainers => _cachedActionContainers;
|
||||||
public async Task<List<JobExtensionRunner>> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps)
|
public async Task<PrepareResult> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
ArgUtil.NotNull(steps, nameof(steps));
|
ArgUtil.NotNull(steps, nameof(steps));
|
||||||
@@ -49,6 +62,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Dictionary<string, List<Guid>> imagesToBuild = new Dictionary<string, List<Guid>>(StringComparer.OrdinalIgnoreCase);
|
Dictionary<string, List<Guid>> imagesToBuild = new Dictionary<string, List<Guid>>(StringComparer.OrdinalIgnoreCase);
|
||||||
Dictionary<string, ActionContainer> imagesToBuildInfo = new Dictionary<string, ActionContainer>(StringComparer.OrdinalIgnoreCase);
|
Dictionary<string, ActionContainer> imagesToBuildInfo = new Dictionary<string, ActionContainer>(StringComparer.OrdinalIgnoreCase);
|
||||||
List<JobExtensionRunner> containerSetupSteps = new List<JobExtensionRunner>();
|
List<JobExtensionRunner> containerSetupSteps = new List<JobExtensionRunner>();
|
||||||
|
Dictionary<Guid, IActionRunner> preStepTracker = new Dictionary<Guid, IActionRunner>();
|
||||||
IEnumerable<Pipelines.ActionStep> actions = steps.OfType<Pipelines.ActionStep>();
|
IEnumerable<Pipelines.ActionStep> actions = steps.OfType<Pipelines.ActionStep>();
|
||||||
|
|
||||||
// TODO: Deprecate the PREVIEW_ACTION_TOKEN
|
// TODO: Deprecate the PREVIEW_ACTION_TOKEN
|
||||||
@@ -117,6 +131,22 @@ namespace GitHub.Runner.Worker
|
|||||||
imagesToBuildInfo[setupInfo.ActionRepository] = setupInfo;
|
imagesToBuildInfo[setupInfo.ActionRepository] = setupInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var repoAction = action.Reference as Pipelines.RepositoryPathReference;
|
||||||
|
if (repoAction.RepositoryType != Pipelines.PipelineConstants.SelfAlias)
|
||||||
|
{
|
||||||
|
var definition = LoadAction(executionContext, action);
|
||||||
|
if (definition.Data.Execution.HasPre)
|
||||||
|
{
|
||||||
|
var actionRunner = HostContext.CreateService<IActionRunner>();
|
||||||
|
actionRunner.Action = action;
|
||||||
|
actionRunner.Stage = ActionRunStage.Pre;
|
||||||
|
actionRunner.Condition = definition.Data.Execution.InitCondition;
|
||||||
|
|
||||||
|
Trace.Info($"Add 'pre' execution for {action.Id}");
|
||||||
|
preStepTracker[action.Id] = actionRunner;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +183,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return containerSetupSteps;
|
return new PrepareResult(containerSetupSteps, preStepTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Definition LoadAction(IExecutionContext executionContext, Pipelines.ActionStep action)
|
public Definition LoadAction(IExecutionContext executionContext, Pipelines.ActionStep action)
|
||||||
@@ -245,14 +275,19 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info($"Action container env: {StringUtil.ConvertToJson(containerAction.Environment)}.");
|
Trace.Info($"Action container env: {StringUtil.ConvertToJson(containerAction.Environment)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(containerAction.Pre))
|
||||||
|
{
|
||||||
|
Trace.Info($"Action container pre entrypoint: {containerAction.Pre}.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(containerAction.EntryPoint))
|
if (!string.IsNullOrEmpty(containerAction.EntryPoint))
|
||||||
{
|
{
|
||||||
Trace.Info($"Action container entrypoint: {containerAction.EntryPoint}.");
|
Trace.Info($"Action container entrypoint: {containerAction.EntryPoint}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(containerAction.Cleanup))
|
if (!string.IsNullOrEmpty(containerAction.Post))
|
||||||
{
|
{
|
||||||
Trace.Info($"Action container cleanup entrypoint: {containerAction.Cleanup}.");
|
Trace.Info($"Action container post entrypoint: {containerAction.Post}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CachedActionContainers.TryGetValue(action.Id, out var container))
|
if (CachedActionContainers.TryGetValue(action.Id, out var container))
|
||||||
@@ -264,8 +299,9 @@ namespace GitHub.Runner.Worker
|
|||||||
else if (definition.Data.Execution.ExecutionType == ActionExecutionType.NodeJS)
|
else if (definition.Data.Execution.ExecutionType == ActionExecutionType.NodeJS)
|
||||||
{
|
{
|
||||||
var nodeAction = definition.Data.Execution as NodeJSActionExecutionData;
|
var nodeAction = definition.Data.Execution as NodeJSActionExecutionData;
|
||||||
|
Trace.Info($"Action pre node.js file: {nodeAction.Pre ?? "N/A"}.");
|
||||||
Trace.Info($"Action node.js file: {nodeAction.Script}.");
|
Trace.Info($"Action node.js file: {nodeAction.Script}.");
|
||||||
Trace.Info($"Action cleanup node.js file: {nodeAction.Cleanup ?? "N/A"}.");
|
Trace.Info($"Action post node.js file: {nodeAction.Post ?? "N/A"}.");
|
||||||
}
|
}
|
||||||
else if (definition.Data.Execution.ExecutionType == ActionExecutionType.Plugin)
|
else if (definition.Data.Execution.ExecutionType == ActionExecutionType.Plugin)
|
||||||
{
|
{
|
||||||
@@ -281,7 +317,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(plugin.PostPluginTypeName))
|
if (!string.IsNullOrEmpty(plugin.PostPluginTypeName))
|
||||||
{
|
{
|
||||||
pluginAction.Cleanup = plugin.PostPluginTypeName;
|
pluginAction.Post = plugin.PostPluginTypeName;
|
||||||
Trace.Info($"Action cleanup plugin: {plugin.PluginTypeName}.");
|
Trace.Info($"Action cleanup plugin: {plugin.PluginTypeName}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -534,7 +570,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// Intentionally empty. Temporary for GHES alpha release, download from dotcom unauthenticated.
|
// Intentionally empty. Temporary for GHES alpha release, download from dotcom unauthenticated.
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.Add(HostContext.UserAgent);
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
using (var result = await httpClient.GetStreamAsync(archiveLink))
|
using (var result = await httpClient.GetStreamAsync(archiveLink))
|
||||||
{
|
{
|
||||||
await result.CopyToAsync(fs, _defaultCopyBufferSize, actionDownloadCancellation.Token);
|
await result.CopyToAsync(fs, _defaultCopyBufferSize, actionDownloadCancellation.Token);
|
||||||
@@ -788,7 +824,8 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
public override ActionExecutionType ExecutionType => ActionExecutionType.Container;
|
public override ActionExecutionType ExecutionType => ActionExecutionType.Container;
|
||||||
|
|
||||||
public override bool HasCleanup => !string.IsNullOrEmpty(Cleanup);
|
public override bool HasPre => !string.IsNullOrEmpty(Pre);
|
||||||
|
public override bool HasPost => !string.IsNullOrEmpty(Post);
|
||||||
|
|
||||||
public string Image { get; set; }
|
public string Image { get; set; }
|
||||||
|
|
||||||
@@ -798,51 +835,66 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public MappingToken Environment { get; set; }
|
public MappingToken Environment { get; set; }
|
||||||
|
|
||||||
public string Cleanup { get; set; }
|
public string Pre { get; set; }
|
||||||
|
|
||||||
|
public string Post { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class NodeJSActionExecutionData : ActionExecutionData
|
public sealed class NodeJSActionExecutionData : ActionExecutionData
|
||||||
{
|
{
|
||||||
public override ActionExecutionType ExecutionType => ActionExecutionType.NodeJS;
|
public override ActionExecutionType ExecutionType => ActionExecutionType.NodeJS;
|
||||||
|
|
||||||
public override bool HasCleanup => !string.IsNullOrEmpty(Cleanup);
|
public override bool HasPre => !string.IsNullOrEmpty(Pre);
|
||||||
|
public override bool HasPost => !string.IsNullOrEmpty(Post);
|
||||||
|
|
||||||
public string Script { get; set; }
|
public string Script { get; set; }
|
||||||
|
|
||||||
public string Cleanup { get; set; }
|
public string Pre { get; set; }
|
||||||
|
|
||||||
|
public string Post { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class PluginActionExecutionData : ActionExecutionData
|
public sealed class PluginActionExecutionData : ActionExecutionData
|
||||||
{
|
{
|
||||||
public override ActionExecutionType ExecutionType => ActionExecutionType.Plugin;
|
public override ActionExecutionType ExecutionType => ActionExecutionType.Plugin;
|
||||||
|
|
||||||
public override bool HasCleanup => !string.IsNullOrEmpty(Cleanup);
|
public override bool HasPre => false;
|
||||||
|
|
||||||
|
public override bool HasPost => !string.IsNullOrEmpty(Post);
|
||||||
|
|
||||||
public string Plugin { get; set; }
|
public string Plugin { get; set; }
|
||||||
|
|
||||||
public string Cleanup { get; set; }
|
public string Post { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ScriptActionExecutionData : ActionExecutionData
|
public sealed class ScriptActionExecutionData : ActionExecutionData
|
||||||
{
|
{
|
||||||
public override ActionExecutionType ExecutionType => ActionExecutionType.Script;
|
public override ActionExecutionType ExecutionType => ActionExecutionType.Script;
|
||||||
|
public override bool HasPre => false;
|
||||||
public override bool HasCleanup => false;
|
public override bool HasPost => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ActionExecutionData
|
public abstract class ActionExecutionData
|
||||||
{
|
{
|
||||||
|
private string _initCondition = $"{Constants.Expressions.Always}()";
|
||||||
private string _cleanupCondition = $"{Constants.Expressions.Always}()";
|
private string _cleanupCondition = $"{Constants.Expressions.Always}()";
|
||||||
|
|
||||||
public abstract ActionExecutionType ExecutionType { get; }
|
public abstract ActionExecutionType ExecutionType { get; }
|
||||||
|
|
||||||
public abstract bool HasCleanup { get; }
|
public abstract bool HasPre { get; }
|
||||||
|
public abstract bool HasPost { get; }
|
||||||
|
|
||||||
public string CleanupCondition
|
public string CleanupCondition
|
||||||
{
|
{
|
||||||
get { return _cleanupCondition; }
|
get { return _cleanupCondition; }
|
||||||
set { _cleanupCondition = value; }
|
set { _cleanupCondition = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string InitCondition
|
||||||
|
{
|
||||||
|
get { return _initCondition; }
|
||||||
|
set { _initCondition = value; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ContainerSetupInfo
|
public class ContainerSetupInfo
|
||||||
|
|||||||
@@ -305,6 +305,9 @@ namespace GitHub.Runner.Worker
|
|||||||
var envToken = default(MappingToken);
|
var envToken = default(MappingToken);
|
||||||
var mainToken = default(StringToken);
|
var mainToken = default(StringToken);
|
||||||
var pluginToken = default(StringToken);
|
var pluginToken = default(StringToken);
|
||||||
|
var preToken = default(StringToken);
|
||||||
|
var preEntrypointToken = default(StringToken);
|
||||||
|
var preIfToken = default(StringToken);
|
||||||
var postToken = default(StringToken);
|
var postToken = default(StringToken);
|
||||||
var postEntrypointToken = default(StringToken);
|
var postEntrypointToken = default(StringToken);
|
||||||
var postIfToken = default(StringToken);
|
var postIfToken = default(StringToken);
|
||||||
@@ -343,6 +346,15 @@ namespace GitHub.Runner.Worker
|
|||||||
case "post-if":
|
case "post-if":
|
||||||
postIfToken = run.Value.AssertString("post-if");
|
postIfToken = run.Value.AssertString("post-if");
|
||||||
break;
|
break;
|
||||||
|
case "pre":
|
||||||
|
preToken = run.Value.AssertString("pre");
|
||||||
|
break;
|
||||||
|
case "pre-entrypoint":
|
||||||
|
preEntrypointToken = run.Value.AssertString("pre-entrypoint");
|
||||||
|
break;
|
||||||
|
case "pre-if":
|
||||||
|
preIfToken = run.Value.AssertString("pre-if");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Trace.Info($"Ignore run property {runsKey}.");
|
Trace.Info($"Ignore run property {runsKey}.");
|
||||||
break;
|
break;
|
||||||
@@ -365,7 +377,9 @@ namespace GitHub.Runner.Worker
|
|||||||
Arguments = argsToken,
|
Arguments = argsToken,
|
||||||
EntryPoint = entrypointToken?.Value,
|
EntryPoint = entrypointToken?.Value,
|
||||||
Environment = envToken,
|
Environment = envToken,
|
||||||
Cleanup = postEntrypointToken?.Value,
|
Pre = preEntrypointToken?.Value,
|
||||||
|
InitCondition = preIfToken?.Value ?? "always()",
|
||||||
|
Post = postEntrypointToken?.Value,
|
||||||
CleanupCondition = postIfToken?.Value ?? "always()"
|
CleanupCondition = postIfToken?.Value ?? "always()"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -374,14 +388,16 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(mainToken?.Value))
|
if (string.IsNullOrEmpty(mainToken?.Value))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException($"Entry javascript fils is not provided.");
|
throw new ArgumentNullException($"Entry javascript file is not provided.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new NodeJSActionExecutionData()
|
return new NodeJSActionExecutionData()
|
||||||
{
|
{
|
||||||
Script = mainToken.Value,
|
Script = mainToken.Value,
|
||||||
Cleanup = postToken?.Value,
|
Pre = preToken?.Value,
|
||||||
|
InitCondition = preIfToken?.Value ?? "always()",
|
||||||
|
Post = postToken?.Value,
|
||||||
CleanupCondition = postIfToken?.Value ?? "always()"
|
CleanupCondition = postIfToken?.Value ?? "always()"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
public enum ActionRunStage
|
public enum ActionRunStage
|
||||||
{
|
{
|
||||||
|
Pre,
|
||||||
Main,
|
Main,
|
||||||
Post,
|
Post,
|
||||||
}
|
}
|
||||||
@@ -81,20 +82,18 @@ namespace GitHub.Runner.Worker
|
|||||||
ActionExecutionData handlerData = definition.Data?.Execution;
|
ActionExecutionData handlerData = definition.Data?.Execution;
|
||||||
ArgUtil.NotNull(handlerData, nameof(handlerData));
|
ArgUtil.NotNull(handlerData, nameof(handlerData));
|
||||||
|
|
||||||
|
if (handlerData.HasPre &&
|
||||||
|
Action.Reference is Pipelines.RepositoryPathReference repoAction &&
|
||||||
|
string.Equals(repoAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
ExecutionContext.Warning($"`pre` execution is not supported for local action from '{repoAction.Path}'");
|
||||||
|
}
|
||||||
|
|
||||||
// The action has post cleanup defined.
|
// The action has post cleanup defined.
|
||||||
// we need to create timeline record for them and add them to the step list that StepRunner is using
|
// we need to create timeline record for them and add them to the step list that StepRunner is using
|
||||||
if (handlerData.HasCleanup && Stage == ActionRunStage.Main)
|
if (handlerData.HasPost && (Stage == ActionRunStage.Pre || Stage == ActionRunStage.Main))
|
||||||
{
|
{
|
||||||
string postDisplayName = null;
|
string postDisplayName = $"Post {this.DisplayName}";
|
||||||
if (this.DisplayName.StartsWith(PipelineTemplateConstants.RunDisplayPrefix))
|
|
||||||
{
|
|
||||||
postDisplayName = $"Post {this.DisplayName.Substring(PipelineTemplateConstants.RunDisplayPrefix.Length)}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
postDisplayName = $"Post {this.DisplayName}";
|
|
||||||
}
|
|
||||||
|
|
||||||
var repositoryReference = Action.Reference as RepositoryPathReference;
|
var repositoryReference = Action.Reference as RepositoryPathReference;
|
||||||
var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}";
|
var pathString = string.IsNullOrEmpty(repositoryReference.Path) ? string.Empty : $"/{repositoryReference.Path}";
|
||||||
var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" :
|
var repoString = string.IsNullOrEmpty(repositoryReference.Ref) ? $"{repositoryReference.Name}{pathString}" :
|
||||||
@@ -108,7 +107,7 @@ namespace GitHub.Runner.Worker
|
|||||||
actionRunner.Condition = handlerData.CleanupCondition;
|
actionRunner.Condition = handlerData.CleanupCondition;
|
||||||
actionRunner.DisplayName = postDisplayName;
|
actionRunner.DisplayName = postDisplayName;
|
||||||
|
|
||||||
ExecutionContext.RegisterPostJobStep($"{actionRunner.Action.Name}_post", actionRunner);
|
ExecutionContext.RegisterPostJobStep(actionRunner);
|
||||||
}
|
}
|
||||||
|
|
||||||
IStepHost stepHost = HostContext.CreateService<IDefaultStepHost>();
|
IStepHost stepHost = HostContext.CreateService<IDefaultStepHost>();
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace GitHub.Runner.Worker
|
|||||||
data: data);
|
data: data);
|
||||||
|
|
||||||
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
||||||
executionContext.RegisterPostJobStep(nameof(StopContainersAsync), postJobStep);
|
executionContext.RegisterPostJobStep(postJobStep);
|
||||||
|
|
||||||
// Check whether we are inside a container.
|
// Check whether we are inside a container.
|
||||||
// Our container feature requires to map working directory from host to the container.
|
// Our container feature requires to map working directory from host to the container.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// others
|
// others
|
||||||
void ForceTaskComplete();
|
void ForceTaskComplete();
|
||||||
void RegisterPostJobStep(string refName, IStep step);
|
void RegisterPostJobStep(IStep step);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ExecutionContext : RunnerService, IExecutionContext
|
public sealed class ExecutionContext : RunnerService, IExecutionContext
|
||||||
@@ -161,6 +161,9 @@ namespace GitHub.Runner.Worker
|
|||||||
// Only job level ExecutionContext has PostJobSteps
|
// Only job level ExecutionContext has PostJobSteps
|
||||||
public Stack<IStep> PostJobSteps { get; private set; }
|
public Stack<IStep> PostJobSteps { get; private set; }
|
||||||
|
|
||||||
|
// Only job level ExecutionContext has StepsWithPostRegistered
|
||||||
|
public HashSet<Guid> StepsWithPostRegistered { get; private set; }
|
||||||
|
|
||||||
public bool EchoOnActionCommand { get; set; }
|
public bool EchoOnActionCommand { get; set; }
|
||||||
|
|
||||||
|
|
||||||
@@ -248,9 +251,15 @@ namespace GitHub.Runner.Worker
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterPostJobStep(string refName, IStep step)
|
public void RegisterPostJobStep(IStep step)
|
||||||
{
|
{
|
||||||
step.ExecutionContext = Root.CreatePostChild(step.DisplayName, refName, IntraActionState);
|
if (step is IActionRunner actionRunner && !Root.StepsWithPostRegistered.Add(actionRunner.Action.Id))
|
||||||
|
{
|
||||||
|
Trace.Info($"'post' of '{actionRunner.DisplayName}' already push to post step stack.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
step.ExecutionContext = Root.CreatePostChild(step.DisplayName, IntraActionState);
|
||||||
Root.PostJobSteps.Push(step);
|
Root.PostJobSteps.Push(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,6 +656,9 @@ namespace GitHub.Runner.Worker
|
|||||||
// PostJobSteps for job ExecutionContext
|
// PostJobSteps for job ExecutionContext
|
||||||
PostJobSteps = new Stack<IStep>();
|
PostJobSteps = new Stack<IStep>();
|
||||||
|
|
||||||
|
// StepsWithPostRegistered for job ExecutionContext
|
||||||
|
StepsWithPostRegistered = new HashSet<Guid>();
|
||||||
|
|
||||||
// Job timeline record.
|
// Job timeline record.
|
||||||
InitializeTimelineRecord(
|
InitializeTimelineRecord(
|
||||||
timelineId: message.Timeline.Id,
|
timelineId: message.Timeline.Id,
|
||||||
@@ -847,7 +859,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IExecutionContext CreatePostChild(string displayName, string refName, Dictionary<string, string> intraActionState)
|
private IExecutionContext CreatePostChild(string displayName, Dictionary<string, string> intraActionState)
|
||||||
{
|
{
|
||||||
if (!_expandedForPostJob)
|
if (!_expandedForPostJob)
|
||||||
{
|
{
|
||||||
@@ -856,7 +868,8 @@ namespace GitHub.Runner.Worker
|
|||||||
_childTimelineRecordOrder = _childTimelineRecordOrder * 2;
|
_childTimelineRecordOrder = _childTimelineRecordOrder * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateChild(Guid.NewGuid(), displayName, refName, null, null, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count);
|
var newGuid = Guid.NewGuid();
|
||||||
|
return CreateChild(newGuid, displayName, newGuid.ToString("N"), null, null, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,9 +82,13 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
container.ContainerEntryPoint = Inputs.GetValueOrDefault("entryPoint");
|
container.ContainerEntryPoint = Inputs.GetValueOrDefault("entryPoint");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (stage == ActionRunStage.Pre)
|
||||||
|
{
|
||||||
|
container.ContainerEntryPoint = Data.Pre;
|
||||||
|
}
|
||||||
else if (stage == ActionRunStage.Post)
|
else if (stage == ActionRunStage.Post)
|
||||||
{
|
{
|
||||||
container.ContainerEntryPoint = Data.Cleanup;
|
container.ContainerEntryPoint = Data.Post;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create inputs context for template evaluation
|
// create inputs context for template evaluation
|
||||||
|
|||||||
@@ -60,9 +60,13 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
target = Data.Script;
|
target = Data.Script;
|
||||||
}
|
}
|
||||||
|
else if (stage == ActionRunStage.Pre)
|
||||||
|
{
|
||||||
|
target = Data.Pre;
|
||||||
|
}
|
||||||
else if (stage == ActionRunStage.Post)
|
else if (stage == ActionRunStage.Post)
|
||||||
{
|
{
|
||||||
target = Data.Cleanup;
|
target = Data.Post;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgUtil.NotNullOrEmpty(target, nameof(target));
|
ArgUtil.NotNullOrEmpty(target, nameof(target));
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
else if (stage == ActionRunStage.Post)
|
else if (stage == ActionRunStage.Post)
|
||||||
{
|
{
|
||||||
plugin = Data.Cleanup;
|
plugin = Data.Post;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgUtil.NotNullOrEmpty(plugin, nameof(plugin));
|
ArgUtil.NotNullOrEmpty(plugin, nameof(plugin));
|
||||||
|
|||||||
@@ -259,6 +259,16 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
// dump out the command
|
// dump out the command
|
||||||
var fileName = isContainerStepHost ? shellCommand : commandPath;
|
var fileName = isContainerStepHost ? shellCommand : commandPath;
|
||||||
|
#if OS_OSX
|
||||||
|
if (Environment.ContainsKey("DYLD_INSERT_LIBRARIES")) // We don't check `isContainerStepHost` because we don't support container on macOS
|
||||||
|
{
|
||||||
|
// launch `node macOSRunInvoker.js shell args` instead of `shell args` to avoid macOS SIP remove `DYLD_INSERT_LIBRARIES` when launch process
|
||||||
|
string node12 = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
string macOSRunInvoker = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "macos-run-invoker.js");
|
||||||
|
arguments = $"\"{macOSRunInvoker.Replace("\"", "\\\"")}\" \"{fileName.Replace("\"", "\\\"")}\" {arguments}";
|
||||||
|
fileName = node12;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ExecutionContext.Debug($"{fileName} {arguments}");
|
ExecutionContext.Debug($"{fileName} {arguments}");
|
||||||
|
|
||||||
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
// try to resolve path inside container if the request path is part of the mount volume
|
// try to resolve path inside container if the request path is part of the mount volume
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
if (Container.MountVolumes.Exists(x => path.StartsWith(x.SourceVolumePath, StringComparison.OrdinalIgnoreCase)))
|
if (Container.MountVolumes.Exists(x => !string.IsNullOrEmpty(x.SourceVolumePath) && path.StartsWith(x.SourceVolumePath, StringComparison.OrdinalIgnoreCase)))
|
||||||
#else
|
#else
|
||||||
if (Container.MountVolumes.Exists(x => path.StartsWith(x.SourceVolumePath)))
|
if (Container.MountVolumes.Exists(x => !string.IsNullOrEmpty(x.SourceVolumePath) && path.StartsWith(x.SourceVolumePath)))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return Container.TranslateToContainerPath(path);
|
return Container.TranslateToContainerPath(path);
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ namespace GitHub.Runner.Worker
|
|||||||
// Download actions not already in the cache
|
// Download actions not already in the cache
|
||||||
Trace.Info("Downloading actions");
|
Trace.Info("Downloading actions");
|
||||||
var actionManager = HostContext.GetService<IActionManager>();
|
var actionManager = HostContext.GetService<IActionManager>();
|
||||||
var prepareSteps = await actionManager.PrepareActionsAsync(context, message.Steps);
|
var prepareResult = await actionManager.PrepareActionsAsync(context, message.Steps);
|
||||||
preJobSteps.AddRange(prepareSteps);
|
preJobSteps.AddRange(prepareResult.ContainerSetupSteps);
|
||||||
|
|
||||||
// Add start-container steps, record and stop-container steps
|
// Add start-container steps, record and stop-container steps
|
||||||
if (jobContext.Container != null || jobContext.ServiceContainers.Count > 0)
|
if (jobContext.Container != null || jobContext.ServiceContainers.Count > 0)
|
||||||
@@ -239,9 +239,23 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
actionRunner.TryEvaluateDisplayName(contextData, context);
|
actionRunner.TryEvaluateDisplayName(contextData, context);
|
||||||
jobSteps.Add(actionRunner);
|
jobSteps.Add(actionRunner);
|
||||||
|
|
||||||
|
if (prepareResult.PreStepTracker.TryGetValue(step.Id, out var preStep))
|
||||||
|
{
|
||||||
|
Trace.Info($"Adding pre-{action.DisplayName}.");
|
||||||
|
preStep.TryEvaluateDisplayName(contextData, context);
|
||||||
|
preStep.DisplayName = $"Pre {preStep.DisplayName}";
|
||||||
|
preJobSteps.Add(preStep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var intraActionStates = new Dictionary<Guid, Dictionary<string, string>>();
|
||||||
|
foreach (var preStep in prepareResult.PreStepTracker)
|
||||||
|
{
|
||||||
|
intraActionStates[preStep.Key] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
// Create execution context for pre-job steps
|
// Create execution context for pre-job steps
|
||||||
foreach (var step in preJobSteps)
|
foreach (var step in preJobSteps)
|
||||||
{
|
{
|
||||||
@@ -252,6 +266,12 @@ namespace GitHub.Runner.Worker
|
|||||||
Guid stepId = Guid.NewGuid();
|
Guid stepId = Guid.NewGuid();
|
||||||
extensionStep.ExecutionContext = jobContext.CreateChild(stepId, extensionStep.DisplayName, null, null, stepId.ToString("N"));
|
extensionStep.ExecutionContext = jobContext.CreateChild(stepId, extensionStep.DisplayName, null, null, stepId.ToString("N"));
|
||||||
}
|
}
|
||||||
|
else if (step is IActionRunner actionStep)
|
||||||
|
{
|
||||||
|
ArgUtil.NotNull(actionStep, step.DisplayName);
|
||||||
|
Guid stepId = Guid.NewGuid();
|
||||||
|
actionStep.ExecutionContext = jobContext.CreateChild(stepId, actionStep.DisplayName, stepId.ToString("N"), null, null, intraActionStates[actionStep.Action.Id]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create execution context for job steps
|
// Create execution context for job steps
|
||||||
@@ -260,7 +280,8 @@ namespace GitHub.Runner.Worker
|
|||||||
if (step is IActionRunner actionStep)
|
if (step is IActionRunner actionStep)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(actionStep, step.DisplayName);
|
ArgUtil.NotNull(actionStep, step.DisplayName);
|
||||||
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, actionStep.Action.ScopeName, actionStep.Action.ContextName);
|
intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState);
|
||||||
|
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, actionStep.Action.ScopeName, actionStep.Action.ContextName, intraActionState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// Validate args.
|
// Validate args.
|
||||||
ArgUtil.NotNullOrEmpty(pipeIn, nameof(pipeIn));
|
ArgUtil.NotNullOrEmpty(pipeIn, nameof(pipeIn));
|
||||||
ArgUtil.NotNullOrEmpty(pipeOut, nameof(pipeOut));
|
ArgUtil.NotNullOrEmpty(pipeOut, nameof(pipeOut));
|
||||||
VssUtil.InitializeVssClientSettings(HostContext.UserAgent, HostContext.WebProxy);
|
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
|
||||||
var jobRunner = HostContext.CreateService<IJobRunner>();
|
var jobRunner = HostContext.CreateService<IJobRunner>();
|
||||||
|
|
||||||
using (var channel = HostContext.CreateService<IProcessChannel>())
|
using (var channel = HostContext.CreateService<IProcessChannel>())
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"entrypoint": "non-empty-string",
|
"entrypoint": "non-empty-string",
|
||||||
"args": "container-runs-args",
|
"args": "container-runs-args",
|
||||||
"env": "container-runs-env",
|
"env": "container-runs-env",
|
||||||
|
"pre-entrypoint": "non-empty-string",
|
||||||
|
"pre-if": "non-empty-string",
|
||||||
"post-entrypoint": "non-empty-string",
|
"post-entrypoint": "non-empty-string",
|
||||||
"post-if": "non-empty-string"
|
"post-if": "non-empty-string"
|
||||||
}
|
}
|
||||||
@@ -67,6 +69,8 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"using": "non-empty-string",
|
"using": "non-empty-string",
|
||||||
"main": "non-empty-string",
|
"main": "non-empty-string",
|
||||||
|
"pre": "non-empty-string",
|
||||||
|
"pre-if": "non-empty-string",
|
||||||
"post": "non-empty-string",
|
"post": "non-empty-string",
|
||||||
"post-if": "non-empty-string"
|
"post-if": "non-empty-string"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 2),
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken,
|
cancellationToken: cancellationToken,
|
||||||
content: content);
|
content: content);
|
||||||
@@ -109,7 +109,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 2),
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken).ConfigureAwait(false))
|
cancellationToken: cancellationToken).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
@@ -164,7 +164,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 2),
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
@@ -227,7 +227,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 2),
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
@@ -257,7 +257,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 2),
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken,
|
cancellationToken: cancellationToken,
|
||||||
content: content);
|
content: content);
|
||||||
@@ -287,7 +287,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 2),
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken,
|
cancellationToken: cancellationToken,
|
||||||
content: content);
|
content: content);
|
||||||
|
|||||||
59
src/Sdk/DTWebApi/WebApi/AgentLabel.cs
Normal file
59
src/Sdk/DTWebApi/WebApi/AgentLabel.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace GitHub.DistributedTask.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public class AgentLabel
|
||||||
|
{
|
||||||
|
[JsonConstructor]
|
||||||
|
public AgentLabel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AgentLabel(string name)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
this.Type = LabelType.System;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AgentLabel(string name, LabelType type)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
this.Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AgentLabel(AgentLabel labelToBeCloned)
|
||||||
|
{
|
||||||
|
this.Id = labelToBeCloned.Id;
|
||||||
|
this.Name = labelToBeCloned.Name;
|
||||||
|
this.Type = labelToBeCloned.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember]
|
||||||
|
public int Id
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember]
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember]
|
||||||
|
public LabelType Type
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AgentLabel Clone()
|
||||||
|
{
|
||||||
|
return new AgentLabel(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/Sdk/DTWebApi/WebApi/LabelType.cs
Normal file
14
src/Sdk/DTWebApi/WebApi/LabelType.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace GitHub.DistributedTask.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public enum LabelType
|
||||||
|
{
|
||||||
|
[EnumMember]
|
||||||
|
System = 0,
|
||||||
|
|
||||||
|
[EnumMember]
|
||||||
|
User = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
|
|
||||||
if (agentToBeCloned.m_labels != null && agentToBeCloned.m_labels.Count > 0)
|
if (agentToBeCloned.m_labels != null && agentToBeCloned.m_labels.Count > 0)
|
||||||
{
|
{
|
||||||
m_labels = new HashSet<string>(agentToBeCloned.m_labels, StringComparer.OrdinalIgnoreCase);
|
m_labels = new HashSet<AgentLabel>(agentToBeCloned.m_labels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,13 +118,13 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The labels of the runner
|
/// The labels of the runner
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISet<string> Labels
|
public ISet<AgentLabel> Labels
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_labels == null)
|
if (m_labels == null)
|
||||||
{
|
{
|
||||||
m_labels = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
m_labels = new HashSet<AgentLabel>();
|
||||||
}
|
}
|
||||||
return m_labels;
|
return m_labels;
|
||||||
}
|
}
|
||||||
@@ -164,6 +164,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
private PropertiesCollection m_properties;
|
private PropertiesCollection m_properties;
|
||||||
|
|
||||||
[DataMember(IsRequired = false, EmitDefaultValue = false, Name = "Labels")]
|
[DataMember(IsRequired = false, EmitDefaultValue = false, Name = "Labels")]
|
||||||
private HashSet<string> m_labels;
|
private HashSet<AgentLabel> m_labels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
Int64 requestId,
|
Int64 requestId,
|
||||||
Guid lockToken,
|
Guid lockToken,
|
||||||
DateTime? expiresOn = null,
|
DateTime? expiresOn = null,
|
||||||
|
string orchestrationId = null,
|
||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
@@ -104,7 +105,30 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
LockedUntil = expiresOn,
|
LockedUntil = expiresOn,
|
||||||
};
|
};
|
||||||
|
|
||||||
return UpdateAgentRequestAsync(poolId, requestId, lockToken, request, userState, cancellationToken);
|
var additionalHeaders = new Dictionary<string, string>();
|
||||||
|
if (!string.IsNullOrEmpty(orchestrationId))
|
||||||
|
{
|
||||||
|
additionalHeaders["X-VSS-OrchestrationId"] = orchestrationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpMethod httpMethod = new HttpMethod("PATCH");
|
||||||
|
Guid locationId = new Guid("fc825784-c92a-4299-9221-998a02d1b54f");
|
||||||
|
object routeValues = new { poolId = poolId, requestId = requestId };
|
||||||
|
HttpContent content = new ObjectContent<TaskAgentJobRequest>(request, new VssJsonMediaTypeFormatter(true));
|
||||||
|
|
||||||
|
List<KeyValuePair<string, string>> queryParams = new List<KeyValuePair<string, string>>();
|
||||||
|
queryParams.Add("lockToken", lockToken.ToString());
|
||||||
|
|
||||||
|
return SendAsync<TaskAgentJobRequest>(
|
||||||
|
httpMethod,
|
||||||
|
additionalHeaders,
|
||||||
|
locationId,
|
||||||
|
routeValues: routeValues,
|
||||||
|
version: new ApiResourceVersion(5.1, 1),
|
||||||
|
queryParameters: queryParams,
|
||||||
|
userState: userState,
|
||||||
|
cancellationToken: cancellationToken,
|
||||||
|
content: content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAgent> ReplaceAgentAsync(
|
public Task<TaskAgent> ReplaceAgentAsync(
|
||||||
@@ -171,5 +195,5 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly ApiResourceVersion m_currentApiVersion = new ApiResourceVersion(3.0, 1);
|
private readonly ApiResourceVersion m_currentApiVersion = new ApiResourceVersion(3.0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ namespace GitHub.Services.WebApi.Jwt
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IEnumerable<Claim> ExtractClaims(this JsonWebToken token)
|
public static IEnumerable<Claim> ExtractClaims(this JsonWebToken token)
|
||||||
{
|
{
|
||||||
ArgumentUtility.CheckForNull(token, nameof(token));
|
ArgumentUtility.CheckForNull(token, nameof(token));
|
||||||
|
|
||||||
|
|||||||
@@ -317,7 +317,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
Environment.MachineName, // defaultValue
|
Environment.MachineName, // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
true)) // unattended
|
true, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some runner");
|
.Returns("some runner");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -344,7 +345,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
Environment.MachineName, // defaultValue
|
Environment.MachineName, // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some runner");
|
.Returns("some runner");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -371,7 +373,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
"some default auth", // defaultValue
|
"some default auth", // defaultValue
|
||||||
Validators.AuthSchemeValidator, // validator
|
Validators.AuthSchemeValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some auth");
|
.Returns("some auth");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -398,7 +401,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
true, // secret
|
true, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some token");
|
.Returns("some token");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -475,7 +479,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
true, // secret
|
true, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some token");
|
.Returns("some token");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -502,7 +507,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
true, // secret
|
true, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some token");
|
.Returns("some token");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -529,7 +535,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.ServerUrlValidator, // validator
|
Validators.ServerUrlValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some url");
|
.Returns("some url");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -556,7 +563,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
"some default account", // defaultValue
|
"some default account", // defaultValue
|
||||||
Validators.NTAccountValidator, // validator
|
Validators.NTAccountValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some windows logon account");
|
.Returns("some windows logon account");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -584,7 +592,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
true, // secret
|
true, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some windows logon password");
|
.Returns("some windows logon password");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -611,7 +620,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
"_work", // defaultValue
|
"_work", // defaultValue
|
||||||
Validators.NonEmptyValidator, // validator
|
Validators.NonEmptyValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some work");
|
.Returns("some work");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -640,7 +650,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.ServerUrlValidator, // validator
|
Validators.ServerUrlValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some url");
|
.Returns("some url");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
@@ -669,7 +680,8 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
false, // secret
|
false, // secret
|
||||||
string.Empty, // defaultValue
|
string.Empty, // defaultValue
|
||||||
Validators.ServerUrlValidator, // validator
|
Validators.ServerUrlValidator, // validator
|
||||||
false)) // unattended
|
false, // unattended
|
||||||
|
false)) // isOptional
|
||||||
.Returns("some url");
|
.Returns("some url");
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
|
|||||||
@@ -145,6 +145,8 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
IConfigurationManager configManager = new ConfigurationManager();
|
IConfigurationManager configManager = new ConfigurationManager();
|
||||||
configManager.Initialize(tc);
|
configManager.Initialize(tc);
|
||||||
|
|
||||||
|
var userLabels = "userlabel1,userlabel2";
|
||||||
|
|
||||||
trace.Info("Preparing command line arguments");
|
trace.Info("Preparing command line arguments");
|
||||||
var command = new CommandSettings(
|
var command = new CommandSettings(
|
||||||
tc,
|
tc,
|
||||||
@@ -156,7 +158,8 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
"--pool", _expectedPoolName,
|
"--pool", _expectedPoolName,
|
||||||
"--work", _expectedWorkFolder,
|
"--work", _expectedWorkFolder,
|
||||||
"--auth", _expectedAuthType,
|
"--auth", _expectedAuthType,
|
||||||
"--token", _expectedToken
|
"--token", _expectedToken,
|
||||||
|
"--labels", userLabels
|
||||||
});
|
});
|
||||||
trace.Info("Constructed.");
|
trace.Info("Constructed.");
|
||||||
_store.Setup(x => x.IsConfigured()).Returns(false);
|
_store.Setup(x => x.IsConfigured()).Returns(false);
|
||||||
@@ -178,7 +181,10 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
||||||
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
||||||
|
|
||||||
_runnerServer.Verify(x => x.AddAgentAsync(It.IsAny<int>(), It.Is<TaskAgent>(a => a.Labels.Contains("self-hosted") && a.Labels.Contains(VarUtil.OS) && a.Labels.Contains(VarUtil.OSArchitecture))), Times.Once);
|
var expectedLabels = new List<string>() { "self-hosted", VarUtil.OS, VarUtil.OSArchitecture};
|
||||||
|
expectedLabels.AddRange(userLabels.Split(",").ToList());
|
||||||
|
|
||||||
|
_runnerServer.Verify(x => x.AddAgentAsync(It.IsAny<int>(), It.Is<TaskAgent>(a => a.Labels.Select(x => x.Name).ToHashSet().SetEquals(expectedLabels))), Times.Once);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
Assert.NotNull(sessionIdProperty);
|
Assert.NotNull(sessionIdProperty);
|
||||||
sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
|
sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
|
||||||
|
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request));
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request));
|
||||||
|
|
||||||
_runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest()));
|
_runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest()));
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
||||||
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(() =>
|
.Returns(() =>
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
@@ -139,10 +139,10 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var jobDispatcher = new JobDispatcher();
|
var jobDispatcher = new JobDispatcher();
|
||||||
jobDispatcher.Initialize(hc);
|
jobDispatcher.Initialize(hc);
|
||||||
|
|
||||||
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
|
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);
|
||||||
|
|
||||||
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully);
|
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully);
|
||||||
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
||||||
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(() =>
|
.Returns(() =>
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
@@ -197,11 +197,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var jobDispatcher = new JobDispatcher();
|
var jobDispatcher = new JobDispatcher();
|
||||||
jobDispatcher.Initialize(hc);
|
jobDispatcher.Initialize(hc);
|
||||||
|
|
||||||
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
|
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);
|
||||||
|
|
||||||
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
||||||
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
||||||
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
||||||
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(() =>
|
.Returns(() =>
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
@@ -256,11 +256,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var jobDispatcher = new JobDispatcher();
|
var jobDispatcher = new JobDispatcher();
|
||||||
jobDispatcher.Initialize(hc);
|
jobDispatcher.Initialize(hc);
|
||||||
|
|
||||||
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
|
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);
|
||||||
|
|
||||||
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
||||||
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
||||||
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
||||||
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(() =>
|
.Returns(() =>
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
@@ -315,11 +315,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var jobDispatcher = new JobDispatcher();
|
var jobDispatcher = new JobDispatcher();
|
||||||
jobDispatcher.Initialize(hc);
|
jobDispatcher.Initialize(hc);
|
||||||
|
|
||||||
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
|
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);
|
||||||
|
|
||||||
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
||||||
Assert.True(cancellationTokenSource.IsCancellationRequested);
|
Assert.True(cancellationTokenSource.IsCancellationRequested);
|
||||||
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(8));
|
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(8));
|
||||||
_runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3));
|
_runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3));
|
||||||
_runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Once);
|
_runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Once);
|
||||||
}
|
}
|
||||||
@@ -349,7 +349,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
||||||
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(() =>
|
.Returns(() =>
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
@@ -372,11 +372,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var jobDispatcher = new JobDispatcher();
|
var jobDispatcher = new JobDispatcher();
|
||||||
jobDispatcher.Initialize(hc);
|
jobDispatcher.Initialize(hc);
|
||||||
|
|
||||||
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
|
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);
|
||||||
|
|
||||||
Assert.False(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should failed.");
|
Assert.False(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should failed.");
|
||||||
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
||||||
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(6));
|
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +404,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
|
||||||
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(() =>
|
.Returns(() =>
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
@@ -436,11 +436,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var jobDispatcher = new JobDispatcher();
|
var jobDispatcher = new JobDispatcher();
|
||||||
jobDispatcher.Initialize(hc);
|
jobDispatcher.Initialize(hc);
|
||||||
|
|
||||||
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
|
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, Guid.NewGuid().ToString(), firstJobRequestRenewed, cancellationTokenSource.Token);
|
||||||
|
|
||||||
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
|
||||||
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
Assert.False(cancellationTokenSource.IsCancellationRequested);
|
||||||
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
_runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
|
||||||
_runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3));
|
_runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3));
|
||||||
_runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Never);
|
_runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Never);
|
||||||
}
|
}
|
||||||
@@ -481,7 +481,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
Assert.NotNull(sessionIdProperty);
|
Assert.NotNull(sessionIdProperty);
|
||||||
sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
|
sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
|
||||||
|
|
||||||
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request));
|
_runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request));
|
||||||
|
|
||||||
_runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest()));
|
_runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest()));
|
||||||
|
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_settings.AgentId))
|
_settings.AgentId))
|
||||||
.Returns(async () =>
|
.Returns(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(10);
|
await Task.Delay(100);
|
||||||
return "https://t.server";
|
return "https://t.server";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProductInfoHeaderValue UserAgent => new ProductInfoHeaderValue("L0Test", "0.0");
|
public List<ProductInfoHeaderValue> UserAgents => new List<ProductInfoHeaderValue>() { new ProductInfoHeaderValue("L0Test", "0.0") };
|
||||||
|
|
||||||
public RunnerWebProxy WebProxy => new RunnerWebProxy();
|
public RunnerWebProxy WebProxy => new RunnerWebProxy();
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
@@ -217,7 +217,7 @@ runs:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.True(steps.Count == 0);
|
Assert.True(steps.Count == 0);
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ runs:
|
|||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfile");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfile");
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
||||||
Assert.Equal(Path.Combine(actionDir, "Dockerfile"), (steps[0].Data as ContainerSetupInfo).Container.Dockerfile);
|
Assert.Equal(Path.Combine(actionDir, "Dockerfile"), (steps[0].Data as ContainerSetupInfo).Container.Dockerfile);
|
||||||
@@ -296,7 +296,7 @@ runs:
|
|||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath");
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
||||||
@@ -335,7 +335,7 @@ runs:
|
|||||||
|
|
||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithdockerfileinrelativepath");
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
||||||
@@ -375,7 +375,7 @@ runs:
|
|||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionfile_DockerfileRelativePath");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionfile_DockerfileRelativePath");
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
||||||
@@ -415,7 +415,7 @@ runs:
|
|||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionfile_DockerHubImage");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionfile_DockerHubImage");
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
Assert.Equal("ubuntu:18.04", (steps[0].Data as ContainerSetupInfo).Container.Image);
|
Assert.Equal("ubuntu:18.04", (steps[0].Data as ContainerSetupInfo).Container.Image);
|
||||||
@@ -454,7 +454,7 @@ runs:
|
|||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionYamlFile_DockerHubImage");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "RepositoryActionWithActionYamlFile_DockerHubImage");
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId);
|
Assert.Equal((steps[0].Data as ContainerSetupInfo).StepIds[0], actionId);
|
||||||
Assert.Equal("ubuntu:18.04", (steps[0].Data as ContainerSetupInfo).Container.Image);
|
Assert.Equal("ubuntu:18.04", (steps[0].Data as ContainerSetupInfo).Container.Image);
|
||||||
@@ -493,7 +493,7 @@ runs:
|
|||||||
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithactionfileanddockerfile");
|
var actionDir = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang", "runner_L0", "repositoryactionwithactionfileanddockerfile");
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
Assert.Equal(actionDir, (steps[0].Data as ContainerSetupInfo).Container.WorkingDirectory);
|
||||||
@@ -610,7 +610,7 @@ runs:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Equal(actionId1, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
Assert.Equal(actionId1, (steps[0].Data as ContainerSetupInfo).StepIds[0]);
|
||||||
@@ -671,7 +671,7 @@ runs:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var steps = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
// node.js based action doesn't need any extra steps to build/pull containers.
|
// node.js based action doesn't need any extra steps to build/pull containers.
|
||||||
Assert.True(steps.Count == 0);
|
Assert.True(steps.Count == 0);
|
||||||
@@ -682,6 +682,104 @@ runs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void PrepareActions_RepositoryActionWithInvalidWrapperActionfile_Node()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
var actionId = Guid.NewGuid();
|
||||||
|
var actions = new List<Pipelines.ActionStep>
|
||||||
|
{
|
||||||
|
new Pipelines.ActionStep()
|
||||||
|
{
|
||||||
|
Name = "action",
|
||||||
|
Id = actionId,
|
||||||
|
Reference = new Pipelines.RepositoryPathReference()
|
||||||
|
{
|
||||||
|
Name = "TingluoHuang/runner_L0",
|
||||||
|
Ref = "RepositoryActionWithInvalidWrapperActionfile_Node",
|
||||||
|
RepositoryType = "GitHub"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Act
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
var traceFile = Path.GetTempFileName();
|
||||||
|
File.Copy(_hc.TraceFileName, traceFile, true);
|
||||||
|
Assert.Contains("Entry javascript file is not provided.", File.ReadAllText(traceFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void PrepareActions_RepositoryActionWithWrapperActionfile_PreSteps()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
_hc.EnqueueInstance<IActionRunner>(new Mock<IActionRunner>().Object);
|
||||||
|
_hc.EnqueueInstance<IActionRunner>(new Mock<IActionRunner>().Object);
|
||||||
|
|
||||||
|
var actionId1 = Guid.NewGuid();
|
||||||
|
var actionId2 = Guid.NewGuid();
|
||||||
|
_hc.GetTrace().Info(actionId1);
|
||||||
|
_hc.GetTrace().Info(actionId2);
|
||||||
|
var actions = new List<Pipelines.ActionStep>
|
||||||
|
{
|
||||||
|
new Pipelines.ActionStep()
|
||||||
|
{
|
||||||
|
Name = "action1",
|
||||||
|
Id = actionId1,
|
||||||
|
Reference = new Pipelines.RepositoryPathReference()
|
||||||
|
{
|
||||||
|
Name = "TingluoHuang/runner_L0",
|
||||||
|
Ref = "RepositoryActionWithWrapperActionfile_Node",
|
||||||
|
RepositoryType = "GitHub"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Pipelines.ActionStep()
|
||||||
|
{
|
||||||
|
Name = "action2",
|
||||||
|
Id = actionId2,
|
||||||
|
Reference = new Pipelines.RepositoryPathReference()
|
||||||
|
{
|
||||||
|
Name = "TingluoHuang/runner_L0",
|
||||||
|
Ref = "RepositoryActionWithWrapperActionfile_Docker",
|
||||||
|
RepositoryType = "GitHub"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var preResult = await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
||||||
|
Assert.Equal(2, preResult.PreStepTracker.Count);
|
||||||
|
Assert.NotNull(preResult.PreStepTracker[actionId1]);
|
||||||
|
Assert.NotNull(preResult.PreStepTracker[actionId2]);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -1426,7 +1524,7 @@ runs:
|
|||||||
|
|
||||||
Assert.NotNull((definition.Data.Execution as NodeJSActionExecutionData));
|
Assert.NotNull((definition.Data.Execution as NodeJSActionExecutionData));
|
||||||
Assert.Equal("task.js", (definition.Data.Execution as NodeJSActionExecutionData).Script);
|
Assert.Equal("task.js", (definition.Data.Execution as NodeJSActionExecutionData).Script);
|
||||||
Assert.Equal("cleanup.js", (definition.Data.Execution as NodeJSActionExecutionData).Cleanup);
|
Assert.Equal("cleanup.js", (definition.Data.Execution as NodeJSActionExecutionData).Post);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -1506,7 +1604,7 @@ runs:
|
|||||||
Assert.NotNull((definition.Data.Execution as ContainerActionExecutionData)); // execution.Node
|
Assert.NotNull((definition.Data.Execution as ContainerActionExecutionData)); // execution.Node
|
||||||
Assert.Equal("image:1234", (definition.Data.Execution as ContainerActionExecutionData).Image);
|
Assert.Equal("image:1234", (definition.Data.Execution as ContainerActionExecutionData).Image);
|
||||||
Assert.Equal("main.sh", (definition.Data.Execution as ContainerActionExecutionData).EntryPoint);
|
Assert.Equal("main.sh", (definition.Data.Execution as ContainerActionExecutionData).EntryPoint);
|
||||||
Assert.Equal("cleanup.sh", (definition.Data.Execution as ContainerActionExecutionData).Cleanup);
|
Assert.Equal("cleanup.sh", (definition.Data.Execution as ContainerActionExecutionData).Post);
|
||||||
|
|
||||||
foreach (var arg in (definition.Data.Execution as ContainerActionExecutionData).Arguments)
|
foreach (var arg in (definition.Data.Execution as ContainerActionExecutionData).Arguments)
|
||||||
{
|
{
|
||||||
@@ -1595,7 +1693,7 @@ runs:
|
|||||||
|
|
||||||
Assert.NotNull((definition.Data.Execution as PluginActionExecutionData));
|
Assert.NotNull((definition.Data.Execution as PluginActionExecutionData));
|
||||||
Assert.Equal("plugin.class, plugin", (definition.Data.Execution as PluginActionExecutionData).Plugin);
|
Assert.Equal("plugin.class, plugin", (definition.Data.Execution as PluginActionExecutionData).Plugin);
|
||||||
Assert.Equal("plugin.cleanup, plugin", (definition.Data.Execution as PluginActionExecutionData).Cleanup);
|
Assert.Equal("plugin.cleanup, plugin", (definition.Data.Execution as PluginActionExecutionData).Post);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,6 +65,52 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void Load_ContainerAction_Dockerfile_Pre()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
var actionManifest = new ActionManifestManager();
|
||||||
|
actionManifest.Initialize(_hc);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = actionManifest.Load(_ec.Object, Path.Combine(TestUtil.GetTestDataPath(), "dockerfileaction_init.yml"));
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
|
||||||
|
Assert.Equal("Hello World", result.Name);
|
||||||
|
Assert.Equal("Greet the world and record the time", result.Description);
|
||||||
|
Assert.Equal(2, result.Inputs.Count);
|
||||||
|
Assert.Equal("greeting", result.Inputs[0].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("Hello", result.Inputs[0].Value.AssertString("value").Value);
|
||||||
|
Assert.Equal("entryPoint", result.Inputs[1].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("", result.Inputs[1].Value.AssertString("value").Value);
|
||||||
|
|
||||||
|
Assert.Equal(ActionExecutionType.Container, result.Execution.ExecutionType);
|
||||||
|
|
||||||
|
var containerAction = result.Execution as ContainerActionExecutionData;
|
||||||
|
|
||||||
|
Assert.Equal("Dockerfile", containerAction.Image);
|
||||||
|
Assert.Equal("main.sh", containerAction.EntryPoint);
|
||||||
|
Assert.Equal("init.sh", containerAction.Pre);
|
||||||
|
Assert.Equal("success()", containerAction.InitCondition);
|
||||||
|
Assert.Equal("bzz", containerAction.Arguments[0].ToString());
|
||||||
|
Assert.Equal("Token", containerAction.Environment[0].Key.ToString());
|
||||||
|
Assert.Equal("foo", containerAction.Environment[0].Value.ToString());
|
||||||
|
Assert.Equal("Url", containerAction.Environment[1].Key.ToString());
|
||||||
|
Assert.Equal("bar", containerAction.Environment[1].Value.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -97,7 +143,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal("Dockerfile", containerAction.Image);
|
Assert.Equal("Dockerfile", containerAction.Image);
|
||||||
Assert.Equal("main.sh", containerAction.EntryPoint);
|
Assert.Equal("main.sh", containerAction.EntryPoint);
|
||||||
Assert.Equal("cleanup.sh", containerAction.Cleanup);
|
Assert.Equal("cleanup.sh", containerAction.Post);
|
||||||
Assert.Equal("failure()", containerAction.CleanupCondition);
|
Assert.Equal("failure()", containerAction.CleanupCondition);
|
||||||
Assert.Equal("bzz", containerAction.Arguments[0].ToString());
|
Assert.Equal("bzz", containerAction.Arguments[0].ToString());
|
||||||
Assert.Equal("Token", containerAction.Environment[0].Key.ToString());
|
Assert.Equal("Token", containerAction.Environment[0].Key.ToString());
|
||||||
@@ -111,6 +157,52 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void Load_ContainerAction_Dockerfile_Pre_DefaultCondition()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
var actionManifest = new ActionManifestManager();
|
||||||
|
actionManifest.Initialize(_hc);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = actionManifest.Load(_ec.Object, Path.Combine(TestUtil.GetTestDataPath(), "dockerfileaction_init_default.yml"));
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
|
||||||
|
Assert.Equal("Hello World", result.Name);
|
||||||
|
Assert.Equal("Greet the world and record the time", result.Description);
|
||||||
|
Assert.Equal(2, result.Inputs.Count);
|
||||||
|
Assert.Equal("greeting", result.Inputs[0].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("Hello", result.Inputs[0].Value.AssertString("value").Value);
|
||||||
|
Assert.Equal("entryPoint", result.Inputs[1].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("", result.Inputs[1].Value.AssertString("value").Value);
|
||||||
|
|
||||||
|
Assert.Equal(ActionExecutionType.Container, result.Execution.ExecutionType);
|
||||||
|
|
||||||
|
var containerAction = result.Execution as ContainerActionExecutionData;
|
||||||
|
|
||||||
|
Assert.Equal("Dockerfile", containerAction.Image);
|
||||||
|
Assert.Equal("main.sh", containerAction.EntryPoint);
|
||||||
|
Assert.Equal("init.sh", containerAction.Pre);
|
||||||
|
Assert.Equal("always()", containerAction.InitCondition);
|
||||||
|
Assert.Equal("bzz", containerAction.Arguments[0].ToString());
|
||||||
|
Assert.Equal("Token", containerAction.Environment[0].Key.ToString());
|
||||||
|
Assert.Equal("foo", containerAction.Environment[0].Value.ToString());
|
||||||
|
Assert.Equal("Url", containerAction.Environment[1].Key.ToString());
|
||||||
|
Assert.Equal("bar", containerAction.Environment[1].Value.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -143,7 +235,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal("Dockerfile", containerAction.Image);
|
Assert.Equal("Dockerfile", containerAction.Image);
|
||||||
Assert.Equal("main.sh", containerAction.EntryPoint);
|
Assert.Equal("main.sh", containerAction.EntryPoint);
|
||||||
Assert.Equal("cleanup.sh", containerAction.Cleanup);
|
Assert.Equal("cleanup.sh", containerAction.Post);
|
||||||
Assert.Equal("always()", containerAction.CleanupCondition);
|
Assert.Equal("always()", containerAction.CleanupCondition);
|
||||||
Assert.Equal("bzz", containerAction.Arguments[0].ToString());
|
Assert.Equal("bzz", containerAction.Arguments[0].ToString());
|
||||||
Assert.Equal("Token", containerAction.Environment[0].Key.ToString());
|
Assert.Equal("Token", containerAction.Environment[0].Key.ToString());
|
||||||
@@ -323,6 +415,94 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void Load_NodeAction_Pre()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
var actionManifest = new ActionManifestManager();
|
||||||
|
actionManifest.Initialize(_hc);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = actionManifest.Load(_ec.Object, Path.Combine(TestUtil.GetTestDataPath(), "nodeaction_init.yml"));
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal("Hello World", result.Name);
|
||||||
|
Assert.Equal("Greet the world and record the time", result.Description);
|
||||||
|
Assert.Equal(2, result.Inputs.Count);
|
||||||
|
Assert.Equal("greeting", result.Inputs[0].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("Hello", result.Inputs[0].Value.AssertString("value").Value);
|
||||||
|
Assert.Equal("entryPoint", result.Inputs[1].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("", result.Inputs[1].Value.AssertString("value").Value);
|
||||||
|
Assert.Equal(1, result.Deprecated.Count);
|
||||||
|
|
||||||
|
Assert.True(result.Deprecated.ContainsKey("greeting"));
|
||||||
|
result.Deprecated.TryGetValue("greeting", out string value);
|
||||||
|
Assert.Equal("This property has been deprecated", value);
|
||||||
|
|
||||||
|
Assert.Equal(ActionExecutionType.NodeJS, result.Execution.ExecutionType);
|
||||||
|
|
||||||
|
var nodeAction = result.Execution as NodeJSActionExecutionData;
|
||||||
|
|
||||||
|
Assert.Equal("main.js", nodeAction.Script);
|
||||||
|
Assert.Equal("init.js", nodeAction.Pre);
|
||||||
|
Assert.Equal("cancelled()", nodeAction.InitCondition);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void Load_NodeAction_Init_DefaultCondition()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
var actionManifest = new ActionManifestManager();
|
||||||
|
actionManifest.Initialize(_hc);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = actionManifest.Load(_ec.Object, Path.Combine(TestUtil.GetTestDataPath(), "nodeaction_init_default.yml"));
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal("Hello World", result.Name);
|
||||||
|
Assert.Equal("Greet the world and record the time", result.Description);
|
||||||
|
Assert.Equal(2, result.Inputs.Count);
|
||||||
|
Assert.Equal("greeting", result.Inputs[0].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("Hello", result.Inputs[0].Value.AssertString("value").Value);
|
||||||
|
Assert.Equal("entryPoint", result.Inputs[1].Key.AssertString("key").Value);
|
||||||
|
Assert.Equal("", result.Inputs[1].Value.AssertString("value").Value);
|
||||||
|
Assert.Equal(1, result.Deprecated.Count);
|
||||||
|
|
||||||
|
Assert.True(result.Deprecated.ContainsKey("greeting"));
|
||||||
|
result.Deprecated.TryGetValue("greeting", out string value);
|
||||||
|
Assert.Equal("This property has been deprecated", value);
|
||||||
|
|
||||||
|
Assert.Equal(ActionExecutionType.NodeJS, result.Execution.ExecutionType);
|
||||||
|
|
||||||
|
var nodeAction = result.Execution as NodeJSActionExecutionData;
|
||||||
|
|
||||||
|
Assert.Equal("main.js", nodeAction.Script);
|
||||||
|
Assert.Equal("init.js", nodeAction.Pre);
|
||||||
|
Assert.Equal("always()", nodeAction.InitCondition);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -358,7 +538,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var nodeAction = result.Execution as NodeJSActionExecutionData;
|
var nodeAction = result.Execution as NodeJSActionExecutionData;
|
||||||
|
|
||||||
Assert.Equal("main.js", nodeAction.Script);
|
Assert.Equal("main.js", nodeAction.Script);
|
||||||
Assert.Equal("cleanup.js", nodeAction.Cleanup);
|
Assert.Equal("cleanup.js", nodeAction.Post);
|
||||||
Assert.Equal("cancelled()", nodeAction.CleanupCondition);
|
Assert.Equal("cancelled()", nodeAction.CleanupCondition);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -402,7 +582,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var nodeAction = result.Execution as NodeJSActionExecutionData;
|
var nodeAction = result.Execution as NodeJSActionExecutionData;
|
||||||
|
|
||||||
Assert.Equal("main.js", nodeAction.Script);
|
Assert.Equal("main.js", nodeAction.Script);
|
||||||
Assert.Equal("cleanup.js", nodeAction.Cleanup);
|
Assert.Equal("cleanup.js", nodeAction.Post);
|
||||||
Assert.Equal("always()", nodeAction.CleanupCondition);
|
Assert.Equal("always()", nodeAction.CleanupCondition);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -199,20 +199,20 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
|
|
||||||
var postRunner1 = hc.CreateService<IActionRunner>();
|
var postRunner1 = hc.CreateService<IActionRunner>();
|
||||||
postRunner1.Action = new Pipelines.ActionStep() { Name = "post1", DisplayName = "Test 1", Reference = new Pipelines.RepositoryPathReference() { Name = "actions/action" } };
|
postRunner1.Action = new Pipelines.ActionStep() { Id = Guid.NewGuid(), Name = "post1", DisplayName = "Test 1", Reference = new Pipelines.RepositoryPathReference() { Name = "actions/action" } };
|
||||||
postRunner1.Stage = ActionRunStage.Post;
|
postRunner1.Stage = ActionRunStage.Post;
|
||||||
postRunner1.Condition = "always()";
|
postRunner1.Condition = "always()";
|
||||||
postRunner1.DisplayName = "post1";
|
postRunner1.DisplayName = "post1";
|
||||||
|
|
||||||
|
|
||||||
var postRunner2 = hc.CreateService<IActionRunner>();
|
var postRunner2 = hc.CreateService<IActionRunner>();
|
||||||
postRunner2.Action = new Pipelines.ActionStep() { Name = "post2", DisplayName = "Test 2", Reference = new Pipelines.RepositoryPathReference() { Name = "actions/action" } };
|
postRunner2.Action = new Pipelines.ActionStep() { Id = Guid.NewGuid(), Name = "post2", DisplayName = "Test 2", Reference = new Pipelines.RepositoryPathReference() { Name = "actions/action" } };
|
||||||
postRunner2.Stage = ActionRunStage.Post;
|
postRunner2.Stage = ActionRunStage.Post;
|
||||||
postRunner2.Condition = "always()";
|
postRunner2.Condition = "always()";
|
||||||
postRunner2.DisplayName = "post2";
|
postRunner2.DisplayName = "post2";
|
||||||
|
|
||||||
action1.RegisterPostJobStep("post1", postRunner1);
|
action1.RegisterPostJobStep(postRunner1);
|
||||||
action2.RegisterPostJobStep("post2", postRunner2);
|
action2.RegisterPostJobStep(postRunner2);
|
||||||
|
|
||||||
Assert.NotNull(jobContext.JobSteps);
|
Assert.NotNull(jobContext.JobSteps);
|
||||||
Assert.NotNull(jobContext.PostJobSteps);
|
Assert.NotNull(jobContext.PostJobSteps);
|
||||||
@@ -238,6 +238,91 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void RegisterPostJobAction_NotRegisterPostTwice()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange: Create a job request message.
|
||||||
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
|
TimelineReference timeline = new TimelineReference();
|
||||||
|
Guid jobId = Guid.NewGuid();
|
||||||
|
string jobName = "some job name";
|
||||||
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
||||||
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
|
{
|
||||||
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
Id = "github",
|
||||||
|
Version = "sha1"
|
||||||
|
});
|
||||||
|
jobRequest.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
jobRequest.Variables["ACTIONS_STEP_DEBUG"] = "true";
|
||||||
|
|
||||||
|
// Arrange: Setup the paging logger.
|
||||||
|
var pagingLogger1 = new Mock<IPagingLogger>();
|
||||||
|
var pagingLogger2 = new Mock<IPagingLogger>();
|
||||||
|
var pagingLogger3 = new Mock<IPagingLogger>();
|
||||||
|
var pagingLogger4 = new Mock<IPagingLogger>();
|
||||||
|
var pagingLogger5 = new Mock<IPagingLogger>();
|
||||||
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
|
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||||
|
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>())).Callback((Guid id, string msg) => { hc.GetTrace().Info(msg); });
|
||||||
|
|
||||||
|
var actionRunner1 = new ActionRunner();
|
||||||
|
actionRunner1.Initialize(hc);
|
||||||
|
var actionRunner2 = new ActionRunner();
|
||||||
|
actionRunner2.Initialize(hc);
|
||||||
|
|
||||||
|
hc.EnqueueInstance(pagingLogger1.Object);
|
||||||
|
hc.EnqueueInstance(pagingLogger2.Object);
|
||||||
|
hc.EnqueueInstance(pagingLogger3.Object);
|
||||||
|
hc.EnqueueInstance(pagingLogger4.Object);
|
||||||
|
hc.EnqueueInstance(pagingLogger5.Object);
|
||||||
|
hc.EnqueueInstance(actionRunner1 as IActionRunner);
|
||||||
|
hc.EnqueueInstance(actionRunner2 as IActionRunner);
|
||||||
|
hc.SetSingleton(jobServerQueue.Object);
|
||||||
|
|
||||||
|
var jobContext = new Runner.Worker.ExecutionContext();
|
||||||
|
jobContext.Initialize(hc);
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
|
var action1 = jobContext.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null);
|
||||||
|
var action2 = jobContext.CreateChild(Guid.NewGuid(), "action_1_main", "action_1_main", null, null);
|
||||||
|
|
||||||
|
var actionId = Guid.NewGuid();
|
||||||
|
var postRunner1 = hc.CreateService<IActionRunner>();
|
||||||
|
postRunner1.Action = new Pipelines.ActionStep() { Id = actionId, Name = "post1", DisplayName = "Test 1", Reference = new Pipelines.RepositoryPathReference() { Name = "actions/action" } };
|
||||||
|
postRunner1.Stage = ActionRunStage.Post;
|
||||||
|
postRunner1.Condition = "always()";
|
||||||
|
postRunner1.DisplayName = "post1";
|
||||||
|
|
||||||
|
|
||||||
|
var postRunner2 = hc.CreateService<IActionRunner>();
|
||||||
|
postRunner2.Action = new Pipelines.ActionStep() { Id = actionId, Name = "post2", DisplayName = "Test 2", Reference = new Pipelines.RepositoryPathReference() { Name = "actions/action" } };
|
||||||
|
postRunner2.Stage = ActionRunStage.Post;
|
||||||
|
postRunner2.Condition = "always()";
|
||||||
|
postRunner2.DisplayName = "post2";
|
||||||
|
|
||||||
|
action1.RegisterPostJobStep(postRunner1);
|
||||||
|
action2.RegisterPostJobStep(postRunner2);
|
||||||
|
|
||||||
|
Assert.NotNull(jobContext.JobSteps);
|
||||||
|
Assert.NotNull(jobContext.PostJobSteps);
|
||||||
|
Assert.Equal(1, jobContext.PostJobSteps.Count);
|
||||||
|
var post1 = jobContext.PostJobSteps.Pop();
|
||||||
|
|
||||||
|
Assert.Equal("post1", (post1 as IActionRunner).Action.Name);
|
||||||
|
|
||||||
|
Assert.Equal(ActionRunStage.Post, (post1 as IActionRunner).Stage);
|
||||||
|
|
||||||
|
Assert.Equal("always()", (post1 as IActionRunner).Condition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
||||||
{
|
{
|
||||||
var hc = new TestHostContext(this, testName);
|
var hc = new TestHostContext(this, testName);
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
jobExtension.Initialize(hc);
|
jobExtension.Initialize(hc);
|
||||||
|
|
||||||
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>()))
|
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>()))
|
||||||
.Returns(Task.FromResult(new List<JobExtensionRunner>()));
|
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>(), new Dictionary<Guid, IActionRunner>())));
|
||||||
|
|
||||||
List<IStep> result = await jobExtension.InitializeJob(_jobEc, _message);
|
List<IStep> result = await jobExtension.InitializeJob(_jobEc, _message);
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
jobExtension.Initialize(hc);
|
jobExtension.Initialize(hc);
|
||||||
|
|
||||||
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>()))
|
_actionManager.Setup(x => x.PrepareActionsAsync(It.IsAny<IExecutionContext>(), It.IsAny<IEnumerable<Pipelines.JobStep>>()))
|
||||||
.Returns(Task.FromResult(new List<JobExtensionRunner>() { new JobExtensionRunner(null, "", "prepare1", null), new JobExtensionRunner(null, "", "prepare2", null) }));
|
.Returns(Task.FromResult(new PrepareResult(new List<JobExtensionRunner>() { new JobExtensionRunner(null, "", "prepare1", null), new JobExtensionRunner(null, "", "prepare2", null) }, new Dictionary<Guid, IActionRunner>())));
|
||||||
|
|
||||||
List<IStep> result = await jobExtension.InitializeJob(_jobEc, _message);
|
List<IStep> result = await jobExtension.InitializeJob(_jobEc, _message);
|
||||||
|
|
||||||
|
|||||||
27
src/Test/TestData/dockerfileaction_init.yml
Normal file
27
src/Test/TestData/dockerfileaction_init.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: 'Hello World'
|
||||||
|
description: 'Greet the world and record the time'
|
||||||
|
author: 'Test Corporation'
|
||||||
|
inputs:
|
||||||
|
greeting: # id of input
|
||||||
|
description: 'The greeting we choose - will print ""{greeting}, World!"" on stdout'
|
||||||
|
required: true
|
||||||
|
default: 'Hello'
|
||||||
|
entryPoint: # id of input
|
||||||
|
description: 'optional docker entrypoint overwrite.'
|
||||||
|
required: false
|
||||||
|
outputs:
|
||||||
|
time: # id of output
|
||||||
|
description: 'The time we did the greeting'
|
||||||
|
icon: 'hello.svg' # vector art to display in the GitHub Marketplace
|
||||||
|
color: 'green' # optional, decorates the entry in the GitHub Marketplace
|
||||||
|
runs:
|
||||||
|
using: 'docker'
|
||||||
|
image: 'Dockerfile'
|
||||||
|
args:
|
||||||
|
- 'bzz'
|
||||||
|
entrypoint: 'main.sh'
|
||||||
|
env:
|
||||||
|
Token: foo
|
||||||
|
Url: bar
|
||||||
|
pre-entrypoint: 'init.sh'
|
||||||
|
pre-if: 'success()'
|
||||||
26
src/Test/TestData/dockerfileaction_init_default.yml
Normal file
26
src/Test/TestData/dockerfileaction_init_default.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: 'Hello World'
|
||||||
|
description: 'Greet the world and record the time'
|
||||||
|
author: 'Test Corporation'
|
||||||
|
inputs:
|
||||||
|
greeting: # id of input
|
||||||
|
description: 'The greeting we choose - will print ""{greeting}, World!"" on stdout'
|
||||||
|
required: true
|
||||||
|
default: 'Hello'
|
||||||
|
entryPoint: # id of input
|
||||||
|
description: 'optional docker entrypoint overwrite.'
|
||||||
|
required: false
|
||||||
|
outputs:
|
||||||
|
time: # id of output
|
||||||
|
description: 'The time we did the greeting'
|
||||||
|
icon: 'hello.svg' # vector art to display in the GitHub Marketplace
|
||||||
|
color: 'green' # optional, decorates the entry in the GitHub Marketplace
|
||||||
|
runs:
|
||||||
|
using: 'docker'
|
||||||
|
image: 'Dockerfile'
|
||||||
|
args:
|
||||||
|
- 'bzz'
|
||||||
|
entrypoint: 'main.sh'
|
||||||
|
env:
|
||||||
|
Token: foo
|
||||||
|
Url: bar
|
||||||
|
pre-entrypoint: 'init.sh'
|
||||||
22
src/Test/TestData/nodeaction_init.yml
Normal file
22
src/Test/TestData/nodeaction_init.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: 'Hello World'
|
||||||
|
description: 'Greet the world and record the time'
|
||||||
|
author: 'Test Corporation'
|
||||||
|
inputs:
|
||||||
|
greeting: # id of input
|
||||||
|
description: 'The greeting we choose - will print ""{greeting}, World!"" on stdout'
|
||||||
|
required: true
|
||||||
|
default: 'Hello'
|
||||||
|
deprecationMessage: 'This property has been deprecated'
|
||||||
|
entryPoint: # id of input
|
||||||
|
description: 'optional docker entrypoint overwrite.'
|
||||||
|
required: false
|
||||||
|
outputs:
|
||||||
|
time: # id of output
|
||||||
|
description: 'The time we did the greeting'
|
||||||
|
icon: 'hello.svg' # vector art to display in the GitHub Marketplace
|
||||||
|
color: 'green' # optional, decorates the entry in the GitHub Marketplace
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'main.js'
|
||||||
|
pre: 'init.js'
|
||||||
|
pre-if: 'cancelled()'
|
||||||
21
src/Test/TestData/nodeaction_init_default.yml
Normal file
21
src/Test/TestData/nodeaction_init_default.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: 'Hello World'
|
||||||
|
description: 'Greet the world and record the time'
|
||||||
|
author: 'Test Corporation'
|
||||||
|
inputs:
|
||||||
|
greeting: # id of input
|
||||||
|
description: 'The greeting we choose - will print ""{greeting}, World!"" on stdout'
|
||||||
|
required: true
|
||||||
|
default: 'Hello'
|
||||||
|
deprecationMessage: 'This property has been deprecated'
|
||||||
|
entryPoint: # id of input
|
||||||
|
description: 'optional docker entrypoint overwrite.'
|
||||||
|
required: false
|
||||||
|
outputs:
|
||||||
|
time: # id of output
|
||||||
|
description: 'The time we did the greeting'
|
||||||
|
icon: 'hello.svg' # vector art to display in the GitHub Marketplace
|
||||||
|
color: 'green' # optional, decorates the entry in the GitHub Marketplace
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'main.js'
|
||||||
|
pre: 'init.js'
|
||||||
Reference in New Issue
Block a user