Compare commits

...

8 Commits

Author SHA1 Message Date
TingluoHuang
4f840647b3 release 2.169.1 runner. 2020-04-15 15:14:45 -04:00
David Kale
e2fbd1dc95 ArgumentNullException: Value cannot be null, for anonymous volume mounts (#426)
* Dont check if path starts with null

* Check SourceVolumePath not MountVolume obj

* Prefer string.IsNullOrEmpty
2020-04-15 14:44:36 -04:00
Lokesh Gopu
8d6acf2a7f Fix optional parameter for unattended (#425) 2020-04-15 14:44:29 -04:00
Tingluo Huang
6b3b42a840 support 'pre' execution for actions. (#389) 2020-04-15 14:44:20 -04:00
Lokesh Gopu
826f58682e Added support for custom labels (#414)
* Added support for custom labels

* ignore case

* Added interactive config for labels

* Fixing L0s

* pr comments
2020-04-15 14:44:11 -04:00
Tingluo Huang
2eefff4b69 launch middle man process on macOS to workaround SIP limit (#416) 2020-04-15 14:44:02 -04:00
Tingluo Huang
8456f7667d Better Kusto Tracing for self-hosted runner. (#405) 2020-04-15 14:43:54 -04:00
Tingluo Huang
7f092c96db create 2.169.0 runner release 2020-04-08 12:59:44 -04:00
46 changed files with 970 additions and 163 deletions

View File

@@ -1,9 +1,10 @@
## Features ## Features
- Runner support for GHES Alpha (#381 #386 #390 #393 $401) - Better telemetry tracing for self-hosted runner. (#405)
- Allow secrets context in Container.env (#388) - Launch middle man process on macOS to workaround SIP limit (#416)
- Added support for custom labels (#414, #425)
- support 'pre' execution for actions. (#389)
## Bugs ## Bugs
- Raise warning when volume mount root. (#413) - ArgumentNullException: Value cannot be null, for anonymous volume mounts (#426)
- Fix typo (#394)
## Misc ## Misc
- N/A - N/A

View File

@@ -1 +1 @@
2.164.0 2.169.1

View 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);
}
});

View File

@@ -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";

View File

@@ -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)

View File

@@ -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))

View File

@@ -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)

View File

@@ -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.Add("self-hosted"); agent.Labels.Clear();
agent.Labels.Add(VarUtil.OS);
agent.Labels.Add(VarUtil.OSArchitecture); agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
agent.Labels.Add(new AgentLabel(VarUtil.OS, LabelType.System));
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>()
{ {

View File

@@ -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,17 +91,27 @@ 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))
{
if (!string.IsNullOrEmpty(defaultValue))
{ {
Trace.Info($"Falling back to the default: '{defaultValue}'"); Trace.Info($"Falling back to the default: '{defaultValue}'");
return 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.

View File

@@ -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);

View File

@@ -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}");

View File

@@ -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();

View File

@@ -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)

View File

@@ -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

View File

@@ -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()"
}; };
} }

View File

@@ -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));
// The action has post cleanup defined. if (handlerData.HasPre &&
// we need to create timeline record for them and add them to the step list that StepRunner is using Action.Reference is Pipelines.RepositoryPathReference repoAction &&
if (handlerData.HasCleanup && Stage == ActionRunStage.Main) string.Equals(repoAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
{ {
string postDisplayName = null; ExecutionContext.Warning($"`pre` execution is not supported for local action from '{repoAction.Path}'");
if (this.DisplayName.StartsWith(PipelineTemplateConstants.RunDisplayPrefix))
{
postDisplayName = $"Post {this.DisplayName.Substring(PipelineTemplateConstants.RunDisplayPrefix.Length)}";
}
else
{
postDisplayName = $"Post {this.DisplayName}";
} }
// 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
if (handlerData.HasPost && (Stage == ActionRunStage.Pre || Stage == ActionRunStage.Main))
{
string 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>();

View File

@@ -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.

View File

@@ -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);
} }
} }

View File

@@ -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

View File

@@ -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));

View File

@@ -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));

View File

@@ -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))

View File

@@ -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);

View File

@@ -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,8 +239,22 @@ 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);
} }
} }

View File

@@ -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>())

View File

@@ -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"
} }

View File

@@ -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);

View 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);
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Runtime.Serialization;
namespace GitHub.DistributedTask.WebApi
{
[DataContract]
public enum LabelType
{
[EnumMember]
System = 0,
[EnumMember]
User = 1
}
}

View File

@@ -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;
} }
} }

View File

@@ -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(

View File

@@ -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));

View File

@@ -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.

View File

@@ -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);
} }
} }
} }

View File

@@ -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()));

View File

@@ -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";
}); });

View File

@@ -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();

View File

@@ -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
{ {

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View 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()'

View 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'

View 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()'

View 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'

View File

@@ -1 +1 @@
2.169.0 2.169.1