mirror of
https://github.com/actions/runner.git
synced 2025-12-11 21:06:55 +00:00
Compare commits
1 Commits
cschleiden
...
users/tihu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ca5ee0fbd |
@@ -1,24 +1,27 @@
|
|||||||
## Features
|
## Features
|
||||||
- Update Runner Register GitHub API URL to Support Org-level Runner (#339 #345 #352)
|
- Expose whether debug is on/off via RUNNER_DEBUG. (#253)
|
||||||
- Preserve workflow file/line/column for better error messages (#356)
|
- Upload log on runner when worker get killed due to cancellation timeout. (#255)
|
||||||
- Switch to use token service instead of SPS for exchanging oauth token. (#325)
|
- Update config.sh/cmd --help documentation (#282)
|
||||||
- Load and print machine setup info from .setup_info (#364)
|
- Set http_proxy and related env vars for job/service containers (#304)
|
||||||
- Expose job name as $GITHUB_JOB (#366)
|
- Set both http_proxy and HTTP_PROXY env for runner/worker processes. (#298)
|
||||||
- Add support for job outputs. (#365)
|
|
||||||
- Set CI=true when launch process in actions runner. (#374)
|
|
||||||
- Set steps.<id>.outcome and steps.<id>.conclusion. (#372)
|
|
||||||
- Add support for workflow/job defaults. (#369)
|
|
||||||
- Expose GITHUB_REPOSITORY_OWNER and ${{github.repository_owner}}. (#378)
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Use authenticate endpoint for testing runner connection. (#311)
|
- Verify runner Windows service hash started successfully after configuration (#236)
|
||||||
- Commands translate file path from container action (#331)
|
- Detect source file path in L0 without using env. (#257)
|
||||||
- Change problem matchers output to debug (#363)
|
- Handle escaped '%' in commands data section (#200)
|
||||||
- Switch hashFiles to extension function (#362)
|
- Allow container to be null/empty during matrix expansion (#266)
|
||||||
- Add expanded volumes strings to container mounts (#384)
|
- Translate problem matcher file to host path (#272)
|
||||||
|
- Change hashFiles() expression function to use @actions/glob. (#268)
|
||||||
|
- Default post-job action's condition to always(). (#293)
|
||||||
|
- Support action.yaml file as action's entry file (#288)
|
||||||
|
- Trace javascript action exit code to debug instead of user logs (#290)
|
||||||
|
- Change prompt message when removing a runner to lines up with GitHub.com UI (#303)
|
||||||
|
- Include step.env as part of env context. (#300)
|
||||||
|
- Update Base64 Encoders to deal with suffixes (#284)
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
- Add runner auth documentation (#357)
|
- Move .sln file under ./src (#238)
|
||||||
|
- Treat warnings as errors during compile (#249)
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ namespace GitHub.Runner.Common
|
|||||||
[DataContract]
|
[DataContract]
|
||||||
public sealed class RunnerSettings
|
public sealed class RunnerSettings
|
||||||
{
|
{
|
||||||
[DataMember(Name = "IsHostedServer", EmitDefaultValue = false)]
|
|
||||||
private bool? _isHostedServer;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public int AgentId { get; set; }
|
public int AgentId { get; set; }
|
||||||
|
|
||||||
@@ -45,21 +42,6 @@ namespace GitHub.Runner.Common
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string MonitorSocketAddress { get; set; }
|
public string MonitorSocketAddress { get; set; }
|
||||||
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public bool IsHostedServer
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// Old runners do not have this property. Hosted runners likely don't have this property either.
|
|
||||||
return _isHostedServer ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_isHostedServer = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
// Computed property for convenience. Can either return:
|
// Computed property for convenience. Can either return:
|
||||||
// 1. If runner was configured at the repo level, returns something like: "myorg/myrepo"
|
// 1. If runner was configured at the repo level, returns something like: "myorg/myrepo"
|
||||||
@@ -87,15 +69,6 @@ namespace GitHub.Runner.Common
|
|||||||
return repoOrOrgName;
|
return repoOrOrgName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[OnSerializing]
|
|
||||||
private void OnSerializing(StreamingContext context)
|
|
||||||
{
|
|
||||||
if (_isHostedServer.HasValue && _isHostedServer.Value)
|
|
||||||
{
|
|
||||||
_isHostedServer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ServiceLocator(Default = typeof(ConfigurationStore))]
|
[ServiceLocator(Default = typeof(ConfigurationStore))]
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
RunnerSettings runnerSettings = new RunnerSettings();
|
RunnerSettings runnerSettings = new RunnerSettings();
|
||||||
|
|
||||||
|
bool isHostedServer = false;
|
||||||
// Loop getting url and creds until you can connect
|
// Loop getting url and creds until you can connect
|
||||||
ICredentialProvider credProvider = null;
|
ICredentialProvider credProvider = null;
|
||||||
VssCredentials creds = null;
|
VssCredentials creds = null;
|
||||||
@@ -93,11 +94,9 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Get the URL
|
// Get the URL
|
||||||
var isGitHub = StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("_IS_GITHUB"));
|
|
||||||
var inputUrl = command.GetUrl();
|
var inputUrl = command.GetUrl();
|
||||||
if (!inputUrl.Contains("github.com", StringComparison.OrdinalIgnoreCase) &&
|
if (!inputUrl.Contains("github.com", StringComparison.OrdinalIgnoreCase) &&
|
||||||
!inputUrl.Contains("github.localhost", StringComparison.OrdinalIgnoreCase) &&
|
!inputUrl.Contains("github.localhost", StringComparison.OrdinalIgnoreCase))
|
||||||
!isGitHub)
|
|
||||||
{
|
{
|
||||||
runnerSettings.ServerUrl = inputUrl;
|
runnerSettings.ServerUrl = inputUrl;
|
||||||
// Get the credentials
|
// Get the credentials
|
||||||
@@ -118,7 +117,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
||||||
runnerSettings.IsHostedServer = await IsHostedServer(runnerSettings.ServerUrl, creds);
|
isHostedServer = await IsHostedServer(runnerSettings.ServerUrl, creds);
|
||||||
|
|
||||||
// Validate can connect.
|
// Validate can connect.
|
||||||
await _runnerServer.ConnectAsync(new Uri(runnerSettings.ServerUrl), creds);
|
await _runnerServer.ConnectAsync(new Uri(runnerSettings.ServerUrl), creds);
|
||||||
@@ -200,7 +199,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);
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -249,7 +248,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
UriBuilder configServerUrl = new UriBuilder(runnerSettings.ServerUrl);
|
UriBuilder configServerUrl = new UriBuilder(runnerSettings.ServerUrl);
|
||||||
UriBuilder oauthEndpointUrlBuilder = new UriBuilder(agent.Authorization.AuthorizationUrl);
|
UriBuilder oauthEndpointUrlBuilder = new UriBuilder(agent.Authorization.AuthorizationUrl);
|
||||||
if (!runnerSettings.IsHostedServer && Uri.Compare(configServerUrl.Uri, oauthEndpointUrlBuilder.Uri, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) != 0)
|
if (!isHostedServer && Uri.Compare(configServerUrl.Uri, oauthEndpointUrlBuilder.Uri, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) != 0)
|
||||||
{
|
{
|
||||||
oauthEndpointUrlBuilder.Scheme = configServerUrl.Scheme;
|
oauthEndpointUrlBuilder.Scheme = configServerUrl.Scheme;
|
||||||
oauthEndpointUrlBuilder.Host = configServerUrl.Host;
|
oauthEndpointUrlBuilder.Host = configServerUrl.Host;
|
||||||
@@ -292,7 +291,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
// there are two exception messages server send that indicate clock skew.
|
// there are two exception messages server send that indicate clock skew.
|
||||||
// 1. The bearer token expired on {jwt.ValidTo}. Current server time is {DateTime.UtcNow}.
|
// 1. The bearer token expired on {jwt.ValidTo}. Current server time is {DateTime.UtcNow}.
|
||||||
// 2. The bearer token is not valid until {jwt.ValidFrom}. Current server time is {DateTime.UtcNow}.
|
// 2. The bearer token is not valid until {jwt.ValidFrom}. Current server time is {DateTime.UtcNow}.
|
||||||
Trace.Error("Catch exception during test agent connection.");
|
Trace.Error("Catch exception during test agent connection.");
|
||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
throw new Exception("The local machine's clock may be out of sync with the server time by more than five minutes. Please sync your clock with your domain or internet time and try again.");
|
throw new Exception("The local machine's clock may be out of sync with the server time by more than five minutes. Please sync your clock with your domain or internet time and try again.");
|
||||||
@@ -382,6 +381,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
||||||
|
bool isHostedServer = await IsHostedServer(settings.ServerUrl, creds);
|
||||||
await _runnerServer.ConnectAsync(new Uri(settings.ServerUrl), creds);
|
await _runnerServer.ConnectAsync(new Uri(settings.ServerUrl), creds);
|
||||||
|
|
||||||
var agents = await _runnerServer.GetAgentsAsync(settings.PoolId, settings.AgentName);
|
var agents = await _runnerServer.GetAgentsAsync(settings.PoolId, settings.AgentName);
|
||||||
@@ -404,7 +404,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
_term.WriteLine("Cannot connect to server, because config files are missing. Skipping removing runner from the server.");
|
_term.WriteLine("Cannot connect to server, because config files are missing. Skipping removing runner from the server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//delete credential config files
|
//delete credential config files
|
||||||
currentAction = "Removing .credentials";
|
currentAction = "Removing .credentials";
|
||||||
if (hasCredentials)
|
if (hasCredentials)
|
||||||
{
|
{
|
||||||
@@ -418,7 +418,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
_term.WriteLine("Does not exist. Skipping " + currentAction);
|
_term.WriteLine("Does not exist. Skipping " + currentAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
//delete settings config file
|
//delete settings config file
|
||||||
currentAction = "Removing .runner";
|
currentAction = "Removing .runner";
|
||||||
if (isConfigured)
|
if (isConfigured)
|
||||||
{
|
{
|
||||||
@@ -522,7 +522,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
||||||
{
|
{
|
||||||
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
var githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/actions/runner-registration";
|
var githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/actions/runner-registration";
|
||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -58,14 +58,8 @@ namespace GitHub.Runner.Worker
|
|||||||
executionContext.Warning("The 'PREVIEW_ACTION_TOKEN' secret is depreciated. Please remove it from the repository's secrets");
|
executionContext.Warning("The 'PREVIEW_ACTION_TOKEN' secret is depreciated. Please remove it from the repository's secrets");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the cache (for self-hosted runners)
|
// Clear the cache (local runner)
|
||||||
// Note, temporarily avoid this step for the on-premises product, to avoid rate limiting.
|
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
||||||
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
|
||||||
var isHostedServer = configurationStore.GetSettings().IsHostedServer;
|
|
||||||
if (isHostedServer)
|
|
||||||
{
|
|
||||||
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
@@ -454,8 +448,7 @@ namespace GitHub.Runner.Worker
|
|||||||
ArgUtil.NotNullOrEmpty(repositoryReference.Ref, nameof(repositoryReference.Ref));
|
ArgUtil.NotNullOrEmpty(repositoryReference.Ref, nameof(repositoryReference.Ref));
|
||||||
|
|
||||||
string destDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), repositoryReference.Name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), repositoryReference.Ref);
|
string destDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Actions), repositoryReference.Name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar), repositoryReference.Ref);
|
||||||
string watermarkFile = destDirectory + ".completed";
|
if (File.Exists(destDirectory + ".completed"))
|
||||||
if (File.Exists(watermarkFile))
|
|
||||||
{
|
{
|
||||||
executionContext.Debug($"Action '{repositoryReference.Name}@{repositoryReference.Ref}' already downloaded at '{destDirectory}'.");
|
executionContext.Debug($"Action '{repositoryReference.Name}@{repositoryReference.Ref}' already downloaded at '{destDirectory}'.");
|
||||||
return;
|
return;
|
||||||
@@ -505,33 +498,24 @@ namespace GitHub.Runner.Worker
|
|||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
{
|
{
|
||||||
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
var authToken = Environment.GetEnvironmentVariable("_GITHUB_ACTION_TOKEN");
|
||||||
var isHostedServer = configurationStore.GetSettings().IsHostedServer;
|
if (string.IsNullOrEmpty(authToken))
|
||||||
if (isHostedServer)
|
|
||||||
{
|
{
|
||||||
var authToken = Environment.GetEnvironmentVariable("_GITHUB_ACTION_TOKEN");
|
// TODO: Depreciate the PREVIEW_ACTION_TOKEN
|
||||||
if (string.IsNullOrEmpty(authToken))
|
authToken = executionContext.Variables.Get("PREVIEW_ACTION_TOKEN");
|
||||||
{
|
}
|
||||||
// TODO: Depreciate the PREVIEW_ACTION_TOKEN
|
|
||||||
authToken = executionContext.Variables.Get("PREVIEW_ACTION_TOKEN");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(authToken))
|
if (!string.IsNullOrEmpty(authToken))
|
||||||
{
|
{
|
||||||
HostContext.SecretMasker.AddValue(authToken);
|
HostContext.SecretMasker.AddValue(authToken);
|
||||||
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"PAT:{authToken}"));
|
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"PAT:{authToken}"));
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodingToken);
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodingToken);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var accessToken = executionContext.GetGitHubContext("token");
|
|
||||||
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{accessToken}"));
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodingToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Intentionally empty. Temporary for GHES alpha release, download from dotcom unauthenticated.
|
var accessToken = executionContext.GetGitHubContext("token");
|
||||||
|
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{accessToken}"));
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.Add(HostContext.UserAgent);
|
httpClient.DefaultRequestHeaders.UserAgent.Add(HostContext.UserAgent);
|
||||||
@@ -626,7 +610,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
Trace.Verbose("Create watermark file indicate action download succeed.");
|
Trace.Verbose("Create watermark file indicate action download succeed.");
|
||||||
File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString());
|
File.WriteAllText(destDirectory + ".completed", DateTime.UtcNow.ToString());
|
||||||
|
|
||||||
executionContext.Debug($"Archive '{archiveFile}' has been unzipped into '{destDirectory}'.");
|
executionContext.Debug($"Archive '{archiveFile}' has been unzipped into '{destDirectory}'.");
|
||||||
Trace.Info("Finished getting action repository.");
|
Trace.Info("Finished getting action repository.");
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile);
|
ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile);
|
||||||
|
|
||||||
List<string> EvaluateContainerArguments(IExecutionContext executionContext, SequenceToken token, IDictionary<string, PipelineContextData> extraExpressionValues);
|
List<string> EvaluateContainerArguments(IExecutionContext executionContext, SequenceToken token, IDictionary<string, PipelineContextData> contextData);
|
||||||
|
|
||||||
Dictionary<string, string> EvaluateContainerEnvironment(IExecutionContext executionContext, MappingToken token, IDictionary<string, PipelineContextData> extraExpressionValues);
|
Dictionary<string, string> EvaluateContainerEnvironment(IExecutionContext executionContext, MappingToken token, IDictionary<string, PipelineContextData> contextData);
|
||||||
|
|
||||||
string EvaluateDefaultInput(IExecutionContext executionContext, string inputName, TemplateToken token);
|
string EvaluateDefaultInput(IExecutionContext executionContext, string inputName, TemplateToken token, IDictionary<string, PipelineContextData> contextData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ActionManifestManager : RunnerService, IActionManifestManager
|
public sealed class ActionManifestManager : RunnerService, IActionManifestManager
|
||||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile)
|
public ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile)
|
||||||
{
|
{
|
||||||
var context = CreateContext(executionContext);
|
var context = CreateContext(executionContext, null);
|
||||||
ActionDefinitionData actionDefinition = new ActionDefinitionData();
|
ActionDefinitionData actionDefinition = new ActionDefinitionData();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -133,13 +133,13 @@ namespace GitHub.Runner.Worker
|
|||||||
public List<string> EvaluateContainerArguments(
|
public List<string> EvaluateContainerArguments(
|
||||||
IExecutionContext executionContext,
|
IExecutionContext executionContext,
|
||||||
SequenceToken token,
|
SequenceToken token,
|
||||||
IDictionary<string, PipelineContextData> extraExpressionValues)
|
IDictionary<string, PipelineContextData> contextData)
|
||||||
{
|
{
|
||||||
var result = new List<string>();
|
var result = new List<string>();
|
||||||
|
|
||||||
if (token != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(executionContext, extraExpressionValues);
|
var context = CreateContext(executionContext, contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-args", token, 0, null, omitHeader: true);
|
var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-args", token, 0, null, omitHeader: true);
|
||||||
@@ -172,13 +172,13 @@ namespace GitHub.Runner.Worker
|
|||||||
public Dictionary<string, string> EvaluateContainerEnvironment(
|
public Dictionary<string, string> EvaluateContainerEnvironment(
|
||||||
IExecutionContext executionContext,
|
IExecutionContext executionContext,
|
||||||
MappingToken token,
|
MappingToken token,
|
||||||
IDictionary<string, PipelineContextData> extraExpressionValues)
|
IDictionary<string, PipelineContextData> contextData)
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (token != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(executionContext, extraExpressionValues);
|
var context = CreateContext(executionContext, contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-env", token, 0, null, omitHeader: true);
|
var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-env", token, 0, null, omitHeader: true);
|
||||||
@@ -216,12 +216,13 @@ namespace GitHub.Runner.Worker
|
|||||||
public string EvaluateDefaultInput(
|
public string EvaluateDefaultInput(
|
||||||
IExecutionContext executionContext,
|
IExecutionContext executionContext,
|
||||||
string inputName,
|
string inputName,
|
||||||
TemplateToken token)
|
TemplateToken token,
|
||||||
|
IDictionary<string, PipelineContextData> contextData)
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
if (token != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(executionContext);
|
var context = CreateContext(executionContext, contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var evaluateResult = TemplateEvaluator.Evaluate(context, "input-default-context", token, 0, null, omitHeader: true);
|
var evaluateResult = TemplateEvaluator.Evaluate(context, "input-default-context", token, 0, null, omitHeader: true);
|
||||||
@@ -246,7 +247,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
private TemplateContext CreateContext(
|
private TemplateContext CreateContext(
|
||||||
IExecutionContext executionContext,
|
IExecutionContext executionContext,
|
||||||
IDictionary<string, PipelineContextData> extraExpressionValues = null)
|
IDictionary<string, PipelineContextData> contextData)
|
||||||
{
|
{
|
||||||
var result = new TemplateContext
|
var result = new TemplateContext
|
||||||
{
|
{
|
||||||
@@ -260,27 +261,14 @@ namespace GitHub.Runner.Worker
|
|||||||
TraceWriter = executionContext.ToTemplateTraceWriter(),
|
TraceWriter = executionContext.ToTemplateTraceWriter(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expression values from execution context
|
if (contextData?.Count > 0)
|
||||||
foreach (var pair in executionContext.ExpressionValues)
|
|
||||||
{
|
{
|
||||||
result.ExpressionValues[pair.Key] = pair.Value;
|
foreach (var pair in contextData)
|
||||||
}
|
|
||||||
|
|
||||||
// Extra expression values
|
|
||||||
if (extraExpressionValues?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var pair in extraExpressionValues)
|
|
||||||
{
|
{
|
||||||
result.ExpressionValues[pair.Key] = pair.Value;
|
result.ExpressionValues[pair.Key] = pair.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expression functions from execution context
|
|
||||||
foreach (var item in executionContext.ExpressionFunctions)
|
|
||||||
{
|
|
||||||
result.ExpressionFunctions.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the file table
|
// Add the file table
|
||||||
if (_fileTable?.Count > 0)
|
if (_fileTable?.Count > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public interface IActionRunner : IStep, IRunnerService
|
public interface IActionRunner : IStep, IRunnerService
|
||||||
{
|
{
|
||||||
ActionRunStage Stage { get; set; }
|
ActionRunStage Stage { get; set; }
|
||||||
bool TryEvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context);
|
Boolean TryEvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context);
|
||||||
Pipelines.ActionStep Action { get; set; }
|
Pipelines.ActionStep Action { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// Load the inputs.
|
// Load the inputs.
|
||||||
ExecutionContext.Debug("Loading inputs");
|
ExecutionContext.Debug("Loading inputs");
|
||||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues);
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> input in inputs)
|
foreach (KeyValuePair<string, string> input in inputs)
|
||||||
{
|
{
|
||||||
@@ -162,7 +162,13 @@ namespace GitHub.Runner.Worker
|
|||||||
string key = input.Key.AssertString("action input name").Value;
|
string key = input.Key.AssertString("action input name").Value;
|
||||||
if (!inputs.ContainsKey(key))
|
if (!inputs.ContainsKey(key))
|
||||||
{
|
{
|
||||||
inputs[key] = manifestManager.EvaluateDefaultInput(ExecutionContext, key, input.Value);
|
var evaluateContext = new Dictionary<string, PipelineContextData>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var data in ExecutionContext.ExpressionValues)
|
||||||
|
{
|
||||||
|
evaluateContext[data.Key] = data.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs[key] = manifestManager.EvaluateDefaultInput(ExecutionContext, key, input.Value, evaluateContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,14 +293,10 @@ namespace GitHub.Runner.Worker
|
|||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
// Try evaluating fully
|
// Try evaluating fully
|
||||||
|
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (tokenToParse.CheckHasRequiredContext(contextData, context.ExpressionFunctions))
|
didFullyEvaluate = templateEvaluator.TryEvaluateStepDisplayName(tokenToParse, contextData, out displayName);
|
||||||
{
|
|
||||||
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
|
||||||
displayName = templateEvaluator.EvaluateStepDisplayName(tokenToParse, contextData, context.ExpressionFunctions);
|
|
||||||
didFullyEvaluate = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (TemplateValidationException e)
|
catch (TemplateValidationException e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
foreach (var volume in container.Volumes)
|
foreach (var volume in container.Volumes)
|
||||||
{
|
{
|
||||||
UserMountVolumes[volume] = volume;
|
UserMountVolumes[volume] = volume;
|
||||||
MountVolumes.Add(new MountVolume(volume));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,13 +130,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
// Watermark for GitHub Action environment
|
// Watermark for GitHub Action environment
|
||||||
dockerOptions.Add("-e GITHUB_ACTIONS=true");
|
dockerOptions.Add("-e GITHUB_ACTIONS=true");
|
||||||
|
|
||||||
// Set CI=true when no one else already set it.
|
|
||||||
// CI=true is common set in most CI provider in GitHub
|
|
||||||
if (!container.ContainerEnvironmentVariables.ContainsKey("CI"))
|
|
||||||
{
|
|
||||||
dockerOptions.Add("-e CI=true");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var volume in container.MountVolumes)
|
foreach (var volume in container.MountVolumes)
|
||||||
{
|
{
|
||||||
// replace `"` with `\"` and add `"{0}"` to all path.
|
// replace `"` with `\"` and add `"{0}"` to all path.
|
||||||
@@ -196,13 +189,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
// Watermark for GitHub Action environment
|
// Watermark for GitHub Action environment
|
||||||
dockerOptions.Add("-e GITHUB_ACTIONS=true");
|
dockerOptions.Add("-e GITHUB_ACTIONS=true");
|
||||||
|
|
||||||
// Set CI=true when no one else already set it.
|
|
||||||
// CI=true is common set in most CI provider in GitHub
|
|
||||||
if (!container.ContainerEnvironmentVariables.ContainsKey("CI"))
|
|
||||||
{
|
|
||||||
dockerOptions.Add("-e CI=true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(container.ContainerEntryPoint))
|
if (!string.IsNullOrEmpty(container.ContainerEntryPoint))
|
||||||
{
|
{
|
||||||
dockerOptions.Add($"--entrypoint \"{container.ContainerEntryPoint}\"");
|
dockerOptions.Add($"--entrypoint \"{container.ContainerEntryPoint}\"");
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
@@ -17,11 +16,12 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections;
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
using GitHub.DistributedTask.Expressions2;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,6 @@ namespace GitHub.Runner.Worker
|
|||||||
IList<String> FileTable { get; }
|
IList<String> FileTable { get; }
|
||||||
StepsContext StepsContext { get; }
|
StepsContext StepsContext { get; }
|
||||||
DictionaryContextData ExpressionValues { get; }
|
DictionaryContextData ExpressionValues { get; }
|
||||||
IList<IFunctionInfo> ExpressionFunctions { get; }
|
|
||||||
List<string> PrependPath { get; }
|
List<string> PrependPath { get; }
|
||||||
ContainerInfo Container { get; set; }
|
ContainerInfo Container { get; set; }
|
||||||
List<ContainerInfo> ServiceContainers { get; }
|
List<ContainerInfo> ServiceContainers { get; }
|
||||||
@@ -149,7 +148,6 @@ namespace GitHub.Runner.Worker
|
|||||||
public IList<String> FileTable { get; private set; }
|
public IList<String> FileTable { get; private set; }
|
||||||
public StepsContext StepsContext { get; private set; }
|
public StepsContext StepsContext { get; private set; }
|
||||||
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
||||||
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
|
||||||
public bool WriteDebug { get; private set; }
|
public bool WriteDebug { get; private set; }
|
||||||
public List<string> PrependPath { get; private set; }
|
public List<string> PrependPath { get; private set; }
|
||||||
public ContainerInfo Container { get; set; }
|
public ContainerInfo Container { get; set; }
|
||||||
@@ -282,10 +280,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
child.ExpressionValues[pair.Key] = pair.Value;
|
child.ExpressionValues[pair.Key] = pair.Value;
|
||||||
}
|
}
|
||||||
foreach (var item in ExpressionFunctions)
|
|
||||||
{
|
|
||||||
child.ExpressionFunctions.Add(item);
|
|
||||||
}
|
|
||||||
child._cancellationTokenSource = new CancellationTokenSource();
|
child._cancellationTokenSource = new CancellationTokenSource();
|
||||||
child.WriteDebug = WriteDebug;
|
child.WriteDebug = WriteDebug;
|
||||||
child._parentExecutionContext = this;
|
child._parentExecutionContext = this;
|
||||||
@@ -599,6 +593,12 @@ namespace GitHub.Runner.Worker
|
|||||||
// File table
|
// File table
|
||||||
FileTable = new List<String>(message.FileTable ?? new string[0]);
|
FileTable = new List<String>(message.FileTable ?? new string[0]);
|
||||||
|
|
||||||
|
// Expression functions
|
||||||
|
if (Variables.GetBoolean("System.HashFilesV2") == true)
|
||||||
|
{
|
||||||
|
ExpressionConstants.UpdateFunction<Handlers.HashFiles>("hashFiles", 1, byte.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
// Expression values
|
// Expression values
|
||||||
if (message.ContextData?.Count > 0)
|
if (message.ContextData?.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -915,19 +915,11 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<KeyValuePair<string, object>> ToExpressionState(this IExecutionContext context)
|
public static PipelineTemplateEvaluator ToPipelineTemplateEvaluator(this IExecutionContext context)
|
||||||
{
|
{
|
||||||
return new[] { new KeyValuePair<string, object>(nameof(IExecutionContext), context) };
|
var templateTrace = context.ToTemplateTraceWriter();
|
||||||
}
|
var schema = new PipelineTemplateSchemaFactory().CreateSchema();
|
||||||
|
return new PipelineTemplateEvaluator(templateTrace, schema, context.FileTable);
|
||||||
public static PipelineTemplateEvaluator ToPipelineTemplateEvaluator(this IExecutionContext context, ObjectTemplating.ITraceWriter traceWriter = null)
|
|
||||||
{
|
|
||||||
if (traceWriter == null)
|
|
||||||
{
|
|
||||||
traceWriter = context.ToTemplateTraceWriter();
|
|
||||||
}
|
|
||||||
var schema = PipelineTemplateSchemaFactory.GetSchema();
|
|
||||||
return new PipelineTemplateEvaluator(traceWriter, schema, context.FileTable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectTemplating.ITraceWriter ToTemplateTraceWriter(this IExecutionContext context)
|
public static ObjectTemplating.ITraceWriter ToTemplateTraceWriter(this IExecutionContext context)
|
||||||
@@ -942,7 +934,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
internal TemplateTraceWriter(IExecutionContext executionContext)
|
internal TemplateTraceWriter(IExecutionContext executionContext)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
|
||||||
_executionContext = executionContext;
|
_executionContext = executionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,28 @@ using System.Reflection;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Expressions
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
{
|
{
|
||||||
public sealed class HashFilesFunction : Function
|
public class FunctionTrace : ITraceWriter
|
||||||
|
{
|
||||||
|
private GitHub.DistributedTask.Expressions2.ITraceWriter _trace;
|
||||||
|
|
||||||
|
public FunctionTrace(GitHub.DistributedTask.Expressions2.ITraceWriter trace)
|
||||||
|
{
|
||||||
|
_trace = trace;
|
||||||
|
}
|
||||||
|
public void Info(string message)
|
||||||
|
{
|
||||||
|
_trace.Info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Verbose(string message)
|
||||||
|
{
|
||||||
|
_trace.Info(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class HashFiles : Function
|
||||||
{
|
{
|
||||||
protected sealed override Object EvaluateCore(
|
protected sealed override Object EvaluateCore(
|
||||||
EvaluationContext context,
|
EvaluationContext context,
|
||||||
@@ -63,7 +82,7 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
string node = Path.Combine(runnerRoot, "externals", "node12", "bin", $"node{IOUtil.ExeExtension}");
|
string node = Path.Combine(runnerRoot, "externals", "node12", "bin", $"node{IOUtil.ExeExtension}");
|
||||||
string hashFilesScript = Path.Combine(binDir, "hashFiles");
|
string hashFilesScript = Path.Combine(binDir, "hashFiles");
|
||||||
var hashResult = string.Empty;
|
var hashResult = string.Empty;
|
||||||
var p = new ProcessInvoker(new HashFilesTrace(context.Trace));
|
var p = new ProcessInvoker(new FunctionTrace(context.Trace));
|
||||||
p.ErrorDataReceived += ((_, data) =>
|
p.ErrorDataReceived += ((_, data) =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(data.Data) && data.Data.StartsWith("__OUTPUT__") && data.Data.EndsWith("__OUTPUT__"))
|
if (!string.IsNullOrEmpty(data.Data) && data.Data.StartsWith("__OUTPUT__") && data.Data.EndsWith("__OUTPUT__"))
|
||||||
@@ -103,24 +122,5 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
|
|
||||||
return hashResult;
|
return hashResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class HashFilesTrace : ITraceWriter
|
|
||||||
{
|
|
||||||
private GitHub.DistributedTask.Expressions2.ITraceWriter _trace;
|
|
||||||
|
|
||||||
public HashFilesTrace(GitHub.DistributedTask.Expressions2.ITraceWriter trace)
|
|
||||||
{
|
|
||||||
_trace = trace;
|
|
||||||
}
|
|
||||||
public void Info(string message)
|
|
||||||
{
|
|
||||||
_trace.Info(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Verbose(string message)
|
|
||||||
{
|
|
||||||
_trace.Info(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
162
src/Runner.Worker/ExpressionManager.cs
Normal file
162
src/Runner.Worker/ExpressionManager.cs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using GitHub.DistributedTask.Expressions2;
|
||||||
|
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||||
|
using PipelineTemplateConstants = GitHub.DistributedTask.Pipelines.ObjectTemplating.PipelineTemplateConstants;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Worker
|
||||||
|
{
|
||||||
|
[ServiceLocator(Default = typeof(ExpressionManager))]
|
||||||
|
public interface IExpressionManager : IRunnerService
|
||||||
|
{
|
||||||
|
ConditionResult Evaluate(IExecutionContext context, string condition, bool hostTracingOnly = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ExpressionManager : RunnerService, IExpressionManager
|
||||||
|
{
|
||||||
|
public ConditionResult Evaluate(IExecutionContext executionContext, string condition, bool hostTracingOnly = false)
|
||||||
|
{
|
||||||
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
|
|
||||||
|
ConditionResult result = new ConditionResult();
|
||||||
|
var expressionTrace = new TraceWriter(Trace, hostTracingOnly ? null : executionContext);
|
||||||
|
var tree = Parse(executionContext, expressionTrace, condition);
|
||||||
|
var expressionResult = tree.Evaluate(expressionTrace, HostContext.SecretMasker, state: executionContext, options: null);
|
||||||
|
result.Value = expressionResult.IsTruthy;
|
||||||
|
result.Trace = expressionTrace.Trace;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IExpressionNode Parse(IExecutionContext executionContext, TraceWriter expressionTrace, string condition)
|
||||||
|
{
|
||||||
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(condition))
|
||||||
|
{
|
||||||
|
condition = $"{PipelineTemplateConstants.Success}()";
|
||||||
|
}
|
||||||
|
|
||||||
|
var parser = new ExpressionParser();
|
||||||
|
var namedValues = executionContext.ExpressionValues.Keys.Select(x => new NamedValueInfo<ContextValueNode>(x)).ToArray();
|
||||||
|
var functions = new IFunctionInfo[]
|
||||||
|
{
|
||||||
|
new FunctionInfo<AlwaysNode>(name: Constants.Expressions.Always, minParameters: 0, maxParameters: 0),
|
||||||
|
new FunctionInfo<CancelledNode>(name: Constants.Expressions.Cancelled, minParameters: 0, maxParameters: 0),
|
||||||
|
new FunctionInfo<FailureNode>(name: Constants.Expressions.Failure, minParameters: 0, maxParameters: 0),
|
||||||
|
new FunctionInfo<SuccessNode>(name: Constants.Expressions.Success, minParameters: 0, maxParameters: 0),
|
||||||
|
};
|
||||||
|
return parser.CreateTree(condition, expressionTrace, namedValues, functions) ?? new SuccessNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TraceWriter : DistributedTask.Expressions2.ITraceWriter
|
||||||
|
{
|
||||||
|
private readonly IExecutionContext _executionContext;
|
||||||
|
private readonly Tracing _trace;
|
||||||
|
private readonly StringBuilder _traceBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
public string Trace => _traceBuilder.ToString();
|
||||||
|
|
||||||
|
public TraceWriter(Tracing trace, IExecutionContext executionContext)
|
||||||
|
{
|
||||||
|
ArgUtil.NotNull(trace, nameof(trace));
|
||||||
|
_trace = trace;
|
||||||
|
_executionContext = executionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Info(string message)
|
||||||
|
{
|
||||||
|
_trace.Info(message);
|
||||||
|
_executionContext?.Debug(message);
|
||||||
|
_traceBuilder.AppendLine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Verbose(string message)
|
||||||
|
{
|
||||||
|
_trace.Verbose(message);
|
||||||
|
_executionContext?.Debug(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class AlwaysNode : Function
|
||||||
|
{
|
||||||
|
protected override Object EvaluateCore(EvaluationContext context, out ResultMemory resultMemory)
|
||||||
|
{
|
||||||
|
resultMemory = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class CancelledNode : Function
|
||||||
|
{
|
||||||
|
protected sealed override object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
||||||
|
{
|
||||||
|
resultMemory = null;
|
||||||
|
var executionContext = evaluationContext.State as IExecutionContext;
|
||||||
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
|
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
||||||
|
return jobStatus == ActionResult.Cancelled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FailureNode : Function
|
||||||
|
{
|
||||||
|
protected sealed override object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
||||||
|
{
|
||||||
|
resultMemory = null;
|
||||||
|
var executionContext = evaluationContext.State as IExecutionContext;
|
||||||
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
|
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
||||||
|
return jobStatus == ActionResult.Failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class SuccessNode : Function
|
||||||
|
{
|
||||||
|
protected sealed override object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
||||||
|
{
|
||||||
|
resultMemory = null;
|
||||||
|
var executionContext = evaluationContext.State as IExecutionContext;
|
||||||
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
|
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
||||||
|
return jobStatus == ActionResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class ContextValueNode : NamedValue
|
||||||
|
{
|
||||||
|
protected override Object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
||||||
|
{
|
||||||
|
resultMemory = null;
|
||||||
|
var jobContext = evaluationContext.State as IExecutionContext;
|
||||||
|
ArgUtil.NotNull(jobContext, nameof(jobContext));
|
||||||
|
return jobContext.ExpressionValues[Name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConditionResult
|
||||||
|
{
|
||||||
|
public ConditionResult(bool value = false, string trace = null)
|
||||||
|
{
|
||||||
|
this.Value = value;
|
||||||
|
this.Trace = trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Value { get; set; }
|
||||||
|
public string Trace { get; set; }
|
||||||
|
|
||||||
|
public static implicit operator ConditionResult(bool value)
|
||||||
|
{
|
||||||
|
return new ConditionResult(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using PipelineTemplateConstants = GitHub.DistributedTask.Pipelines.ObjectTemplating.PipelineTemplateConstants;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Expressions
|
|
||||||
{
|
|
||||||
public sealed class AlwaysFunction : Function
|
|
||||||
{
|
|
||||||
protected override Object EvaluateCore(EvaluationContext context, out ResultMemory resultMemory)
|
|
||||||
{
|
|
||||||
resultMemory = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using PipelineTemplateConstants = GitHub.DistributedTask.Pipelines.ObjectTemplating.PipelineTemplateConstants;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Expressions
|
|
||||||
{
|
|
||||||
public sealed class CancelledFunction : Function
|
|
||||||
{
|
|
||||||
protected sealed override object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
|
||||||
{
|
|
||||||
resultMemory = null;
|
|
||||||
var templateContext = evaluationContext.State as TemplateContext;
|
|
||||||
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
|
||||||
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
|
||||||
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
|
||||||
return jobStatus == ActionResult.Cancelled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using PipelineTemplateConstants = GitHub.DistributedTask.Pipelines.ObjectTemplating.PipelineTemplateConstants;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Expressions
|
|
||||||
{
|
|
||||||
public sealed class FailureFunction : Function
|
|
||||||
{
|
|
||||||
protected sealed override object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
|
||||||
{
|
|
||||||
resultMemory = null;
|
|
||||||
var templateContext = evaluationContext.State as TemplateContext;
|
|
||||||
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
|
||||||
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
|
||||||
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
|
||||||
return jobStatus == ActionResult.Failure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using PipelineTemplateConstants = GitHub.DistributedTask.Pipelines.ObjectTemplating.PipelineTemplateConstants;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Expressions
|
|
||||||
{
|
|
||||||
public sealed class SuccessFunction : Function
|
|
||||||
{
|
|
||||||
protected sealed override object EvaluateCore(EvaluationContext evaluationContext, out ResultMemory resultMemory)
|
|
||||||
{
|
|
||||||
resultMemory = null;
|
|
||||||
var templateContext = evaluationContext.State as TemplateContext;
|
|
||||||
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
|
||||||
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
|
||||||
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
|
||||||
return jobStatus == ActionResult.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
"action",
|
"action",
|
||||||
"actor",
|
"actor",
|
||||||
"api_url", // temp for GHES alpha release
|
|
||||||
"base_ref",
|
"base_ref",
|
||||||
"event_name",
|
"event_name",
|
||||||
"event_path",
|
"event_path",
|
||||||
@@ -18,11 +17,9 @@ namespace GitHub.Runner.Worker
|
|||||||
"job",
|
"job",
|
||||||
"ref",
|
"ref",
|
||||||
"repository",
|
"repository",
|
||||||
"repository_owner",
|
|
||||||
"run_id",
|
"run_id",
|
||||||
"run_number",
|
"run_number",
|
||||||
"sha",
|
"sha",
|
||||||
"url", // temp for GHES alpha release
|
|
||||||
"workflow",
|
"workflow",
|
||||||
"workspace",
|
"workspace",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,14 +97,14 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var extraExpressionValues = new Dictionary<string, PipelineContextData>(StringComparer.OrdinalIgnoreCase);
|
var evaluateContext = new Dictionary<string, PipelineContextData>(StringComparer.OrdinalIgnoreCase);
|
||||||
extraExpressionValues["inputs"] = inputsContext;
|
evaluateContext["inputs"] = inputsContext;
|
||||||
|
|
||||||
var manifestManager = HostContext.GetService<IActionManifestManager>();
|
var manifestManager = HostContext.GetService<IActionManifestManager>();
|
||||||
if (Data.Arguments != null)
|
if (Data.Arguments != null)
|
||||||
{
|
{
|
||||||
container.ContainerEntryPointArgs = "";
|
container.ContainerEntryPointArgs = "";
|
||||||
var evaluatedArgs = manifestManager.EvaluateContainerArguments(ExecutionContext, Data.Arguments, extraExpressionValues);
|
var evaluatedArgs = manifestManager.EvaluateContainerArguments(ExecutionContext, Data.Arguments, evaluateContext);
|
||||||
foreach (var arg in evaluatedArgs)
|
foreach (var arg in evaluatedArgs)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(arg))
|
if (!string.IsNullOrEmpty(arg))
|
||||||
@@ -124,7 +124,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
if (Data.Environment != null)
|
if (Data.Environment != null)
|
||||||
{
|
{
|
||||||
var evaluatedEnv = manifestManager.EvaluateContainerEnvironment(ExecutionContext, Data.Environment, extraExpressionValues);
|
var evaluatedEnv = manifestManager.EvaluateContainerEnvironment(ExecutionContext, Data.Environment, evaluateContext);
|
||||||
foreach (var env in evaluatedEnv)
|
foreach (var env in evaluatedEnv)
|
||||||
{
|
{
|
||||||
if (!this.Environment.ContainsKey(env.Key))
|
if (!this.Environment.ContainsKey(env.Key))
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
@@ -128,23 +127,12 @@ namespace GitHub.Runner.Worker
|
|||||||
context.SetRunnerContext("workspace", Path.Combine(_workDirectory, trackingConfig.PipelineDirectory));
|
context.SetRunnerContext("workspace", Path.Combine(_workDirectory, trackingConfig.PipelineDirectory));
|
||||||
context.SetGitHubContext("workspace", Path.Combine(_workDirectory, trackingConfig.WorkspaceDirectory));
|
context.SetGitHubContext("workspace", Path.Combine(_workDirectory, trackingConfig.WorkspaceDirectory));
|
||||||
|
|
||||||
// Temporary hack for GHES alpha
|
|
||||||
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
|
||||||
var runnerSettings = configurationStore.GetSettings();
|
|
||||||
if (!runnerSettings.IsHostedServer && !string.IsNullOrEmpty(runnerSettings.GitHubUrl))
|
|
||||||
{
|
|
||||||
var url = new Uri(runnerSettings.GitHubUrl);
|
|
||||||
var portInfo = url.IsDefaultPort ? string.Empty : $":{url.Port.ToString(CultureInfo.InvariantCulture)}";
|
|
||||||
context.SetGitHubContext("url", $"{url.Scheme}://{url.Host}{portInfo}");
|
|
||||||
context.SetGitHubContext("api_url", $"{url.Scheme}://api.{url.Host}{portInfo}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the job-level environment variables
|
// Evaluate the job-level environment variables
|
||||||
context.Debug("Evaluating job-level environment variables");
|
context.Debug("Evaluating job-level environment variables");
|
||||||
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
||||||
foreach (var token in message.EnvironmentVariables)
|
foreach (var token in message.EnvironmentVariables)
|
||||||
{
|
{
|
||||||
var environmentVariables = templateEvaluator.EvaluateStepEnvironment(token, jobContext.ExpressionValues, jobContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer);
|
var environmentVariables = templateEvaluator.EvaluateStepEnvironment(token, jobContext.ExpressionValues, VarUtil.EnvironmentVariableKeyComparer);
|
||||||
foreach (var pair in environmentVariables)
|
foreach (var pair in environmentVariables)
|
||||||
{
|
{
|
||||||
context.EnvironmentVariables[pair.Key] = pair.Value ?? string.Empty;
|
context.EnvironmentVariables[pair.Key] = pair.Value ?? string.Empty;
|
||||||
@@ -154,7 +142,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Evaluate the job container
|
// Evaluate the job container
|
||||||
context.Debug("Evaluating job container");
|
context.Debug("Evaluating job container");
|
||||||
var container = templateEvaluator.EvaluateJobContainer(message.JobContainer, jobContext.ExpressionValues, jobContext.ExpressionFunctions);
|
var container = templateEvaluator.EvaluateJobContainer(message.JobContainer, jobContext.ExpressionValues);
|
||||||
if (container != null)
|
if (container != null)
|
||||||
{
|
{
|
||||||
jobContext.Container = new Container.ContainerInfo(HostContext, container);
|
jobContext.Container = new Container.ContainerInfo(HostContext, container);
|
||||||
@@ -162,7 +150,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Evaluate the job service containers
|
// Evaluate the job service containers
|
||||||
context.Debug("Evaluating job service containers");
|
context.Debug("Evaluating job service containers");
|
||||||
var serviceContainers = templateEvaluator.EvaluateJobServiceContainers(message.JobServiceContainers, jobContext.ExpressionValues, jobContext.ExpressionFunctions);
|
var serviceContainers = templateEvaluator.EvaluateJobServiceContainers(message.JobServiceContainers, jobContext.ExpressionValues);
|
||||||
if (serviceContainers?.Count > 0)
|
if (serviceContainers?.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var pair in serviceContainers)
|
foreach (var pair in serviceContainers)
|
||||||
@@ -182,7 +170,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
context.JobDefaults["run"] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
context.JobDefaults["run"] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var defaultsRun = defaults.First(x => string.Equals(x.Key.AssertString("defaults key").Value, "run", StringComparison.OrdinalIgnoreCase));
|
var defaultsRun = defaults.First(x => string.Equals(x.Key.AssertString("defaults key").Value, "run", StringComparison.OrdinalIgnoreCase));
|
||||||
var jobDefaults = templateEvaluator.EvaluateJobDefaultsRun(defaultsRun.Value, jobContext.ExpressionValues, jobContext.ExpressionFunctions);
|
var jobDefaults = templateEvaluator.EvaluateJobDefaultsRun(defaultsRun.Value, jobContext.ExpressionValues);
|
||||||
foreach (var pair in jobDefaults)
|
foreach (var pair in jobDefaults)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(pair.Value))
|
if (!string.IsNullOrEmpty(pair.Value))
|
||||||
@@ -349,7 +337,7 @@ namespace GitHub.Runner.Worker
|
|||||||
context.ExpressionValues["steps"] = context.StepsContext.GetScope(context.ScopeName);
|
context.ExpressionValues["steps"] = context.StepsContext.GetScope(context.ScopeName);
|
||||||
|
|
||||||
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
||||||
var outputs = templateEvaluator.EvaluateJobOutput(message.JobOutputs, context.ExpressionValues, context.ExpressionFunctions);
|
var outputs = templateEvaluator.EvaluateJobOutput(message.JobOutputs, context.ExpressionValues);
|
||||||
foreach (var output in outputs)
|
foreach (var output in outputs)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(output.Value))
|
if (string.IsNullOrEmpty(output.Value))
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
@@ -8,13 +10,8 @@ using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Expressions;
|
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -66,7 +63,11 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
var step = jobContext.JobSteps.Dequeue();
|
var step = jobContext.JobSteps.Dequeue();
|
||||||
var nextStep = jobContext.JobSteps.Count > 0 ? jobContext.JobSteps.Peek() : null;
|
IStep nextStep = null;
|
||||||
|
if (jobContext.JobSteps.Count > 0)
|
||||||
|
{
|
||||||
|
nextStep = jobContext.JobSteps.Peek();
|
||||||
|
}
|
||||||
|
|
||||||
Trace.Info($"Processing step: DisplayName='{step.DisplayName}'");
|
Trace.Info($"Processing step: DisplayName='{step.DisplayName}'");
|
||||||
ArgUtil.NotNull(step.ExecutionContext, nameof(step.ExecutionContext));
|
ArgUtil.NotNull(step.ExecutionContext, nameof(step.ExecutionContext));
|
||||||
@@ -75,13 +76,6 @@ namespace GitHub.Runner.Worker
|
|||||||
// Start
|
// Start
|
||||||
step.ExecutionContext.Start();
|
step.ExecutionContext.Start();
|
||||||
|
|
||||||
// Expression functions
|
|
||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<AlwaysFunction>(PipelineTemplateConstants.Always, 0, 0));
|
|
||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<CancelledFunction>(PipelineTemplateConstants.Cancelled, 0, 0));
|
|
||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<FailureFunction>(PipelineTemplateConstants.Failure, 0, 0));
|
|
||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<SuccessFunction>(PipelineTemplateConstants.Success, 0, 0));
|
|
||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<HashFilesFunction>(PipelineTemplateConstants.HashFiles, 1, byte.MaxValue));
|
|
||||||
|
|
||||||
// Initialize scope
|
// Initialize scope
|
||||||
if (InitializeScope(step, scopeInputs))
|
if (InitializeScope(step, scopeInputs))
|
||||||
{
|
{
|
||||||
@@ -105,13 +99,14 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Evaluate and merge action's env block to env context
|
// Evaluate and merge action's env block to env context
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer);
|
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, VarUtil.EnvironmentVariableKeyComparer);
|
||||||
foreach (var env in actionEnvironment)
|
foreach (var env in actionEnvironment)
|
||||||
{
|
{
|
||||||
envContext[env.Key] = new StringContextData(env.Value ?? string.Empty);
|
envContext[env.Key] = new StringContextData(env.Value ?? string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var expressionManager = HostContext.GetService<IExpressionManager>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Register job cancellation call back only if job cancellation token not been fire before each step run
|
// Register job cancellation call back only if job cancellation token not been fire before each step run
|
||||||
@@ -125,29 +120,28 @@ namespace GitHub.Runner.Worker
|
|||||||
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
||||||
|
|
||||||
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
||||||
var conditionReTestTraceWriter = new ConditionTraceWriter(Trace, null); // host tracing only
|
ConditionResult conditionReTestResult;
|
||||||
var conditionReTestResult = false;
|
|
||||||
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown.");
|
step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown.");
|
||||||
|
conditionReTestResult = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionReTestTraceWriter);
|
conditionReTestResult = expressionManager.Evaluate(step.ExecutionContext, step.Condition, hostTracingOnly: true);
|
||||||
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
|
||||||
conditionReTestResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Cancel the step since we get exception while re-evaluate step condition.
|
// Cancel the step since we get exception while re-evaluate step condition.
|
||||||
Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
|
Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
|
||||||
step.ExecutionContext.Error(ex);
|
step.ExecutionContext.Error(ex);
|
||||||
|
conditionReTestResult = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conditionReTestResult)
|
if (!conditionReTestResult.Value)
|
||||||
{
|
{
|
||||||
// Cancel the step.
|
// Cancel the step.
|
||||||
Trace.Info("Cancel current running step.");
|
Trace.Info("Cancel current running step.");
|
||||||
@@ -167,35 +161,34 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Evaluate condition.
|
// Evaluate condition.
|
||||||
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
|
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
|
||||||
var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext);
|
Exception conditionEvaluateError = null;
|
||||||
var conditionResult = false;
|
ConditionResult conditionResult;
|
||||||
var conditionEvaluateError = default(Exception);
|
|
||||||
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown.");
|
step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown.");
|
||||||
|
conditionResult = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
conditionResult = expressionManager.Evaluate(step.ExecutionContext, step.Condition);
|
||||||
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
|
||||||
conditionResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Trace.Info("Caught exception from expression.");
|
Trace.Info("Caught exception from expression.");
|
||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
|
conditionResult = false;
|
||||||
conditionEvaluateError = ex;
|
conditionEvaluateError = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no evaluate error but condition is false
|
// no evaluate error but condition is false
|
||||||
if (!conditionResult && conditionEvaluateError == null)
|
if (!conditionResult.Value && conditionEvaluateError == null)
|
||||||
{
|
{
|
||||||
// Condition == false
|
// Condition == false
|
||||||
Trace.Info("Skipping step due to condition evaluation.");
|
Trace.Info("Skipping step due to condition evaluation.");
|
||||||
CompleteStep(step, nextStep, TaskResult.Skipped, resultCode: conditionTraceWriter.Trace);
|
CompleteStep(step, nextStep, TaskResult.Skipped, resultCode: conditionResult.Trace);
|
||||||
}
|
}
|
||||||
else if (conditionEvaluateError != null)
|
else if (conditionEvaluateError != null)
|
||||||
{
|
{
|
||||||
@@ -255,7 +248,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
timeoutMinutes = templateEvaluator.EvaluateStepTimeout(step.Timeout, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions);
|
timeoutMinutes = templateEvaluator.EvaluateStepTimeout(step.Timeout, step.ExecutionContext.ExpressionValues);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -346,7 +339,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var continueOnError = false;
|
var continueOnError = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
continueOnError = templateEvaluator.EvaluateStepContinueOnError(step.ContinueOnError, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions);
|
continueOnError = templateEvaluator.EvaluateStepContinueOnError(step.ContinueOnError, step.ExecutionContext.ExpressionValues);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -399,7 +392,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var inputs = default(DictionaryContextData);
|
var inputs = default(DictionaryContextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
inputs = templateEvaluator.EvaluateStepScopeInputs(scope.Inputs, executionContext.ExpressionValues, executionContext.ExpressionFunctions);
|
inputs = templateEvaluator.EvaluateStepScopeInputs(scope.Inputs, executionContext.ExpressionValues);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -455,7 +448,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var outputs = default(DictionaryContextData);
|
var outputs = default(DictionaryContextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
outputs = templateEvaluator.EvaluateStepScopeOutputs(scope.Outputs, executionContext.ExpressionValues, executionContext.ExpressionFunctions);
|
outputs = templateEvaluator.EvaluateStepScopeOutputs(scope.Outputs, executionContext.ExpressionValues);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -483,43 +476,5 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
executionContext.Complete(result, resultCode: resultCode);
|
executionContext.Complete(result, resultCode: resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class ConditionTraceWriter : ObjectTemplating::ITraceWriter
|
|
||||||
{
|
|
||||||
private readonly IExecutionContext _executionContext;
|
|
||||||
private readonly Tracing _trace;
|
|
||||||
private readonly StringBuilder _traceBuilder = new StringBuilder();
|
|
||||||
|
|
||||||
public string Trace => _traceBuilder.ToString();
|
|
||||||
|
|
||||||
public ConditionTraceWriter(Tracing trace, IExecutionContext executionContext)
|
|
||||||
{
|
|
||||||
ArgUtil.NotNull(trace, nameof(trace));
|
|
||||||
_trace = trace;
|
|
||||||
_executionContext = executionContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Error(string format, params Object[] args)
|
|
||||||
{
|
|
||||||
var message = StringUtil.Format(format, args);
|
|
||||||
_trace.Error(message);
|
|
||||||
_executionContext?.Debug(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Info(string format, params Object[] args)
|
|
||||||
{
|
|
||||||
var message = StringUtil.Format(format, args);
|
|
||||||
_trace.Info(message);
|
|
||||||
_executionContext?.Debug(message);
|
|
||||||
_traceBuilder.AppendLine(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Verbose(string format, params Object[] args)
|
|
||||||
{
|
|
||||||
var message = StringUtil.Format(format, args);
|
|
||||||
_trace.Verbose(message);
|
|
||||||
_executionContext?.Debug(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,7 @@
|
|||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using GitHub.DistributedTask.Expressions2.Sdk.Functions;
|
|||||||
|
|
||||||
namespace GitHub.DistributedTask.Expressions2
|
namespace GitHub.DistributedTask.Expressions2
|
||||||
{
|
{
|
||||||
internal static class ExpressionConstants
|
public static class ExpressionConstants
|
||||||
{
|
{
|
||||||
static ExpressionConstants()
|
static ExpressionConstants()
|
||||||
{
|
{
|
||||||
@@ -16,6 +16,7 @@ namespace GitHub.DistributedTask.Expressions2
|
|||||||
AddFunction<StartsWith>("startsWith", 2, 2);
|
AddFunction<StartsWith>("startsWith", 2, 2);
|
||||||
AddFunction<ToJson>("toJson", 1, 1);
|
AddFunction<ToJson>("toJson", 1, 1);
|
||||||
AddFunction<FromJson>("fromJson", 1, 1);
|
AddFunction<FromJson>("fromJson", 1, 1);
|
||||||
|
AddFunction<HashFiles>("hashFiles", 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddFunction<T>(String name, Int32 minParameters, Int32 maxParameters)
|
private static void AddFunction<T>(String name, Int32 minParameters, Int32 maxParameters)
|
||||||
@@ -24,6 +25,12 @@ namespace GitHub.DistributedTask.Expressions2
|
|||||||
WellKnownFunctions.Add(name, new FunctionInfo<T>(name, minParameters, maxParameters));
|
WellKnownFunctions.Add(name, new FunctionInfo<T>(name, minParameters, maxParameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void UpdateFunction<T>(String name, Int32 minParameters, Int32 maxParameters)
|
||||||
|
where T : Function, new()
|
||||||
|
{
|
||||||
|
WellKnownFunctions[name] = new FunctionInfo<T>(name, minParameters, maxParameters);
|
||||||
|
}
|
||||||
|
|
||||||
internal static readonly String False = "false";
|
internal static readonly String False = "false";
|
||||||
internal static readonly String Infinity = "Infinity";
|
internal static readonly String Infinity = "Infinity";
|
||||||
internal static readonly Int32 MaxDepth = 50;
|
internal static readonly Int32 MaxDepth = 50;
|
||||||
|
|||||||
122
src/Sdk/DTExpressions2/Expressions2/Sdk/Functions/HashFiles.cs
Normal file
122
src/Sdk/DTExpressions2/Expressions2/Sdk/Functions/HashFiles.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Minimatch;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
|
namespace GitHub.DistributedTask.Expressions2.Sdk.Functions
|
||||||
|
{
|
||||||
|
internal sealed class HashFiles : Function
|
||||||
|
{
|
||||||
|
protected sealed override Object EvaluateCore(
|
||||||
|
EvaluationContext context,
|
||||||
|
out ResultMemory resultMemory)
|
||||||
|
{
|
||||||
|
resultMemory = null;
|
||||||
|
|
||||||
|
// hashFiles() only works on the runner and only works with files under GITHUB_WORKSPACE
|
||||||
|
// Since GITHUB_WORKSPACE is set by runner, I am using that as the fact of this code runs on server or runner.
|
||||||
|
if (context.State is ObjectTemplating.TemplateContext templateContext &&
|
||||||
|
templateContext.ExpressionValues.TryGetValue(PipelineTemplateConstants.GitHub, out var githubContextData) &&
|
||||||
|
githubContextData is DictionaryContextData githubContext &&
|
||||||
|
githubContext.TryGetValue(PipelineTemplateConstants.Workspace, out var workspace) == true &&
|
||||||
|
workspace is StringContextData workspaceData)
|
||||||
|
{
|
||||||
|
string searchRoot = workspaceData.Value;
|
||||||
|
string pattern = Parameters[0].Evaluate(context).ConvertToString();
|
||||||
|
|
||||||
|
// Convert slashes on Windows
|
||||||
|
if (s_isWindows)
|
||||||
|
{
|
||||||
|
pattern = pattern.Replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root the pattern
|
||||||
|
if (!Path.IsPathRooted(pattern))
|
||||||
|
{
|
||||||
|
var patternRoot = s_isWindows ? searchRoot.Replace('\\', '/').TrimEnd('/') : searchRoot.TrimEnd('/');
|
||||||
|
pattern = string.Concat(patternRoot, "/", pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all files
|
||||||
|
context.Trace.Info($"Search root directory: '{searchRoot}'");
|
||||||
|
context.Trace.Info($"Search pattern: '{pattern}'");
|
||||||
|
var files = Directory.GetFiles(searchRoot, "*", SearchOption.AllDirectories)
|
||||||
|
.Select(x => s_isWindows ? x.Replace('\\', '/') : x)
|
||||||
|
.OrderBy(x => x, StringComparer.Ordinal)
|
||||||
|
.ToList();
|
||||||
|
if (files.Count == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"hashFiles('{ExpressionUtility.StringEscape(pattern)}') failed. Directory '{searchRoot}' is empty");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Trace.Info($"Found {files.Count} files");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match
|
||||||
|
var matcher = new Minimatcher(pattern, s_minimatchOptions);
|
||||||
|
files = matcher.Filter(files)
|
||||||
|
.Select(x => s_isWindows ? x.Replace('/', '\\') : x)
|
||||||
|
.ToList();
|
||||||
|
if (files.Count == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"hashFiles('{ExpressionUtility.StringEscape(pattern)}') failed. Search pattern '{pattern}' doesn't match any file under '{searchRoot}'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Trace.Info($"{files.Count} matches to hash");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash each file
|
||||||
|
List<byte> filesSha256 = new List<byte>();
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
context.Trace.Info($"Hash {file}");
|
||||||
|
using (SHA256 sha256hash = SHA256.Create())
|
||||||
|
{
|
||||||
|
using (var fileStream = File.OpenRead(file))
|
||||||
|
{
|
||||||
|
filesSha256.AddRange(sha256hash.ComputeHash(fileStream));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash the hashes
|
||||||
|
using (SHA256 sha256hash = SHA256.Create())
|
||||||
|
{
|
||||||
|
var hashBytes = sha256hash.ComputeHash(filesSha256.ToArray());
|
||||||
|
StringBuilder hashString = new StringBuilder();
|
||||||
|
for (int i = 0; i < hashBytes.Length; i++)
|
||||||
|
{
|
||||||
|
hashString.Append(hashBytes[i].ToString("x2"));
|
||||||
|
}
|
||||||
|
var result = hashString.ToString();
|
||||||
|
context.Trace.Info($"Final hash result: '{result}'");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("'hashfiles' expression function is only supported under runner context.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly bool s_isWindows = Environment.OSVersion.Platform != PlatformID.Unix && Environment.OSVersion.Platform != PlatformID.MacOSX;
|
||||||
|
|
||||||
|
// Only support basic globbing (* ? and []) and globstar (**)
|
||||||
|
private static readonly Options s_minimatchOptions = new Options
|
||||||
|
{
|
||||||
|
Dot = true,
|
||||||
|
NoBrace = true,
|
||||||
|
NoCase = s_isWindows,
|
||||||
|
NoComment = true,
|
||||||
|
NoExt = true,
|
||||||
|
NoNegate = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
|
|
||||||
@@ -23,27 +22,10 @@ namespace GitHub.DistributedTask.ObjectTemplating.Schema
|
|||||||
{
|
{
|
||||||
var context = definition[i].Value.AssertSequence($"{TemplateConstants.Context}");
|
var context = definition[i].Value.AssertSequence($"{TemplateConstants.Context}");
|
||||||
definition.RemoveAt(i);
|
definition.RemoveAt(i);
|
||||||
var readerContext = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
Context = context
|
||||||
var evaluatorContext = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
.Select(x => x.AssertString($"{TemplateConstants.Context} item").Value)
|
||||||
foreach (TemplateToken item in context)
|
.Distinct()
|
||||||
{
|
.ToArray();
|
||||||
var itemStr = item.AssertString($"{TemplateConstants.Context} item").Value;
|
|
||||||
readerContext.Add(itemStr);
|
|
||||||
|
|
||||||
// Remove min/max parameter info
|
|
||||||
var paramIndex = itemStr.IndexOf('(');
|
|
||||||
if (paramIndex > 0)
|
|
||||||
{
|
|
||||||
evaluatorContext.Add(String.Concat(itemStr.Substring(0, paramIndex + 1), ")"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
evaluatorContext.Add(itemStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReaderContext = readerContext.ToArray();
|
|
||||||
EvaluatorContext = evaluatorContext.ToArray();
|
|
||||||
}
|
}
|
||||||
else if (String.Equals(definitionKey.Value, TemplateConstants.Description, StringComparison.Ordinal))
|
else if (String.Equals(definitionKey.Value, TemplateConstants.Description, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
@@ -58,17 +40,7 @@ namespace GitHub.DistributedTask.ObjectTemplating.Schema
|
|||||||
|
|
||||||
internal abstract DefinitionType DefinitionType { get; }
|
internal abstract DefinitionType DefinitionType { get; }
|
||||||
|
|
||||||
/// <summary>
|
internal String[] Context { get; private set; } = new String[0];
|
||||||
/// Used by the template reader to determine allowed expression values and functions.
|
|
||||||
/// Also used by the template reader to validate function min/max parameters.
|
|
||||||
/// </summary>
|
|
||||||
internal String[] ReaderContext { get; private set; } = new String[0];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used by the template evaluator to determine allowed expression values and functions.
|
|
||||||
/// The min/max parameter info is omitted.
|
|
||||||
/// </summary>
|
|
||||||
internal String[] EvaluatorContext { get; private set; } = new String[0];
|
|
||||||
|
|
||||||
internal abstract void Validate(
|
internal abstract void Validate(
|
||||||
TemplateSchema schema,
|
TemplateSchema schema,
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ namespace GitHub.DistributedTask.ObjectTemplating.Schema
|
|||||||
{
|
{
|
||||||
var inherited = schema.GetDefinition(Inherits);
|
var inherited = schema.GetDefinition(Inherits);
|
||||||
|
|
||||||
if (inherited.ReaderContext.Length > 0)
|
if (inherited.Context.Length > 0)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException($"Property '{TemplateConstants.Context}' is not supported on inhertied definitions");
|
throw new NotSupportedException($"Property '{TemplateConstants.Context}' is not supported on inhertied definitions");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ namespace GitHub.DistributedTask.ObjectTemplating.Schema
|
|||||||
{
|
{
|
||||||
var nestedDefinition = schema.GetDefinition(nestedType);
|
var nestedDefinition = schema.GetDefinition(nestedType);
|
||||||
|
|
||||||
if (nestedDefinition.ReaderContext.Length > 0)
|
if (nestedDefinition.Context.Length > 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"'{name}' is a one-of definition and references another definition that defines context. This is currently not supported.");
|
throw new ArgumentException($"'{name}' is a one-of definition and references another definition that defines context. This is currently not supported.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,16 +47,7 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
var evaluator = new TemplateEvaluator(context, template, removeBytes);
|
var evaluator = new TemplateEvaluator(context, template, removeBytes);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var availableContext = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
var availableContext = new HashSet<String>(context.ExpressionValues.Keys.Concat(context.ExpressionFunctions.Select(x => $"{x.Name}({x.MinParameters},{x.MaxParameters})")));
|
||||||
foreach (var key in context.ExpressionValues.Keys)
|
|
||||||
{
|
|
||||||
availableContext.Add(key);
|
|
||||||
}
|
|
||||||
foreach (var function in context.ExpressionFunctions)
|
|
||||||
{
|
|
||||||
availableContext.Add($"{function.Name}()");
|
|
||||||
}
|
|
||||||
|
|
||||||
var definitionInfo = new DefinitionInfo(context.Schema, type, availableContext);
|
var definitionInfo = new DefinitionInfo(context.Schema, type, availableContext);
|
||||||
result = evaluator.Evaluate(definitionInfo);
|
result = evaluator.Evaluate(definitionInfo);
|
||||||
|
|
||||||
@@ -402,13 +393,14 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
Definition = m_schema.GetDefinition(name);
|
Definition = m_schema.GetDefinition(name);
|
||||||
|
|
||||||
// Determine whether to expand
|
// Determine whether to expand
|
||||||
m_allowedContext = Definition.EvaluatorContext;
|
if (Definition.Context.Length > 0)
|
||||||
if (Definition.EvaluatorContext.Length > 0)
|
|
||||||
{
|
{
|
||||||
|
m_allowedContext = Definition.Context;
|
||||||
Expand = m_availableContext.IsSupersetOf(m_allowedContext);
|
Expand = m_availableContext.IsSupersetOf(m_allowedContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
m_allowedContext = new String[0];
|
||||||
Expand = false;
|
Expand = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,9 +416,9 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
Definition = m_schema.GetDefinition(name);
|
Definition = m_schema.GetDefinition(name);
|
||||||
|
|
||||||
// Determine whether to expand
|
// Determine whether to expand
|
||||||
if (Definition.EvaluatorContext.Length > 0)
|
if (Definition.Context.Length > 0)
|
||||||
{
|
{
|
||||||
m_allowedContext = new HashSet<String>(parent.m_allowedContext.Concat(Definition.EvaluatorContext), StringComparer.OrdinalIgnoreCase).ToArray();
|
m_allowedContext = new HashSet<String>(parent.m_allowedContext.Concat(Definition.Context)).ToArray();
|
||||||
Expand = m_availableContext.IsSupersetOf(m_allowedContext);
|
Expand = m_availableContext.IsSupersetOf(m_allowedContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -49,14 +49,6 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
m_errors = new List<TemplateValidationError>(errors ?? Enumerable.Empty<TemplateValidationError>());
|
m_errors = new List<TemplateValidationError>(errors ?? Enumerable.Empty<TemplateValidationError>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemplateValidationException(
|
|
||||||
String message,
|
|
||||||
IEnumerable<TemplateValidationError> errors)
|
|
||||||
: this(message)
|
|
||||||
{
|
|
||||||
m_errors = new List<TemplateValidationError>(errors ?? Enumerable.Empty<TemplateValidationError>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemplateValidationException(String message)
|
public TemplateValidationException(String message)
|
||||||
: base(message)
|
: base(message)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -780,8 +780,15 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
// Lookup the definition
|
// Lookup the definition
|
||||||
Definition = m_schema.GetDefinition(name);
|
Definition = m_schema.GetDefinition(name);
|
||||||
|
|
||||||
// Record allowed context
|
// Determine whether to expand
|
||||||
AllowedContext = Definition.ReaderContext;
|
if (Definition.Context.Length > 0)
|
||||||
|
{
|
||||||
|
AllowedContext = Definition.Context;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AllowedContext = new String[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefinitionInfo(
|
public DefinitionInfo(
|
||||||
@@ -793,10 +800,10 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
// Lookup the definition
|
// Lookup the definition
|
||||||
Definition = m_schema.GetDefinition(name);
|
Definition = m_schema.GetDefinition(name);
|
||||||
|
|
||||||
// Record allowed context
|
// Determine whether to expand
|
||||||
if (Definition.ReaderContext.Length > 0)
|
if (Definition.Context.Length > 0)
|
||||||
{
|
{
|
||||||
AllowedContext = new HashSet<String>(parent.AllowedContext.Concat(Definition.ReaderContext), StringComparer.OrdinalIgnoreCase).ToArray();
|
AllowedContext = new HashSet<String>(parent.AllowedContext.Concat(Definition.Context)).ToArray();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.ObjectTemplating
|
namespace GitHub.DistributedTask.ObjectTemplating
|
||||||
@@ -42,7 +41,7 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < 50; i++)
|
for (int i = 0; i < 50; i++)
|
||||||
{
|
{
|
||||||
String message = !String.IsNullOrEmpty(messagePrefix) ? $"{messagePrefix} {ex.Message}" : ex.ToString();
|
String message = !String.IsNullOrEmpty(messagePrefix) ? $"{messagePrefix} {ex.Message}" : ex.Message;
|
||||||
Add(new TemplateValidationError(message));
|
Add(new TemplateValidationError(message));
|
||||||
if (ex.InnerException == null)
|
if (ex.InnerException == null)
|
||||||
{
|
{
|
||||||
@@ -89,23 +88,6 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Throws <c ref="TemplateValidationException" /> if any errors.
|
|
||||||
/// <param name="prefix">The error message prefix</param>
|
|
||||||
/// </summary>
|
|
||||||
public void Check(String prefix)
|
|
||||||
{
|
|
||||||
if (String.IsNullOrEmpty(prefix))
|
|
||||||
{
|
|
||||||
this.Check();
|
|
||||||
}
|
|
||||||
else if (m_errors.Count > 0)
|
|
||||||
{
|
|
||||||
var message = $"{prefix.Trim()} {String.Join(",", m_errors.Select(e => e.Message))}";
|
|
||||||
throw new TemplateValidationException(message, m_errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
m_errors.Clear();
|
m_errors.Clear();
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||||
using GitHub.Services.WebApi.Internal;
|
using GitHub.Services.WebApi.Internal;
|
||||||
@@ -37,29 +35,11 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tokens
|
|||||||
String[] allowedContext,
|
String[] allowedContext,
|
||||||
out Exception ex)
|
out Exception ex)
|
||||||
{
|
{
|
||||||
// Create dummy named values and functions
|
// Create dummy allowed contexts
|
||||||
var namedValues = new List<INamedValueInfo>();
|
INamedValueInfo[] namedValues = null;
|
||||||
var functions = new List<IFunctionInfo>();
|
|
||||||
if (allowedContext?.Length > 0)
|
if (allowedContext?.Length > 0)
|
||||||
{
|
{
|
||||||
foreach (var contextItem in allowedContext)
|
namedValues = allowedContext.Select(x => new NamedValueInfo<ContextValueNode>(x)).ToArray();
|
||||||
{
|
|
||||||
var match = s_function.Match(contextItem);
|
|
||||||
if (match.Success)
|
|
||||||
{
|
|
||||||
var functionName = match.Groups[1].Value;
|
|
||||||
var minParameters = Int32.Parse(match.Groups[2].Value, NumberStyles.None, CultureInfo.InvariantCulture);
|
|
||||||
var maxParametersRaw = match.Groups[3].Value;
|
|
||||||
var maxParameters = String.Equals(maxParametersRaw, TemplateConstants.MaxConstant, StringComparison.Ordinal)
|
|
||||||
? Int32.MaxValue
|
|
||||||
: Int32.Parse(maxParametersRaw, NumberStyles.None, CultureInfo.InvariantCulture);
|
|
||||||
functions.Add(new FunctionInfo<DummyFunction>(functionName, minParameters, maxParameters));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
namedValues.Add(new NamedValueInfo<ContextValueNode>(contextItem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
@@ -67,7 +47,7 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tokens
|
|||||||
ExpressionNode root = null;
|
ExpressionNode root = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
root = new ExpressionParser().CreateTree(expression, null, namedValues, functions) as ExpressionNode;
|
root = new ExpressionParser().CreateTree(expression, null, namedValues, null) as ExpressionNode;
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
ex = null;
|
ex = null;
|
||||||
@@ -80,18 +60,5 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tokens
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class DummyFunction : Function
|
|
||||||
{
|
|
||||||
protected override Object EvaluateCore(
|
|
||||||
EvaluationContext context,
|
|
||||||
out ResultMemory resultMemory)
|
|
||||||
{
|
|
||||||
resultMemory = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Regex s_function = new Regex(@"^([a-zA-Z0-9_]+)\(([0-9]+),([0-9]+|MAX)\)$", RegexOptions.Compiled);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.ObjectTemplating.Tokens
|
namespace GitHub.DistributedTask.ObjectTemplating.Tokens
|
||||||
{
|
{
|
||||||
@@ -109,43 +106,6 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tokens
|
|||||||
throw new ArgumentException($"Error while reading '{objectDescription}'. Unexpected value '{literal.ToString()}'");
|
throw new ArgumentException($"Error while reading '{objectDescription}'. Unexpected value '{literal.ToString()}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Traverses the token and checks whether all required expression values
|
|
||||||
/// and functions are provided.
|
|
||||||
/// </summary>
|
|
||||||
public static bool CheckHasRequiredContext(
|
|
||||||
this TemplateToken token,
|
|
||||||
IReadOnlyObject expressionValues,
|
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
|
||||||
var expressionTokens = token.Traverse()
|
|
||||||
.OfType<BasicExpressionToken>()
|
|
||||||
.ToArray();
|
|
||||||
var parser = new ExpressionParser();
|
|
||||||
foreach (var expressionToken in expressionTokens)
|
|
||||||
{
|
|
||||||
var tree = parser.ValidateSyntax(expressionToken.Expression, null);
|
|
||||||
foreach (var node in tree.Traverse())
|
|
||||||
{
|
|
||||||
if (node is NamedValue namedValue)
|
|
||||||
{
|
|
||||||
if (expressionValues?.Keys.Any(x => string.Equals(x, namedValue.Name, StringComparison.OrdinalIgnoreCase)) != true)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (node is Function function &&
|
|
||||||
!ExpressionConstants.WellKnownFunctions.ContainsKey(function.Name) &&
|
|
||||||
expressionFunctions?.Any(x => string.Equals(x.Name, function.Name, StringComparison.OrdinalIgnoreCase)) != true)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all tokens (depth first)
|
/// Returns all tokens (depth first)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String FetchDepth = "fetch-depth";
|
public const String FetchDepth = "fetch-depth";
|
||||||
public const String GeneratedId = "generated-id";
|
public const String GeneratedId = "generated-id";
|
||||||
public const String GitHub = "github";
|
public const String GitHub = "github";
|
||||||
public const String HashFiles = "hashFiles";
|
|
||||||
public const String Id = "id";
|
public const String Id = "id";
|
||||||
public const String If = "if";
|
public const String If = "if";
|
||||||
public const String Image = "image";
|
public const String Image = "image";
|
||||||
@@ -32,7 +31,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String Inputs = "inputs";
|
public const String Inputs = "inputs";
|
||||||
public const String Job = "job";
|
public const String Job = "job";
|
||||||
public const String JobDefaultsRun = "job-defaults-run";
|
public const String JobDefaultsRun = "job-defaults-run";
|
||||||
public const String JobIfResult = "job-if-result";
|
|
||||||
public const String JobOutputs = "job-outputs";
|
public const String JobOutputs = "job-outputs";
|
||||||
public const String Jobs = "jobs";
|
public const String Jobs = "jobs";
|
||||||
public const String Labels = "labels";
|
public const String Labels = "labels";
|
||||||
@@ -62,7 +60,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String Shell = "shell";
|
public const String Shell = "shell";
|
||||||
public const String Skipped = "skipped";
|
public const String Skipped = "skipped";
|
||||||
public const String StepEnv = "step-env";
|
public const String StepEnv = "step-env";
|
||||||
public const String StepIfResult = "step-if-result";
|
|
||||||
public const String Steps = "steps";
|
public const String Steps = "steps";
|
||||||
public const String StepsScopeInputs = "steps-scope-inputs";
|
public const String StepsScopeInputs = "steps-scope-inputs";
|
||||||
public const String StepsScopeOutputs = "steps-scope-outputs";
|
public const String StepsScopeOutputs = "steps-scope-outputs";
|
||||||
|
|||||||
@@ -16,20 +16,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
{
|
{
|
||||||
internal static class PipelineTemplateConverter
|
internal static class PipelineTemplateConverter
|
||||||
{
|
{
|
||||||
internal static Boolean ConvertToIfResult(
|
|
||||||
TemplateContext context,
|
|
||||||
TemplateToken ifResult)
|
|
||||||
{
|
|
||||||
var expression = ifResult.Traverse().FirstOrDefault(x => x is ExpressionToken);
|
|
||||||
if (expression != null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"Unexpected type '{expression.GetType().Name}' encountered while reading 'if'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var evaluationResult = EvaluationResult.CreateIntermediateResult(null, ifResult);
|
|
||||||
return evaluationResult.IsTruthy;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static Boolean? ConvertToStepContinueOnError(
|
internal static Boolean? ConvertToStepContinueOnError(
|
||||||
TemplateContext context,
|
TemplateContext context,
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk.Functions;
|
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
using GitHub.DistributedTask.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Schema;
|
using GitHub.DistributedTask.ObjectTemplating.Schema;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
@@ -14,9 +14,6 @@ using ITraceWriter = GitHub.DistributedTask.ObjectTemplating.ITraceWriter;
|
|||||||
|
|
||||||
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Evaluates parts of the workflow DOM. For example, a job strategy or step inputs.
|
|
||||||
/// </summary>
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public class PipelineTemplateEvaluator
|
public class PipelineTemplateEvaluator
|
||||||
{
|
{
|
||||||
@@ -53,14 +50,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public DictionaryContextData EvaluateStepScopeInputs(
|
public DictionaryContextData EvaluateStepScopeInputs(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(DictionaryContextData);
|
var result = default(DictionaryContextData);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsScopeInputs, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsScopeInputs, token, 0, null, omitHeader: true);
|
||||||
@@ -80,14 +76,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public DictionaryContextData EvaluateStepScopeOutputs(
|
public DictionaryContextData EvaluateStepScopeOutputs(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(DictionaryContextData);
|
var result = default(DictionaryContextData);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsScopeOutputs, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsScopeOutputs, token, 0, null, omitHeader: true);
|
||||||
@@ -107,14 +102,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public Boolean EvaluateStepContinueOnError(
|
public Boolean EvaluateStepContinueOnError(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(Boolean?);
|
var result = default(Boolean?);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.BooleanStepsContext, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.BooleanStepsContext, token, 0, null, omitHeader: true);
|
||||||
@@ -132,44 +126,16 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return result ?? false;
|
return result ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String EvaluateStepDisplayName(
|
|
||||||
TemplateToken token,
|
|
||||||
DictionaryContextData contextData,
|
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
|
||||||
var result = default(String);
|
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
|
||||||
{
|
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StringStepsContext, token, 0, null, omitHeader: true);
|
|
||||||
context.Errors.Check();
|
|
||||||
result = PipelineTemplateConverter.ConvertToStepDisplayName(context, token);
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (!(ex is TemplateValidationException))
|
|
||||||
{
|
|
||||||
context.Errors.Add(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Errors.Check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<String, String> EvaluateStepEnvironment(
|
public Dictionary<String, String> EvaluateStepEnvironment(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData,
|
||||||
IList<IFunctionInfo> expressionFunctions,
|
|
||||||
StringComparer keyComparer)
|
StringComparer keyComparer)
|
||||||
{
|
{
|
||||||
var result = default(Dictionary<String, String>);
|
var result = default(Dictionary<String, String>);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepEnv, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepEnv, token, 0, null, omitHeader: true);
|
||||||
@@ -187,44 +153,15 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return result ?? new Dictionary<String, String>(keyComparer);
|
return result ?? new Dictionary<String, String>(keyComparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean EvaluateStepIf(
|
|
||||||
TemplateToken token,
|
|
||||||
DictionaryContextData contextData,
|
|
||||||
IList<IFunctionInfo> expressionFunctions,
|
|
||||||
IEnumerable<KeyValuePair<String, Object>> expressionState)
|
|
||||||
{
|
|
||||||
var result = default(Boolean?);
|
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
|
||||||
{
|
|
||||||
var context = CreateContext(contextData, expressionFunctions, expressionState);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepIfResult, token, 0, null, omitHeader: true);
|
|
||||||
context.Errors.Check();
|
|
||||||
result = PipelineTemplateConverter.ConvertToIfResult(context, token);
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (!(ex is TemplateValidationException))
|
|
||||||
{
|
|
||||||
context.Errors.Add(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Errors.Check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result ?? throw new InvalidOperationException("Step if cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<String, String> EvaluateStepInputs(
|
public Dictionary<String, String> EvaluateStepInputs(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(Dictionary<String, String>);
|
var result = default(Dictionary<String, String>);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepWith, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepWith, token, 0, null, omitHeader: true);
|
||||||
@@ -244,14 +181,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public Int32 EvaluateStepTimeout(
|
public Int32 EvaluateStepTimeout(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(Int32?);
|
var result = default(Int32?);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.NumberStepsContext, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.NumberStepsContext, token, 0, null, omitHeader: true);
|
||||||
@@ -271,14 +207,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public JobContainer EvaluateJobContainer(
|
public JobContainer EvaluateJobContainer(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(JobContainer);
|
var result = default(JobContainer);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.Container, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.Container, token, 0, null, omitHeader: true);
|
||||||
@@ -298,14 +233,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public Dictionary<String, String> EvaluateJobOutput(
|
public Dictionary<String, String> EvaluateJobOutput(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(Dictionary<String, String>);
|
var result = default(Dictionary<String, String>);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.JobOutputs, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.JobOutputs, token, 0, null, omitHeader: true);
|
||||||
@@ -335,14 +269,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public Dictionary<String, String> EvaluateJobDefaultsRun(
|
public Dictionary<String, String> EvaluateJobDefaultsRun(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(Dictionary<String, String>);
|
var result = default(Dictionary<String, String>);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.JobDefaultsRun, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.JobDefaultsRun, token, 0, null, omitHeader: true);
|
||||||
@@ -372,14 +305,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
public IList<KeyValuePair<String, JobContainer>> EvaluateJobServiceContainers(
|
public IList<KeyValuePair<String, JobContainer>> EvaluateJobServiceContainers(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData)
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
{
|
||||||
var result = default(List<KeyValuePair<String, JobContainer>>);
|
var result = default(List<KeyValuePair<String, JobContainer>>);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
var context = CreateContext(contextData);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.Services, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.Services, token, 0, null, omitHeader: true);
|
||||||
@@ -397,10 +329,62 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TemplateContext CreateContext(
|
public Boolean TryEvaluateStepDisplayName(
|
||||||
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData,
|
||||||
IList<IFunctionInfo> expressionFunctions,
|
out String stepName)
|
||||||
IEnumerable<KeyValuePair<String, Object>> expressionState = null)
|
{
|
||||||
|
stepName = default(String);
|
||||||
|
var context = CreateContext(contextData);
|
||||||
|
|
||||||
|
if (token != null && token.Type != TokenType.Null)
|
||||||
|
{
|
||||||
|
// We should only evaluate basic expressions if we are sure we have context on all the Named Values and functions
|
||||||
|
// Otherwise return and use a default name
|
||||||
|
if (token is BasicExpressionToken expressionToken)
|
||||||
|
{
|
||||||
|
ExpressionNode root = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
root = new ExpressionParser().ValidateSyntax(expressionToken.Expression, null) as ExpressionNode;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
context.Errors.Add(exception);
|
||||||
|
context.Errors.Check();
|
||||||
|
}
|
||||||
|
foreach (var node in root.Traverse())
|
||||||
|
{
|
||||||
|
if (node is NamedValue namedValue && !contextData.ContainsKey(namedValue.Name))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (node is Function function &&
|
||||||
|
!context.ExpressionFunctions.Any(item => String.Equals(item.Name, function.Name)) &&
|
||||||
|
!ExpressionConstants.WellKnownFunctions.ContainsKey(function.Name))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StringStepsContext, token, 0, null, omitHeader: true);
|
||||||
|
context.Errors.Check();
|
||||||
|
stepName = PipelineTemplateConverter.ConvertToStepDisplayName(context, token);
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (!(ex is TemplateValidationException))
|
||||||
|
{
|
||||||
|
context.Errors.Add(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Errors.Check();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TemplateContext CreateContext(DictionaryContextData contextData)
|
||||||
{
|
{
|
||||||
var result = new TemplateContext
|
var result = new TemplateContext
|
||||||
{
|
{
|
||||||
@@ -423,7 +407,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add named values
|
// Add named context
|
||||||
if (contextData != null)
|
if (contextData != null)
|
||||||
{
|
{
|
||||||
foreach (var pair in contextData)
|
foreach (var pair in contextData)
|
||||||
@@ -432,46 +416,14 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add functions
|
// Compat for new agent against old server
|
||||||
var functionNames = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
foreach (var name in s_contextNames)
|
||||||
if (expressionFunctions?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var function in expressionFunctions)
|
|
||||||
{
|
|
||||||
result.ExpressionFunctions.Add(function);
|
|
||||||
functionNames.Add(function.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add missing expression values and expression functions.
|
|
||||||
// This solves the following problems:
|
|
||||||
// - Compat for new agent against old server (new contexts not sent down in job message)
|
|
||||||
// - Evaluating early when all referenced contexts are available, even though all allowed
|
|
||||||
// contexts may not yet be available. For example, evaluating step display name can often
|
|
||||||
// be performed early.
|
|
||||||
foreach (var name in s_expressionValueNames)
|
|
||||||
{
|
{
|
||||||
if (!result.ExpressionValues.ContainsKey(name))
|
if (!result.ExpressionValues.ContainsKey(name))
|
||||||
{
|
{
|
||||||
result.ExpressionValues[name] = null;
|
result.ExpressionValues[name] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var name in s_expressionFunctionNames)
|
|
||||||
{
|
|
||||||
if (!functionNames.Contains(name))
|
|
||||||
{
|
|
||||||
result.ExpressionFunctions.Add(new FunctionInfo<NoOperation>(name, 0, Int32.MaxValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add state
|
|
||||||
if (expressionState != null)
|
|
||||||
{
|
|
||||||
foreach (var pair in expressionState)
|
|
||||||
{
|
|
||||||
result.State[pair.Key] = pair.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -479,10 +431,9 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
private readonly ITraceWriter m_trace;
|
private readonly ITraceWriter m_trace;
|
||||||
private readonly TemplateSchema m_schema;
|
private readonly TemplateSchema m_schema;
|
||||||
private readonly IList<String> m_fileTable;
|
private readonly IList<String> m_fileTable;
|
||||||
private readonly String[] s_expressionValueNames = new[]
|
private readonly String[] s_contextNames = new[]
|
||||||
{
|
{
|
||||||
PipelineTemplateConstants.GitHub,
|
PipelineTemplateConstants.GitHub,
|
||||||
PipelineTemplateConstants.Needs,
|
|
||||||
PipelineTemplateConstants.Strategy,
|
PipelineTemplateConstants.Strategy,
|
||||||
PipelineTemplateConstants.Matrix,
|
PipelineTemplateConstants.Matrix,
|
||||||
PipelineTemplateConstants.Needs,
|
PipelineTemplateConstants.Needs,
|
||||||
@@ -493,13 +444,5 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
PipelineTemplateConstants.Runner,
|
PipelineTemplateConstants.Runner,
|
||||||
PipelineTemplateConstants.Env,
|
PipelineTemplateConstants.Env,
|
||||||
};
|
};
|
||||||
private readonly String[] s_expressionFunctionNames = new[]
|
|
||||||
{
|
|
||||||
PipelineTemplateConstants.Always,
|
|
||||||
PipelineTemplateConstants.Cancelled,
|
|
||||||
PipelineTemplateConstants.Failure,
|
|
||||||
PipelineTemplateConstants.HashFiles,
|
|
||||||
PipelineTemplateConstants.Success,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,35 +2,25 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Schema;
|
using GitHub.DistributedTask.ObjectTemplating.Schema;
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
||||||
{
|
{
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public static class PipelineTemplateSchemaFactory
|
public sealed class PipelineTemplateSchemaFactory
|
||||||
{
|
{
|
||||||
public static TemplateSchema GetSchema()
|
public TemplateSchema CreateSchema()
|
||||||
{
|
{
|
||||||
if (s_schema == null)
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
var json = default(String);
|
||||||
|
using (var stream = assembly.GetManifestResourceStream("GitHub.DistributedTask.Pipelines.ObjectTemplating.workflow-v1.0.json"))
|
||||||
|
using (var streamReader = new StreamReader(stream))
|
||||||
{
|
{
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
json = streamReader.ReadToEnd();
|
||||||
var json = default(String);
|
|
||||||
using (var stream = assembly.GetManifestResourceStream("GitHub.DistributedTask.Pipelines.ObjectTemplating.workflow-v1.0.json"))
|
|
||||||
using (var streamReader = new StreamReader(stream))
|
|
||||||
{
|
|
||||||
json = streamReader.ReadToEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
var objectReader = new JsonObjectReader(null, json);
|
|
||||||
var schema = TemplateSchema.Load(objectReader);
|
|
||||||
Interlocked.CompareExchange(ref s_schema, schema, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s_schema;
|
var objectReader = new JsonObjectReader(null, json);
|
||||||
|
return TemplateSchema.Load(objectReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TemplateSchema s_schema;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
"steps-scope-input-value": {
|
"steps-scope-input-value": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
|
"needs",
|
||||||
"matrix",
|
"matrix",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
@@ -66,9 +66,9 @@
|
|||||||
"steps-scope-output-value": {
|
"steps-scope-output-value": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
@@ -91,9 +91,9 @@
|
|||||||
"description": "Default input values for a steps template",
|
"description": "Default input values for a steps template",
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"one-of": [
|
"one-of": [
|
||||||
"string",
|
"string",
|
||||||
@@ -114,9 +114,9 @@
|
|||||||
"description": "Output values for a steps template",
|
"description": "Output values for a steps template",
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
@@ -204,25 +204,6 @@
|
|||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"job-if-result": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"needs",
|
|
||||||
"always(0,0)",
|
|
||||||
"failure(0,MAX)",
|
|
||||||
"cancelled(0,0)",
|
|
||||||
"success(0,MAX)"
|
|
||||||
],
|
|
||||||
"one-of": [
|
|
||||||
"null",
|
|
||||||
"boolean",
|
|
||||||
"number",
|
|
||||||
"string",
|
|
||||||
"sequence",
|
|
||||||
"mapping"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
@@ -291,9 +272,9 @@
|
|||||||
"runs-on": {
|
"runs-on": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"one-of": [
|
"one-of": [
|
||||||
"non-empty-string",
|
"non-empty-string",
|
||||||
@@ -316,10 +297,10 @@
|
|||||||
"job-env": {
|
"job-env": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
"secrets",
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
"secrets"
|
"needs"
|
||||||
],
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
@@ -463,9 +444,9 @@
|
|||||||
"step-if": {
|
"step-if": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
@@ -473,8 +454,7 @@
|
|||||||
"always(0,0)",
|
"always(0,0)",
|
||||||
"failure(0,0)",
|
"failure(0,0)",
|
||||||
"cancelled(0,0)",
|
"cancelled(0,0)",
|
||||||
"success(0,0)",
|
"success(0,0)"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
@@ -482,9 +462,9 @@
|
|||||||
"step-if-in-template": {
|
"step-if-in-template": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
"job",
|
"job",
|
||||||
@@ -493,63 +473,11 @@
|
|||||||
"always(0,0)",
|
"always(0,0)",
|
||||||
"failure(0,0)",
|
"failure(0,0)",
|
||||||
"cancelled(0,0)",
|
"cancelled(0,0)",
|
||||||
"success(0,0)",
|
"success(0,0)"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"step-if-result": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"steps",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env",
|
|
||||||
"always(0,0)",
|
|
||||||
"failure(0,0)",
|
|
||||||
"cancelled(0,0)",
|
|
||||||
"success(0,0)",
|
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
|
||||||
"one-of": [
|
|
||||||
"null",
|
|
||||||
"boolean",
|
|
||||||
"number",
|
|
||||||
"string",
|
|
||||||
"sequence",
|
|
||||||
"mapping"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"step-if-result-in-template": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"steps",
|
|
||||||
"inputs",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env",
|
|
||||||
"always(0,0)",
|
|
||||||
"failure(0,0)",
|
|
||||||
"cancelled(0,0)",
|
|
||||||
"success(0,0)",
|
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
|
||||||
"one-of": [
|
|
||||||
"null",
|
|
||||||
"boolean",
|
|
||||||
"number",
|
|
||||||
"string",
|
|
||||||
"sequence",
|
|
||||||
"mapping"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"steps-template-reference": {
|
"steps-template-reference": {
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -573,9 +501,9 @@
|
|||||||
"steps-template-reference-inputs": {
|
"steps-template-reference-inputs": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
@@ -591,9 +519,9 @@
|
|||||||
"steps-template-reference-inputs-in-template": {
|
"steps-template-reference-inputs-in-template": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
@@ -610,15 +538,14 @@
|
|||||||
"step-env": {
|
"step-env": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
@@ -629,16 +556,15 @@
|
|||||||
"step-env-in-template": {
|
"step-env-in-template": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
@@ -649,35 +575,14 @@
|
|||||||
"step-with": {
|
"step-with": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
|
||||||
"mapping": {
|
|
||||||
"loose-key-type": "non-empty-string",
|
|
||||||
"loose-value-type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"step-with-in-template": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"needs",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"secrets",
|
|
||||||
"steps",
|
|
||||||
"inputs",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env",
|
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
@@ -688,9 +593,9 @@
|
|||||||
"container": {
|
"container": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"one-of": [
|
"one-of": [
|
||||||
"string",
|
"string",
|
||||||
@@ -713,9 +618,9 @@
|
|||||||
"services": {
|
"services": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
@@ -726,9 +631,9 @@
|
|||||||
"services-container": {
|
"services-container": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"one-of": [
|
"one-of": [
|
||||||
"non-empty-string",
|
"non-empty-string",
|
||||||
@@ -743,6 +648,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"step-with-in-template": {
|
||||||
|
"context": [
|
||||||
|
"github",
|
||||||
|
"strategy",
|
||||||
|
"matrix",
|
||||||
|
"needs",
|
||||||
|
"secrets",
|
||||||
|
"steps",
|
||||||
|
"inputs",
|
||||||
|
"job",
|
||||||
|
"runner",
|
||||||
|
"env"
|
||||||
|
],
|
||||||
|
"mapping": {
|
||||||
|
"loose-key-type": "non-empty-string",
|
||||||
|
"loose-value-type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"non-empty-string": {
|
"non-empty-string": {
|
||||||
"string": {
|
"string": {
|
||||||
"require-non-empty": true
|
"require-non-empty": true
|
||||||
@@ -758,9 +682,9 @@
|
|||||||
"boolean-strategy-context": {
|
"boolean-strategy-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"boolean": {}
|
"boolean": {}
|
||||||
},
|
},
|
||||||
@@ -768,9 +692,9 @@
|
|||||||
"number-strategy-context": {
|
"number-strategy-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"number": {}
|
"number": {}
|
||||||
},
|
},
|
||||||
@@ -778,9 +702,9 @@
|
|||||||
"string-strategy-context": {
|
"string-strategy-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix"
|
"matrix",
|
||||||
|
"needs"
|
||||||
],
|
],
|
||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
@@ -788,15 +712,14 @@
|
|||||||
"boolean-steps-context": {
|
"boolean-steps-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"boolean": {}
|
"boolean": {}
|
||||||
},
|
},
|
||||||
@@ -804,16 +727,15 @@
|
|||||||
"boolean-steps-context-in-template": {
|
"boolean-steps-context-in-template": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"boolean": {}
|
"boolean": {}
|
||||||
},
|
},
|
||||||
@@ -821,15 +743,14 @@
|
|||||||
"number-steps-context": {
|
"number-steps-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"number": {}
|
"number": {}
|
||||||
},
|
},
|
||||||
@@ -837,16 +758,15 @@
|
|||||||
"number-steps-context-in-template": {
|
"number-steps-context-in-template": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"number": {}
|
"number": {}
|
||||||
},
|
},
|
||||||
@@ -854,9 +774,9 @@
|
|||||||
"string-runner-context": {
|
"string-runner-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
@@ -869,15 +789,14 @@
|
|||||||
"string-steps-context": {
|
"string-steps-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
@@ -885,16 +804,15 @@
|
|||||||
"string-steps-context-in-template": {
|
"string-steps-context-in-template": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
"needs",
|
|
||||||
"strategy",
|
"strategy",
|
||||||
"matrix",
|
"matrix",
|
||||||
|
"needs",
|
||||||
"secrets",
|
"secrets",
|
||||||
"steps",
|
"steps",
|
||||||
"inputs",
|
"inputs",
|
||||||
"job",
|
"job",
|
||||||
"runner",
|
"runner",
|
||||||
"env",
|
"env"
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
],
|
||||||
"string": {}
|
"string": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
@@ -111,57 +109,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public async void PrepareActions_SkipDownloadActionFromGraphWhenCached_OnPremises()
|
|
||||||
{
|
|
||||||
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 = "actions/no-such-action",
|
|
||||||
Ref = "master",
|
|
||||||
RepositoryType = "GitHub"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_configurationStore.Object.GetSettings().IsHostedServer = false;
|
|
||||||
var actionDirectory = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "actions/no-such-action", "master");
|
|
||||||
Directory.CreateDirectory(actionDirectory);
|
|
||||||
var watermarkFile = $"{actionDirectory}.completed";
|
|
||||||
File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString());
|
|
||||||
var actionFile = Path.Combine(actionDirectory, "action.yml");
|
|
||||||
File.WriteAllText(actionFile, @"
|
|
||||||
name: ""no-such-action""
|
|
||||||
runs:
|
|
||||||
using: node12
|
|
||||||
main: no-such-action.js
|
|
||||||
");
|
|
||||||
var testFile = Path.Combine(actionDirectory, "test-file");
|
|
||||||
File.WriteAllText(testFile, "asdf");
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.True(File.Exists(testFile));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Teardown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -1653,8 +1600,6 @@ runs:
|
|||||||
_ec = new Mock<IExecutionContext>();
|
_ec = new Mock<IExecutionContext>();
|
||||||
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
||||||
_ec.Setup(x => x.Variables).Returns(new Variables(_hc, new Dictionary<string, VariableValue>()));
|
_ec.Setup(x => x.Variables).Returns(new Variables(_hc, new Dictionary<string, VariableValue>()));
|
||||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
|
||||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
|
||||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
|
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
||||||
_ec.Setup(x => x.GetGitHubContext("workspace")).Returns(Path.Combine(_workFolder, "actions", "actions"));
|
_ec.Setup(x => x.GetGitHubContext("workspace")).Returns(Path.Combine(_workFolder, "actions", "actions"));
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Expressions;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -535,26 +533,26 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var actionManifest = new ActionManifestManager();
|
var actionManifest = new ActionManifestManager();
|
||||||
actionManifest.Initialize(_hc);
|
actionManifest.Initialize(_hc);
|
||||||
|
|
||||||
_ec.Object.ExpressionValues["github"] = new DictionaryContextData
|
var githubContext = new DictionaryContextData();
|
||||||
{
|
githubContext.Add("ref", new StringContextData("refs/heads/master"));
|
||||||
{ "ref", new StringContextData("refs/heads/master") },
|
|
||||||
};
|
var evaluateContext = new Dictionary<string, PipelineContextData>(StringComparer.OrdinalIgnoreCase);
|
||||||
_ec.Object.ExpressionValues["strategy"] = new DictionaryContextData();
|
evaluateContext["github"] = githubContext;
|
||||||
_ec.Object.ExpressionValues["matrix"] = new DictionaryContextData();
|
evaluateContext["strategy"] = new DictionaryContextData();
|
||||||
_ec.Object.ExpressionValues["steps"] = new DictionaryContextData();
|
evaluateContext["matrix"] = new DictionaryContextData();
|
||||||
_ec.Object.ExpressionValues["job"] = new DictionaryContextData();
|
evaluateContext["steps"] = new DictionaryContextData();
|
||||||
_ec.Object.ExpressionValues["runner"] = new DictionaryContextData();
|
evaluateContext["job"] = new DictionaryContextData();
|
||||||
_ec.Object.ExpressionValues["env"] = new DictionaryContextData();
|
evaluateContext["runner"] = new DictionaryContextData();
|
||||||
_ec.Object.ExpressionFunctions.Add(new FunctionInfo<HashFilesFunction>("hashFiles", 1, 255));
|
evaluateContext["env"] = new DictionaryContextData();
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = actionManifest.EvaluateDefaultInput(_ec.Object, "testInput", new StringToken(null, null, null, "defaultValue"));
|
var result = actionManifest.EvaluateDefaultInput(_ec.Object, "testInput", new StringToken(null, null, null, "defaultValue"), evaluateContext);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Equal("defaultValue", result);
|
Assert.Equal("defaultValue", result);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
result = actionManifest.EvaluateDefaultInput(_ec.Object, "testInput", new BasicExpressionToken(null, null, null, "github.ref"));
|
result = actionManifest.EvaluateDefaultInput(_ec.Object, "testInput", new BasicExpressionToken(null, null, null, "github.ref"), evaluateContext);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Equal("refs/heads/master", result);
|
Assert.Equal("refs/heads/master", result);
|
||||||
@@ -577,8 +575,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_ec.Setup(x => x.WriteDebug).Returns(true);
|
_ec.Setup(x => x.WriteDebug).Returns(true);
|
||||||
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
||||||
_ec.Setup(x => x.Variables).Returns(new Variables(_hc, new Dictionary<string, VariableValue>()));
|
_ec.Setup(x => x.Variables).Returns(new Variables(_hc, new Dictionary<string, VariableValue>()));
|
||||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
|
||||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
|
||||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"{tag}{message}"); });
|
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"{tag}{message}"); });
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
@@ -323,7 +322,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_ec = new Mock<IExecutionContext>();
|
_ec = new Mock<IExecutionContext>();
|
||||||
_ec.Setup(x => x.ExpressionValues).Returns(_context);
|
_ec.Setup(x => x.ExpressionValues).Returns(_context);
|
||||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
|
||||||
_ec.Setup(x => x.IntraActionState).Returns(new Dictionary<string, string>());
|
_ec.Setup(x => x.IntraActionState).Returns(new Dictionary<string, string>());
|
||||||
_ec.Setup(x => x.EnvironmentVariables).Returns(new Dictionary<string, string>());
|
_ec.Setup(x => x.EnvironmentVariables).Returns(new Dictionary<string, string>());
|
||||||
_ec.Setup(x => x.SetGitHubContext(It.IsAny<string>(), It.IsAny<string>()));
|
_ec.Setup(x => x.SetGitHubContext(It.IsAny<string>(), It.IsAny<string>()));
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Expressions;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using GitHub.DistributedTask.Expressions2;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
{
|
{
|
||||||
public sealed class ConditionFunctionsL0
|
public sealed class ExpressionManagerL0
|
||||||
{
|
{
|
||||||
private TemplateContext _templateContext;
|
private Mock<IExecutionContext> _ec;
|
||||||
|
private ExpressionManager _expressionManager;
|
||||||
|
private DictionaryContextData _expressions;
|
||||||
private JobContext _jobContext;
|
private JobContext _jobContext;
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -38,7 +38,7 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
_jobContext.Status = variableSet.JobStatus;
|
_jobContext.Status = variableSet.JobStatus;
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
bool actual = Evaluate("always()");
|
bool actual = _expressionManager.Evaluate(_ec.Object, "always()").Value;
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(variableSet.Expected, actual);
|
Assert.Equal(variableSet.Expected, actual);
|
||||||
@@ -68,7 +68,7 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
_jobContext.Status = variableSet.JobStatus;
|
_jobContext.Status = variableSet.JobStatus;
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
bool actual = Evaluate("cancelled()");
|
bool actual = _expressionManager.Evaluate(_ec.Object, "cancelled()").Value;
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(variableSet.Expected, actual);
|
Assert.Equal(variableSet.Expected, actual);
|
||||||
@@ -97,7 +97,7 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
_jobContext.Status = variableSet.JobStatus;
|
_jobContext.Status = variableSet.JobStatus;
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
bool actual = Evaluate("failure()");
|
bool actual = _expressionManager.Evaluate(_ec.Object, "failure()").Value;
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(variableSet.Expected, actual);
|
Assert.Equal(variableSet.Expected, actual);
|
||||||
@@ -126,7 +126,37 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
_jobContext.Status = variableSet.JobStatus;
|
_jobContext.Status = variableSet.JobStatus;
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
bool actual = Evaluate("success()");
|
bool actual = _expressionManager.Evaluate(_ec.Object, "success()").Value;
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.Equal(variableSet.Expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void ContextNamedValue()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange.
|
||||||
|
var variableSets = new[]
|
||||||
|
{
|
||||||
|
new { Condition = "github.ref == 'refs/heads/master'", VariableName = "ref", VariableValue = "refs/heads/master", Expected = true },
|
||||||
|
new { Condition = "github['ref'] == 'refs/heads/master'", VariableName = "ref", VariableValue = "refs/heads/master", Expected = true },
|
||||||
|
new { Condition = "github.nosuch || '' == ''", VariableName = "ref", VariableValue = "refs/heads/master", Expected = true },
|
||||||
|
new { Condition = "github['ref'] == 'refs/heads/release'", VariableName = "ref", VariableValue = "refs/heads/master", Expected = false },
|
||||||
|
new { Condition = "github.ref == 'refs/heads/release'", VariableName = "ref", VariableValue = "refs/heads/master", Expected = false },
|
||||||
|
};
|
||||||
|
foreach (var variableSet in variableSets)
|
||||||
|
{
|
||||||
|
InitializeExecutionContext(hc);
|
||||||
|
_ec.Object.ExpressionValues["github"] = new GitHubContext() { { variableSet.VariableName, new StringContextData(variableSet.VariableValue) } };
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
bool actual = _expressionManager.Evaluate(_ec.Object, variableSet.Condition).Value;
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(variableSet.Expected, actual);
|
Assert.Equal(variableSet.Expected, actual);
|
||||||
@@ -136,34 +166,21 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
|
|
||||||
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
||||||
{
|
{
|
||||||
return new TestHostContext(this, testName);
|
var hc = new TestHostContext(this, testName);
|
||||||
|
_expressionManager = new ExpressionManager();
|
||||||
|
_expressionManager.Initialize(hc);
|
||||||
|
return hc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeExecutionContext(TestHostContext hc)
|
private void InitializeExecutionContext(TestHostContext hc)
|
||||||
{
|
{
|
||||||
|
_expressions = new DictionaryContextData();
|
||||||
_jobContext = new JobContext();
|
_jobContext = new JobContext();
|
||||||
|
|
||||||
var executionContext = new Mock<IExecutionContext>();
|
_ec = new Mock<IExecutionContext>();
|
||||||
executionContext.SetupAllProperties();
|
_ec.SetupAllProperties();
|
||||||
executionContext.Setup(x => x.JobContext).Returns(_jobContext);
|
_ec.Setup(x => x.ExpressionValues).Returns(_expressions);
|
||||||
|
_ec.Setup(x => x.JobContext).Returns(_jobContext);
|
||||||
_templateContext = new TemplateContext();
|
|
||||||
_templateContext.State[nameof(IExecutionContext)] = executionContext.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Evaluate(string expression)
|
|
||||||
{
|
|
||||||
var parser = new ExpressionParser();
|
|
||||||
var functions = new IFunctionInfo[]
|
|
||||||
{
|
|
||||||
new FunctionInfo<AlwaysFunction>(PipelineTemplateConstants.Always, 0, 0),
|
|
||||||
new FunctionInfo<CancelledFunction>(PipelineTemplateConstants.Cancelled, 0, 0),
|
|
||||||
new FunctionInfo<FailureFunction>(PipelineTemplateConstants.Failure, 0, 0),
|
|
||||||
new FunctionInfo<SuccessFunction>(PipelineTemplateConstants.Success, 0, 0),
|
|
||||||
};
|
|
||||||
var tree = parser.CreateTree(expression, null, null, functions);
|
|
||||||
var result = tree.Evaluate(null, null, _templateContext, null);
|
|
||||||
return result.IsTruthy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
private Mock<IJobServerQueue> _jobServerQueue;
|
private Mock<IJobServerQueue> _jobServerQueue;
|
||||||
private Mock<IConfigurationStore> _config;
|
private Mock<IConfigurationStore> _config;
|
||||||
private Mock<IPagingLogger> _logger;
|
private Mock<IPagingLogger> _logger;
|
||||||
|
private Mock<IExpressionManager> _express;
|
||||||
private Mock<IContainerOperationProvider> _containerProvider;
|
private Mock<IContainerOperationProvider> _containerProvider;
|
||||||
private Mock<IDiagnosticLogManager> _diagnosticLogManager;
|
private Mock<IDiagnosticLogManager> _diagnosticLogManager;
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_jobServerQueue = new Mock<IJobServerQueue>();
|
_jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
_config = new Mock<IConfigurationStore>();
|
_config = new Mock<IConfigurationStore>();
|
||||||
_logger = new Mock<IPagingLogger>();
|
_logger = new Mock<IPagingLogger>();
|
||||||
|
_express = new Mock<IExpressionManager>();
|
||||||
_containerProvider = new Mock<IContainerOperationProvider>();
|
_containerProvider = new Mock<IContainerOperationProvider>();
|
||||||
_diagnosticLogManager = new Mock<IDiagnosticLogManager>();
|
_diagnosticLogManager = new Mock<IDiagnosticLogManager>();
|
||||||
_directoryManager = new Mock<IPipelineDirectoryManager>();
|
_directoryManager = new Mock<IPipelineDirectoryManager>();
|
||||||
@@ -106,6 +108,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
hc.SetSingleton(_actionManager.Object);
|
hc.SetSingleton(_actionManager.Object);
|
||||||
hc.SetSingleton(_config.Object);
|
hc.SetSingleton(_config.Object);
|
||||||
hc.SetSingleton(_jobServerQueue.Object);
|
hc.SetSingleton(_jobServerQueue.Object);
|
||||||
|
hc.SetSingleton(_express.Object);
|
||||||
hc.SetSingleton(_containerProvider.Object);
|
hc.SetSingleton(_containerProvider.Object);
|
||||||
hc.SetSingleton(_directoryManager.Object);
|
hc.SetSingleton(_directoryManager.Object);
|
||||||
hc.SetSingleton(_diagnosticLogManager.Object);
|
hc.SetSingleton(_diagnosticLogManager.Object);
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
_tokenSource = new CancellationTokenSource();
|
_tokenSource = new CancellationTokenSource();
|
||||||
|
var expressionManager = new ExpressionManager();
|
||||||
|
expressionManager.Initialize(hc);
|
||||||
|
hc.SetSingleton<IExpressionManager>(expressionManager);
|
||||||
|
|
||||||
_jobRunner = new JobRunner();
|
_jobRunner = new JobRunner();
|
||||||
_jobRunner.Initialize(hc);
|
_jobRunner.Initialize(hc);
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
using System;
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Worker;
|
||||||
|
using Moq;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Moq;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Worker;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
{
|
{
|
||||||
@@ -27,6 +27,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
||||||
{
|
{
|
||||||
var hc = new TestHostContext(this, testName);
|
var hc = new TestHostContext(this, testName);
|
||||||
|
var expressionManager = new ExpressionManager();
|
||||||
|
expressionManager.Initialize(hc);
|
||||||
|
hc.SetSingleton<IExpressionManager>(expressionManager);
|
||||||
Dictionary<string, VariableValue> variablesToCopy = new Dictionary<string, VariableValue>();
|
Dictionary<string, VariableValue> variablesToCopy = new Dictionary<string, VariableValue>();
|
||||||
_variables = new Variables(
|
_variables = new Variables(
|
||||||
hostContext: hc,
|
hostContext: hc,
|
||||||
@@ -46,7 +49,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_contexts["runner"] = new DictionaryContextData();
|
_contexts["runner"] = new DictionaryContextData();
|
||||||
_contexts["job"] = _jobContext;
|
_contexts["job"] = _jobContext;
|
||||||
_ec.Setup(x => x.ExpressionValues).Returns(_contexts);
|
_ec.Setup(x => x.ExpressionValues).Returns(_contexts);
|
||||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
|
||||||
_ec.Setup(x => x.JobContext).Returns(_jobContext);
|
_ec.Setup(x => x.JobContext).Returns(_jobContext);
|
||||||
|
|
||||||
_stepContext = new StepsContext();
|
_stepContext = new StepsContext();
|
||||||
@@ -381,11 +383,16 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
using (TestHostContext hc = CreateTestContext())
|
using (TestHostContext hc = CreateTestContext())
|
||||||
{
|
{
|
||||||
|
var expressionManager = new Mock<IExpressionManager>();
|
||||||
|
expressionManager.Object.Initialize(hc);
|
||||||
|
hc.SetSingleton<IExpressionManager>(expressionManager.Object);
|
||||||
|
expressionManager.Setup(x => x.Evaluate(It.IsAny<IExecutionContext>(), It.IsAny<string>(), It.IsAny<bool>())).Throws(new Exception());
|
||||||
|
|
||||||
// Arrange.
|
// Arrange.
|
||||||
var variableSets = new[]
|
var variableSets = new[]
|
||||||
{
|
{
|
||||||
new[] { CreateStep(hc, TaskResult.Succeeded, "fromJson('not json')") },
|
new[] { CreateStep(hc, TaskResult.Succeeded, "success()") },
|
||||||
new[] { CreateStep(hc, TaskResult.Succeeded, "fromJson('not json')") },
|
new[] { CreateStep(hc, TaskResult.Succeeded, "success()") },
|
||||||
};
|
};
|
||||||
foreach (var variableSet in variableSets)
|
foreach (var variableSet in variableSets)
|
||||||
{
|
{
|
||||||
@@ -603,7 +610,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
stepContext.Setup(x => x.Variables).Returns(_variables);
|
stepContext.Setup(x => x.Variables).Returns(_variables);
|
||||||
stepContext.Setup(x => x.EnvironmentVariables).Returns(_env);
|
stepContext.Setup(x => x.EnvironmentVariables).Returns(_env);
|
||||||
stepContext.Setup(x => x.ExpressionValues).Returns(_contexts);
|
stepContext.Setup(x => x.ExpressionValues).Returns(_contexts);
|
||||||
stepContext.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
|
||||||
stepContext.Setup(x => x.JobContext).Returns(_jobContext);
|
stepContext.Setup(x => x.JobContext).Returns(_jobContext);
|
||||||
stepContext.Setup(x => x.StepsContext).Returns(_stepContext);
|
stepContext.Setup(x => x.StepsContext).Returns(_stepContext);
|
||||||
stepContext.Setup(x => x.ContextName).Returns(step.Object.Action.ContextName);
|
stepContext.Setup(x => x.ContextName).Returns(step.Object.Action.ContextName);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.168.0
|
2.165.2
|
||||||
|
|||||||
Reference in New Issue
Block a user