Prepare to switch GITHUB_ACTION to use ContextName instead of refname (#593)

This PR changes GITHUB_ACTION to use the step ContextName, instead of refname. The behavior is behind a feature flag. Refname is an otherwise deprecated property.

Primary motivation: For composite actions, we need a distinct GITHUB_ACTION for each nested step. This PR adds code to generate a default context name for nested steps.

For nested steps, GITHUB_ACTION will be set to "{ScopeName}.{ContextName}" to ensure no collisions.

A corresponding change will be made on the server so context name is never empty. Generated context names will start with "__".

A follow-up PR is required to avoid tracking "step" context values (outputs/conclusion/result) for generated context names. Waiting on telemetry from the server to confirm it's safe to assume leading "__" is a generate context name.
This commit is contained in:
eric sciple
2020-07-19 17:19:13 -04:00
committed by GitHub
parent f9dca15c63
commit 1cc3c08cf2
20 changed files with 288 additions and 745 deletions

View File

@@ -55,7 +55,7 @@ namespace GitHub.Runner.Worker
public ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile) public ActionDefinitionData Load(IExecutionContext executionContext, string manifestFile)
{ {
var templateContext = CreateContext(executionContext); var templateContext = CreateTemplateContext(executionContext);
ActionDefinitionData actionDefinition = new ActionDefinitionData(); ActionDefinitionData actionDefinition = new ActionDefinitionData();
// Clean up file name real quick // Clean up file name real quick
@@ -118,7 +118,7 @@ namespace GitHub.Runner.Worker
break; break;
case "inputs": case "inputs":
ConvertInputs(templateContext, actionPair.Value, actionDefinition); ConvertInputs(actionPair.Value, actionDefinition);
break; break;
case "runs": case "runs":
@@ -177,19 +177,19 @@ namespace GitHub.Runner.Worker
if (token != null) if (token != null)
{ {
var context = CreateContext(executionContext, extraExpressionValues); var templateContext = CreateTemplateContext(executionContext, extraExpressionValues);
try try
{ {
token = TemplateEvaluator.Evaluate(context, "outputs", token, 0, null, omitHeader: true); token = TemplateEvaluator.Evaluate(templateContext, "outputs", token, 0, null, omitHeader: true);
context.Errors.Check(); templateContext.Errors.Check();
result = token.ToContextData().AssertDictionary("composite outputs"); result = token.ToContextData().AssertDictionary("composite outputs");
} }
catch (Exception ex) when (!(ex is TemplateValidationException)) catch (Exception ex) when (!(ex is TemplateValidationException))
{ {
context.Errors.Add(ex); templateContext.Errors.Add(ex);
} }
context.Errors.Check(); templateContext.Errors.Check();
} }
return result ?? new DictionaryContextData(); return result ?? new DictionaryContextData();
@@ -204,11 +204,11 @@ namespace GitHub.Runner.Worker
if (token != null) if (token != null)
{ {
var context = CreateContext(executionContext, extraExpressionValues); var templateContext = CreateTemplateContext(executionContext, extraExpressionValues);
try try
{ {
var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-args", token, 0, null, omitHeader: true); var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "container-runs-args", token, 0, null, omitHeader: true);
context.Errors.Check(); templateContext.Errors.Check();
Trace.Info($"Arguments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}"); Trace.Info($"Arguments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}");
@@ -225,10 +225,10 @@ namespace GitHub.Runner.Worker
catch (Exception ex) when (!(ex is TemplateValidationException)) catch (Exception ex) when (!(ex is TemplateValidationException))
{ {
Trace.Error(ex); Trace.Error(ex);
context.Errors.Add(ex); templateContext.Errors.Add(ex);
} }
context.Errors.Check(); templateContext.Errors.Check();
} }
return result; return result;
@@ -243,11 +243,11 @@ namespace GitHub.Runner.Worker
if (token != null) if (token != null)
{ {
var context = CreateContext(executionContext, extraExpressionValues); var templateContext = CreateTemplateContext(executionContext, extraExpressionValues);
try try
{ {
var evaluateResult = TemplateEvaluator.Evaluate(context, "container-runs-env", token, 0, null, omitHeader: true); var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "container-runs-env", token, 0, null, omitHeader: true);
context.Errors.Check(); templateContext.Errors.Check();
Trace.Info($"Environments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}"); Trace.Info($"Environments evaluate result: {StringUtil.ConvertToJson(evaluateResult)}");
@@ -269,10 +269,10 @@ namespace GitHub.Runner.Worker
catch (Exception ex) when (!(ex is TemplateValidationException)) catch (Exception ex) when (!(ex is TemplateValidationException))
{ {
Trace.Error(ex); Trace.Error(ex);
context.Errors.Add(ex); templateContext.Errors.Add(ex);
} }
context.Errors.Check(); templateContext.Errors.Check();
} }
return result; return result;
@@ -286,11 +286,11 @@ namespace GitHub.Runner.Worker
string result = ""; string result = "";
if (token != null) if (token != null)
{ {
var context = CreateContext(executionContext); var templateContext = CreateTemplateContext(executionContext);
try try
{ {
var evaluateResult = TemplateEvaluator.Evaluate(context, "input-default-context", token, 0, null, omitHeader: true); var evaluateResult = TemplateEvaluator.Evaluate(templateContext, "input-default-context", token, 0, null, omitHeader: true);
context.Errors.Check(); templateContext.Errors.Check();
Trace.Info($"Input '{inputName}': default value evaluate result: {StringUtil.ConvertToJson(evaluateResult)}"); Trace.Info($"Input '{inputName}': default value evaluate result: {StringUtil.ConvertToJson(evaluateResult)}");
@@ -300,16 +300,16 @@ namespace GitHub.Runner.Worker
catch (Exception ex) when (!(ex is TemplateValidationException)) catch (Exception ex) when (!(ex is TemplateValidationException))
{ {
Trace.Error(ex); Trace.Error(ex);
context.Errors.Add(ex); templateContext.Errors.Add(ex);
} }
context.Errors.Check(); templateContext.Errors.Check();
} }
return result; return result;
} }
private TemplateContext CreateContext( private TemplateContext CreateTemplateContext(
IExecutionContext executionContext, IExecutionContext executionContext,
IDictionary<string, PipelineContextData> extraExpressionValues = null) IDictionary<string, PipelineContextData> extraExpressionValues = null)
{ {
@@ -357,7 +357,7 @@ namespace GitHub.Runner.Worker
private ActionExecutionData ConvertRuns( private ActionExecutionData ConvertRuns(
IExecutionContext executionContext, IExecutionContext executionContext,
TemplateContext context, TemplateContext templateContext,
TemplateToken inputsToken, TemplateToken inputsToken,
MappingToken outputs = null) MappingToken outputs = null)
{ {
@@ -375,7 +375,7 @@ namespace GitHub.Runner.Worker
var postToken = default(StringToken); var postToken = default(StringToken);
var postEntrypointToken = default(StringToken); var postEntrypointToken = default(StringToken);
var postIfToken = default(StringToken); var postIfToken = default(StringToken);
var stepsLoaded = default(List<Pipelines.ActionStep>); var steps = default(List<Pipelines.Step>);
foreach (var run in runsMapping) foreach (var run in runsMapping)
{ {
@@ -424,9 +424,9 @@ namespace GitHub.Runner.Worker
case "steps": case "steps":
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA"))) if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
{ {
var steps = run.Value.AssertSequence("steps"); var stepsToken = run.Value.AssertSequence("steps");
var evaluator = executionContext.ToPipelineTemplateEvaluator(); steps = PipelineTemplateConverter.ConvertToSteps(templateContext, stepsToken);
stepsLoaded = evaluator.LoadCompositeSteps(steps); templateContext.Errors.Check();
break; break;
} }
throw new Exception("You aren't supposed to be using Composite Actions yet!"); throw new Exception("You aren't supposed to be using Composite Actions yet!");
@@ -479,7 +479,7 @@ namespace GitHub.Runner.Worker
} }
else if (string.Equals(usingToken.Value, "composite", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA"))) else if (string.Equals(usingToken.Value, "composite", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
{ {
if (stepsLoaded == null) if (steps == null)
{ {
// TODO: Add a more helpful error message + including file name, etc. to show user that it's because of their yaml file // TODO: Add a more helpful error message + including file name, etc. to show user that it's because of their yaml file
throw new ArgumentNullException($"No steps provided."); throw new ArgumentNullException($"No steps provided.");
@@ -488,7 +488,7 @@ namespace GitHub.Runner.Worker
{ {
return new CompositeActionExecutionData() return new CompositeActionExecutionData()
{ {
Steps = stepsLoaded, Steps = steps.Cast<Pipelines.ActionStep>().ToList(),
Outputs = outputs Outputs = outputs
}; };
} }
@@ -510,7 +510,6 @@ namespace GitHub.Runner.Worker
} }
private void ConvertInputs( private void ConvertInputs(
TemplateContext context,
TemplateToken inputsToken, TemplateToken inputsToken,
ActionDefinitionData actionDefinition) ActionDefinitionData actionDefinition)
{ {

View File

@@ -105,7 +105,7 @@ namespace GitHub.Runner.Worker
// others // others
void ForceTaskComplete(); void ForceTaskComplete();
void RegisterPostJobStep(IStep step); void RegisterPostJobStep(IStep step);
IStep CreateCompositeStep(IActionRunner step, DictionaryContextData inputsData, Dictionary<string, string> envData); IStep CreateCompositeStep(string scopeName, IActionRunner step, DictionaryContextData inputsData, Dictionary<string, string> envData);
} }
public sealed class ExecutionContext : RunnerService, IExecutionContext public sealed class ExecutionContext : RunnerService, IExecutionContext
@@ -120,9 +120,6 @@ namespace GitHub.Runner.Worker
private event OnMatcherChanged _onMatcherChanged; private event OnMatcherChanged _onMatcherChanged;
// Regex used for checking if ScopeName meets the condition that shows that its id is null.
private readonly static Regex _generatedContextNamePattern = new Regex("^__[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
private IssueMatcherConfig[] _matchers; private IssueMatcherConfig[] _matchers;
private IPagingLogger _logger; private IPagingLogger _logger;
@@ -273,23 +270,14 @@ namespace GitHub.Runner.Worker
/// add a child node, aka a step, to the current job to the Root.JobSteps based on the location. /// add a child node, aka a step, to the current job to the Root.JobSteps based on the location.
/// </summary> /// </summary>
public IStep CreateCompositeStep( public IStep CreateCompositeStep(
string scopeName,
IActionRunner step, IActionRunner step,
DictionaryContextData inputsData, DictionaryContextData inputsData,
Dictionary<string, string> envData) Dictionary<string, string> envData)
{ {
// If the context name is empty and the scope name is empty, we would generate a unique scope name for this child in the following format: step.ExecutionContext = Root.CreateChild(_record.Id, step.DisplayName, _record.Id.ToString("N"), scopeName, step.Action.ContextName, logger: _logger);
// "__<GUID>"
var safeContextName = !string.IsNullOrEmpty(ContextName) ? ContextName : $"__{Guid.NewGuid()}";
// Set Scope Name. Note, for our design, we consider each step in a composite action to have the same scope
// This makes it much simpler to handle their outputs at the end of the Composite Action
var childScopeName = !string.IsNullOrEmpty(ScopeName) ? $"{ScopeName}.{safeContextName}" : safeContextName;
var childContextName = !string.IsNullOrEmpty(step.Action.ContextName) ? step.Action.ContextName : $"__{Guid.NewGuid()}";
step.ExecutionContext = Root.CreateChild(_record.Id, step.DisplayName, _record.Id.ToString("N"), childScopeName, childContextName, logger: _logger);
step.ExecutionContext.ExpressionValues["inputs"] = inputsData; step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
step.ExecutionContext.ExpressionValues["steps"] = StepsContext.GetScope(step.ExecutionContext.GetFullyQualifiedContextName());
// Add the composite action environment variables to each step. // Add the composite action environment variables to each step.
#if OS_WINDOWS #if OS_WINDOWS
@@ -420,6 +408,7 @@ namespace GitHub.Runner.Worker
_logger.End(); _logger.End();
// todo: Skip if generated context name. After M271-ish the server will never send an empty context name. Generated context names will start with "__"
if (!string.IsNullOrEmpty(ContextName)) if (!string.IsNullOrEmpty(ContextName))
{ {
StepsContext.SetOutcome(ScopeName, ContextName, (Outcome ?? Result ?? TaskResult.Succeeded).ToActionResult()); StepsContext.SetOutcome(ScopeName, ContextName, (Outcome ?? Result ?? TaskResult.Succeeded).ToActionResult());
@@ -482,8 +471,8 @@ namespace GitHub.Runner.Worker
{ {
ArgUtil.NotNullOrEmpty(name, nameof(name)); ArgUtil.NotNullOrEmpty(name, nameof(name));
// if the ContextName follows the __GUID format which is set as the default value for ContextName if null for Composite Actions. // todo: Skip if generated context name. After M271-ish the server will never send an empty context name. Generated context names will start with "__"
if (String.IsNullOrEmpty(ContextName) || _generatedContextNamePattern.IsMatch(ContextName)) if (string.IsNullOrEmpty(ContextName))
{ {
reference = null; reference = null;
return; return;
@@ -923,6 +912,16 @@ namespace GitHub.Runner.Worker
// Otherwise individual overloads would need to be implemented (depending on the unit test). // Otherwise individual overloads would need to be implemented (depending on the unit test).
public static class ExecutionContextExtension public static class ExecutionContextExtension
{ {
public static string GetFullyQualifiedContextName(this IExecutionContext context)
{
if (!string.IsNullOrEmpty(context.ScopeName))
{
return $"{context.ScopeName}.{context.ContextName}";
}
return context.ContextName;
}
public static void Error(this IExecutionContext context, Exception ex) public static void Error(this IExecutionContext context, Exception ex)
{ {
context.Error(ex.Message); context.Error(ex.Message);

View File

@@ -47,46 +47,22 @@ namespace GitHub.Runner.Worker.Handlers
// Initialize Composite Steps List of Steps // Initialize Composite Steps List of Steps
var compositeSteps = new List<IStep>(); var compositeSteps = new List<IStep>();
foreach (Pipelines.ActionStep aStep in actionSteps) // Temporary hack until after M271-ish. After M271-ish the server will never send an empty
// context name. Generated context names start with "__"
var childScopeName = ExecutionContext.GetFullyQualifiedContextName();
if (string.IsNullOrEmpty(childScopeName))
{ {
// Ex: childScopeName = $"__{Guid.NewGuid()}";
// runs: }
// using: "composite"
// steps:
// - uses: example/test-composite@v2 (a)
// - run echo hello world (b)
// - run echo hello world 2 (c)
//
// ethanchewy/test-composite/action.yaml
// runs:
// using: "composite"
// steps:
// - run echo hello world 3 (d)
// - run echo hello world 4 (e)
//
// Steps processed as follow:
// | a |
// | a | => | d |
// (Run step d)
// | a |
// | a | => | e |
// (Run step e)
// | a |
// (Run step a)
// | b |
// (Run step b)
// | c |
// (Run step c)
// Done.
foreach (Pipelines.ActionStep actionStep in actionSteps)
{
var actionRunner = HostContext.CreateService<IActionRunner>(); var actionRunner = HostContext.CreateService<IActionRunner>();
actionRunner.Action = aStep; actionRunner.Action = actionStep;
actionRunner.Stage = stage; actionRunner.Stage = stage;
actionRunner.Condition = aStep.Condition; actionRunner.Condition = actionStep.Condition;
var step = ExecutionContext.CreateCompositeStep(actionRunner, inputsData, Environment);
InitializeScope(step);
var step = ExecutionContext.CreateCompositeStep(childScopeName, actionRunner, inputsData, Environment);
compositeSteps.Add(step); compositeSteps.Add(step);
} }
@@ -96,10 +72,8 @@ namespace GitHub.Runner.Worker.Handlers
await RunStepsAsync(compositeSteps); await RunStepsAsync(compositeSteps);
// Get the pointer of the correct "steps" object and pass it to the ExecutionContext so that we can process the outputs correctly // Get the pointer of the correct "steps" object and pass it to the ExecutionContext so that we can process the outputs correctly
// This will always be the same for every step so we can pull this from the first step if it exists
var stepExecutionContext = compositeSteps.Count > 0 ? compositeSteps[0].ExecutionContext : null;
ExecutionContext.ExpressionValues["inputs"] = inputsData; ExecutionContext.ExpressionValues["inputs"] = inputsData;
ExecutionContext.ExpressionValues["steps"] = stepExecutionContext.StepsContext.GetScope(stepExecutionContext.ScopeName); ExecutionContext.ExpressionValues["steps"] = ExecutionContext.StepsContext.GetScope(ExecutionContext.GetFullyQualifiedContextName());
ProcessCompositeActionOutputs(); ProcessCompositeActionOutputs();
} }
@@ -158,13 +132,6 @@ namespace GitHub.Runner.Worker.Handlers
} }
} }
private void InitializeScope(IStep step)
{
var stepsContext = step.ExecutionContext.StepsContext;
var scopeName = step.ExecutionContext.ScopeName;
step.ExecutionContext.ExpressionValues["steps"] = stepsContext.GetScope(scopeName);
}
private async Task RunStepsAsync(List<IStep> compositeSteps) private async Task RunStepsAsync(List<IStep> compositeSteps)
{ {
ArgUtil.NotNull(compositeSteps, nameof(compositeSteps)); ArgUtil.NotNull(compositeSteps, nameof(compositeSteps));
@@ -209,15 +176,7 @@ namespace GitHub.Runner.Worker.Handlers
var actionStep = step as IActionRunner; var actionStep = step as IActionRunner;
// Set GITHUB_ACTION // Set GITHUB_ACTION
// TODO: Fix this after SDK Changes. step.ExecutionContext.SetGitHubContext("action", step.ExecutionContext.GetFullyQualifiedContextName());
if (!String.IsNullOrEmpty(step.ExecutionContext.ScopeName))
{
step.ExecutionContext.SetGitHubContext("action", step.ExecutionContext.ScopeName);
}
else
{
step.ExecutionContext.SetGitHubContext("action", step.ExecutionContext.ContextName);
}
try try
{ {

View File

@@ -296,7 +296,7 @@ namespace GitHub.Runner.Worker
{ {
ArgUtil.NotNull(actionStep, step.DisplayName); ArgUtil.NotNull(actionStep, step.DisplayName);
intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState); intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState);
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, actionStep.Action.ScopeName, actionStep.Action.ContextName, intraActionState); actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, null, actionStep.Action.ContextName, intraActionState);
} }
} }

View File

@@ -103,7 +103,16 @@ namespace GitHub.Runner.Worker
if (step is IActionRunner actionStep) if (step is IActionRunner actionStep)
{ {
// Set GITHUB_ACTION // Set GITHUB_ACTION
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name); // Warning: Do not turn on FF DistributedTask.UseContextNameForGITHUBACTION until after M271-ish. After M271-ish
// the server will never send an empty context name. Generated context names start with "__"
if (step.ExecutionContext.Variables.GetBoolean("DistributedTask.UseContextNameForGITHUBACTION") ?? false)
{
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name);
}
else
{
step.ExecutionContext.SetGitHubContext("action", step.ExecutionContext.GetFullyQualifiedContextName());
}
try try
{ {

View File

@@ -24,7 +24,6 @@ namespace GitHub.DistributedTask.Pipelines
Environment = actionToClone.Environment?.Clone(); Environment = actionToClone.Environment?.Clone();
Inputs = actionToClone.Inputs?.Clone(); Inputs = actionToClone.Inputs?.Clone();
ContextName = actionToClone?.ContextName; ContextName = actionToClone?.ContextName;
ScopeName = actionToClone?.ScopeName;
DisplayNameToken = actionToClone.DisplayNameToken?.Clone(); DisplayNameToken = actionToClone.DisplayNameToken?.Clone();
} }
@@ -41,9 +40,6 @@ namespace GitHub.DistributedTask.Pipelines
[DataMember(EmitDefaultValue = false)] [DataMember(EmitDefaultValue = false)]
public TemplateToken DisplayNameToken { get; set; } public TemplateToken DisplayNameToken { get; set; }
[DataMember(EmitDefaultValue = false)]
public String ScopeName { get; set; }
[DataMember(EmitDefaultValue = false)] [DataMember(EmitDefaultValue = false)]
public String ContextName { get; set; } public String ContextName { get; set; }

View File

@@ -39,7 +39,6 @@ namespace GitHub.DistributedTask.Pipelines
DictionaryContextData contextData, DictionaryContextData contextData,
WorkspaceOptions workspaceOptions, WorkspaceOptions workspaceOptions,
IEnumerable<JobStep> steps, IEnumerable<JobStep> steps,
IEnumerable<ContextScope> scopes,
IList<String> fileTable, IList<String> fileTable,
TemplateToken jobOutputs, TemplateToken jobOutputs,
IList<TemplateToken> defaults) IList<TemplateToken> defaults)
@@ -60,11 +59,6 @@ namespace GitHub.DistributedTask.Pipelines
m_maskHints = new List<MaskHint>(maskHints); m_maskHints = new List<MaskHint>(maskHints);
m_steps = new List<JobStep>(steps); m_steps = new List<JobStep>(steps);
if (scopes != null)
{
m_scopes = new List<ContextScope>(scopes);
}
if (environmentVariables?.Count > 0) if (environmentVariables?.Count > 0)
{ {
m_environmentVariables = new List<TemplateToken>(environmentVariables); m_environmentVariables = new List<TemplateToken>(environmentVariables);
@@ -261,18 +255,6 @@ namespace GitHub.DistributedTask.Pipelines
} }
} }
public IList<ContextScope> Scopes
{
get
{
if (m_scopes == null)
{
m_scopes = new List<ContextScope>();
}
return m_scopes;
}
}
/// <summary> /// <summary>
/// Gets the table of files used when parsing the pipeline (e.g. yaml files) /// Gets the table of files used when parsing the pipeline (e.g. yaml files)
/// </summary> /// </summary>
@@ -415,11 +397,6 @@ namespace GitHub.DistributedTask.Pipelines
m_maskHints = new List<MaskHint>(this.m_maskHints.Distinct()); m_maskHints = new List<MaskHint>(this.m_maskHints.Distinct());
} }
if (m_scopes?.Count == 0)
{
m_scopes = null;
}
if (m_variables?.Count == 0) if (m_variables?.Count == 0)
{ {
m_variables = null; m_variables = null;
@@ -447,9 +424,6 @@ namespace GitHub.DistributedTask.Pipelines
[DataMember(Name = "Steps", EmitDefaultValue = false)] [DataMember(Name = "Steps", EmitDefaultValue = false)]
private List<JobStep> m_steps; private List<JobStep> m_steps;
[DataMember(Name = "Scopes", EmitDefaultValue = false)]
private List<ContextScope> m_scopes;
[DataMember(Name = "Variables", EmitDefaultValue = false)] [DataMember(Name = "Variables", EmitDefaultValue = false)]
private IDictionary<String, VariableValue> m_variables; private IDictionary<String, VariableValue> m_variables;

View File

@@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
using Newtonsoft.Json;
namespace GitHub.DistributedTask.Pipelines
{
[DataContract]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class ContextScope
{
[DataMember(EmitDefaultValue = false)]
public String Name { get; set; }
[IgnoreDataMember]
public String ContextName
{
get
{
var index = Name.LastIndexOf('.');
if (index >= 0)
{
return Name.Substring(index + 1);
}
return Name;
}
}
[IgnoreDataMember]
public String ParentName
{
get
{
var index = Name.LastIndexOf('.');
if (index >= 0)
{
return Name.Substring(0, index);
}
return String.Empty;
}
}
[DataMember(EmitDefaultValue = false)]
public TemplateToken Inputs { get; set; }
[DataMember(EmitDefaultValue = false)]
public TemplateToken Outputs { get; set; }
}
}

View File

@@ -11,8 +11,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String BooleanStrategyContext = "boolean-strategy-context"; public const String BooleanStrategyContext = "boolean-strategy-context";
public const String CancelTimeoutMinutes = "cancel-timeout-minutes"; public const String CancelTimeoutMinutes = "cancel-timeout-minutes";
public const String Cancelled = "cancelled"; public const String Cancelled = "cancelled";
public const String Checkout = "checkout"; public const String Clean= "clean";
public const String Clean = "clean";
public const String Container = "container"; public const String Container = "container";
public const String ContinueOnError = "continue-on-error"; public const String ContinueOnError = "continue-on-error";
public const String Defaults = "defaults"; public const String Defaults = "defaults";
@@ -23,7 +22,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String FailFast = "fail-fast"; public const String FailFast = "fail-fast";
public const String Failure = "failure"; public const String Failure = "failure";
public const String FetchDepth = "fetch-depth"; public const String FetchDepth = "fetch-depth";
public const String GeneratedId = "generated-id";
public const String GitHub = "github"; public const String GitHub = "github";
public const String HashFiles = "hashFiles"; public const String HashFiles = "hashFiles";
public const String Id = "id"; public const String Id = "id";
@@ -36,7 +34,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String JobIfResult = "job-if-result"; 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 Lfs = "lfs"; public const String Lfs = "lfs";
public const String Matrix = "matrix"; public const String Matrix = "matrix";
public const String MaxParallel = "max-parallel"; public const String MaxParallel = "max-parallel";
@@ -52,24 +49,18 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String Pool = "pool"; public const String Pool = "pool";
public const String Ports = "ports"; public const String Ports = "ports";
public const String Result = "result"; public const String Result = "result";
public const String RunDisplayPrefix = "Run ";
public const String Run = "run"; public const String Run = "run";
public const String RunDisplayPrefix = "Run ";
public const String Runner = "runner"; public const String Runner = "runner";
public const String RunsOn = "runs-on"; public const String RunsOn = "runs-on";
public const String Scope = "scope";
public const String Scopes = "scopes";
public const String Secrets = "secrets"; public const String Secrets = "secrets";
public const String Services = "services"; public const String Services = "services";
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 StepIfResult = "step-if-result";
public const String Steps = "steps";
public const String StepsInTemplate = "steps-in-template";
public const String StepsScopeInputs = "steps-scope-inputs";
public const String StepsScopeOutputs = "steps-scope-outputs";
public const String StepsTemplateRoot = "steps-template-root";
public const String StepWith = "step-with"; public const String StepWith = "step-with";
public const String Steps = "steps";
public const String Strategy = "strategy"; public const String Strategy = "strategy";
public const String StringStepsContext = "string-steps-context"; public const String StringStepsContext = "string-steps-context";
public const String StringStrategyContext = "string-strategy-context"; public const String StringStrategyContext = "string-strategy-context";
@@ -77,7 +68,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String Success = "success"; public const String Success = "success";
public const String Template = "template"; public const String Template = "template";
public const String TimeoutMinutes = "timeout-minutes"; public const String TimeoutMinutes = "timeout-minutes";
public const String Token = "token";
public const String Uses = "uses"; public const String Uses = "uses";
public const String VmImage = "vmImage"; public const String VmImage = "vmImage";
public const String Volumes = "volumes"; public const String Volumes = "volumes";

View File

@@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.ComponentModel;
using System.Linq; using System.Linq;
using GitHub.DistributedTask.Expressions2; using GitHub.DistributedTask.Expressions2;
using GitHub.DistributedTask.Expressions2.Sdk; using GitHub.DistributedTask.Expressions2.Sdk;
@@ -14,8 +14,62 @@ using Newtonsoft.Json.Linq;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{ {
internal static class PipelineTemplateConverter [EditorBrowsable(EditorBrowsableState.Never)]
public static class PipelineTemplateConverter
{ {
public static List<Step> ConvertToSteps(
TemplateContext context,
TemplateToken steps)
{
var stepsSequence = steps.AssertSequence($"job {PipelineTemplateConstants.Steps}");
var result = new List<Step>();
var nameBuilder = new ReferenceNameBuilder();
foreach (var stepsItem in stepsSequence)
{
var step = ConvertToStep(context, stepsItem, nameBuilder);
if (step != null) // step = null means we are hitting error during step conversion, there should be an error in context.errors
{
if (step.Enabled)
{
result.Add(step);
}
}
}
// Generate context name if empty
foreach (ActionStep step in result)
{
if (!String.IsNullOrEmpty(step.ContextName))
{
continue;
}
var name = default(string);
switch (step.Reference.Type)
{
case ActionSourceType.ContainerRegistry:
var containerReference = step.Reference as ContainerRegistryReference;
name = containerReference.Image;
break;
case ActionSourceType.Repository:
var repositoryReference = step.Reference as RepositoryPathReference;
name = !String.IsNullOrEmpty(repositoryReference.Name) ? repositoryReference.Name : PipelineConstants.SelfAlias;
break;
}
if (String.IsNullOrEmpty(name))
{
name = "run";
}
nameBuilder.AppendSegment($"__{name}");
step.ContextName = nameBuilder.Build();
}
return result;
}
internal static Boolean ConvertToIfResult( internal static Boolean ConvertToIfResult(
TemplateContext context, TemplateContext context,
TemplateToken ifResult) TemplateToken ifResult)
@@ -29,6 +83,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
var evaluationResult = EvaluationResult.CreateIntermediateResult(null, ifResult); var evaluationResult = EvaluationResult.CreateIntermediateResult(null, ifResult);
return evaluationResult.IsTruthy; return evaluationResult.IsTruthy;
} }
internal static Boolean? ConvertToStepContinueOnError( internal static Boolean? ConvertToStepContinueOnError(
TemplateContext context, TemplateContext context,
TemplateToken token, TemplateToken token,
@@ -264,32 +319,10 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
return result; return result;
} }
//Note: originally was List<Step> but we need to change to List<ActionStep> to use the "Inputs" attribute
internal static List<ActionStep> ConvertToSteps(
TemplateContext context,
TemplateToken steps)
{
var stepsSequence = steps.AssertSequence($"job {PipelineTemplateConstants.Steps}");
var result = new List<ActionStep>();
foreach (var stepsItem in stepsSequence)
{
var step = ConvertToStep(context, stepsItem);
if (step != null) // step = null means we are hitting error during step conversion, there should be an error in context.errors
{
if (step.Enabled)
{
result.Add(step);
}
}
}
return result;
}
private static ActionStep ConvertToStep( private static ActionStep ConvertToStep(
TemplateContext context, TemplateContext context,
TemplateToken stepsItem) TemplateToken stepsItem,
ReferenceNameBuilder nameBuilder)
{ {
var step = stepsItem.AssertMapping($"{PipelineTemplateConstants.Steps} item"); var step = stepsItem.AssertMapping($"{PipelineTemplateConstants.Steps} item");
var continueOnError = default(ScalarToken); var continueOnError = default(ScalarToken);
@@ -299,7 +332,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
var ifToken = default(ScalarToken); var ifToken = default(ScalarToken);
var name = default(ScalarToken); var name = default(ScalarToken);
var run = default(ScalarToken); var run = default(ScalarToken);
var scope = default(StringToken);
var timeoutMinutes = default(ScalarToken); var timeoutMinutes = default(ScalarToken);
var uses = default(StringToken); var uses = default(StringToken);
var with = default(TemplateToken); var with = default(TemplateToken);
@@ -337,9 +369,12 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
case PipelineTemplateConstants.Id: case PipelineTemplateConstants.Id:
id = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Id}"); id = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Id}");
if (!NameValidation.IsValid(id.Value, true)) if (!String.IsNullOrEmpty(id.Value))
{ {
context.Error(id, $"Step id {id.Value} is invalid. Ids must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'"); if (!nameBuilder.TryAddKnownName(id.Value, out var error))
{
context.Error(id, error);
}
} }
break; break;
@@ -367,10 +402,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
shell = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Shell}"); shell = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Shell}");
break; break;
case PipelineTemplateConstants.Scope:
scope = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Scope}");
break;
case PipelineTemplateConstants.Submodules: case PipelineTemplateConstants.Submodules:
submodules = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Submodules}"); submodules = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Submodules}");
break; break;
@@ -400,14 +431,12 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
} }
// Fixup the if-condition // Fixup the if-condition
var isDefaultScope = String.IsNullOrEmpty(scope?.Value); ifCondition = ConvertToIfCondition(context, ifToken, false);
ifCondition = ConvertToIfCondition(context, ifToken, false, isDefaultScope);
if (run != null) if (run != null)
{ {
var result = new ActionStep var result = new ActionStep
{ {
ScopeName = scope?.Value,
ContextName = id?.Value, ContextName = id?.Value,
ContinueOnError = continueOnError, ContinueOnError = continueOnError,
DisplayNameToken = name, DisplayNameToken = name,
@@ -439,7 +468,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
uses.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Uses}"); uses.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Uses}");
var result = new ActionStep var result = new ActionStep
{ {
ScopeName = scope?.Value,
ContextName = id?.Value, ContextName = id?.Value,
ContinueOnError = continueOnError, ContinueOnError = continueOnError,
DisplayNameToken = name, DisplayNameToken = name,
@@ -503,8 +531,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
private static String ConvertToIfCondition( private static String ConvertToIfCondition(
TemplateContext context, TemplateContext context,
TemplateToken token, TemplateToken token,
Boolean isJob, Boolean isJob)
Boolean isDefaultScope)
{ {
String condition; String condition;
if (token is null) if (token is null)
@@ -537,7 +564,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
} }
else else
{ {
namedValues = isDefaultScope ? s_stepNamedValues : s_stepInTemplateNamedValues; namedValues = s_stepNamedValues;
functions = s_stepConditionFunctions; functions = s_stepConditionFunctions;
} }
@@ -589,18 +616,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env), new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Needs), new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Needs),
}; };
private static readonly INamedValueInfo[] s_stepInTemplateNamedValues = new INamedValueInfo[]
{
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Strategy),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Matrix),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Steps),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Inputs),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Job),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Runner),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Needs),
};
private static readonly IFunctionInfo[] s_stepConditionFunctions = new IFunctionInfo[] private static readonly IFunctionInfo[] s_stepConditionFunctions = new IFunctionInfo[]
{ {
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Always, 0, 0), new FunctionInfo<NoOperation>(PipelineTemplateConstants.Always, 0, 0),

View File

@@ -51,60 +51,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public Int32 MaxResultSize { get; set; } = 10 * 1024 * 1024; // 10 mb public Int32 MaxResultSize { get; set; } = 10 * 1024 * 1024; // 10 mb
public DictionaryContextData EvaluateStepScopeInputs(
TemplateToken token,
DictionaryContextData contextData,
IList<IFunctionInfo> expressionFunctions)
{
var result = default(DictionaryContextData);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(contextData, expressionFunctions);
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsScopeInputs, token, 0, null, omitHeader: true);
context.Errors.Check();
result = token.ToContextData().AssertDictionary("steps scope inputs");
}
catch (Exception ex) when (!(ex is TemplateValidationException))
{
context.Errors.Add(ex);
}
context.Errors.Check();
}
return result ?? new DictionaryContextData();
}
public DictionaryContextData EvaluateStepScopeOutputs(
TemplateToken token,
DictionaryContextData contextData,
IList<IFunctionInfo> expressionFunctions)
{
var result = default(DictionaryContextData);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(contextData, expressionFunctions);
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsScopeOutputs, token, 0, null, omitHeader: true);
context.Errors.Check();
result = token.ToContextData().AssertDictionary("steps scope outputs");
}
catch (Exception ex) when (!(ex is TemplateValidationException))
{
context.Errors.Add(ex);
}
context.Errors.Check();
}
return result ?? new DictionaryContextData();
}
public Boolean EvaluateStepContinueOnError( public Boolean EvaluateStepContinueOnError(
TemplateToken token, TemplateToken token,
DictionaryContextData contextData, DictionaryContextData contextData,
@@ -159,31 +105,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
return result; return result;
} }
public List<ActionStep> LoadCompositeSteps(
TemplateToken token)
{
var result = default(List<ActionStep>);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(null, null, setMissingContext: false);
// TODO: we might want to to have a bool to prevent it from filling in with missing context w/ dummy variables
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepsInTemplate, token, 0, null, omitHeader: true);
context.Errors.Check();
result = PipelineTemplateConverter.ConvertToSteps(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,
@@ -425,8 +346,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
private TemplateContext CreateContext( private TemplateContext CreateContext(
DictionaryContextData contextData, DictionaryContextData contextData,
IList<IFunctionInfo> expressionFunctions, IList<IFunctionInfo> expressionFunctions,
IEnumerable<KeyValuePair<String, Object>> expressionState = null, IEnumerable<KeyValuePair<String, Object>> expressionState = null)
bool setMissingContext = true)
{ {
var result = new TemplateContext var result = new TemplateContext
{ {
@@ -475,21 +395,18 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
// - Evaluating early when all referenced contexts are available, even though all allowed // - 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 // contexts may not yet be available. For example, evaluating step display name can often
// be performed early. // be performed early.
if (setMissingContext) foreach (var name in s_expressionValueNames)
{ {
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) }
foreach (var name in s_expressionFunctionNames)
{
if (!functionNames.Contains(name))
{ {
if (!functionNames.Contains(name)) result.ExpressionFunctions.Add(new FunctionInfo<NoOperation>(name, 0, Int32.MaxValue));
{
result.ExpressionFunctions.Add(new FunctionInfo<NoOperation>(name, 0, Int32.MaxValue));
}
} }
} }

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using GitHub.DistributedTask.Pipelines.Validation;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
internal sealed class ReferenceNameBuilder
{
internal void AppendSegment(String value)
{
if (String.IsNullOrEmpty(value))
{
return;
}
if (m_name.Length == 0)
{
var first = value[0];
if ((first >= 'a' && first <= 'z') ||
(first >= 'A' && first <= 'Z') ||
first == '_')
{
// Legal first char
}
else if ((first >= '0' && first <= '9') || first == '-')
{
// Illegal first char, but legal char.
// Prepend "_".
m_name.Append("_");
}
else
{
// Illegal char
}
}
else
{
// Separator
m_name.Append(c_separator);
}
foreach (var c in value)
{
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '_' ||
c == '-')
{
// Legal
m_name.Append(c);
}
else
{
// Illegal
m_name.Append("_");
}
}
}
internal String Build()
{
var original = m_name.Length > 0 ? m_name.ToString() : "job";
var attempt = 1;
var suffix = default(String);
while (true)
{
if (attempt == 1)
{
suffix = String.Empty;
}
else if (attempt < 1000)
{
suffix = String.Format(CultureInfo.InvariantCulture, "_{0}", attempt);
}
else
{
throw new InvalidOperationException("Unable to create a unique name");
}
var candidate = original.Substring(0, Math.Min(original.Length, PipelineConstants.MaxNodeNameLength - suffix.Length)) + suffix;
if (m_distinctNames.Add(candidate))
{
m_name.Clear();
return candidate;
}
attempt++;
}
}
internal Boolean TryAddKnownName(
String value,
out String error)
{
if (!NameValidation.IsValid(value, allowHyphens: true) && value.Length < PipelineConstants.MaxNodeNameLength)
{
error = $"The identifier '{value}' is invalid. IDs may only contain alphanumeric characters, '_', and '-'. IDs must start with a letter or '_' and and must be less than {PipelineConstants.MaxNodeNameLength} characters.";
return false;
}
else if (!m_distinctNames.Add(value))
{
error = $"The identifier '{value}' may not be used more than once within the same scope.";
return false;
}
else
{
error = null;
return true;
}
}
private const String c_separator = "_";
private readonly HashSet<String> m_distinctNames = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
private readonly StringBuilder m_name = new StringBuilder();
}
}

View File

@@ -16,116 +16,6 @@
} }
}, },
"steps-template-root": {
"description": "Steps template file",
"mapping": {
"properties": {
"inputs": "steps-template-inputs",
"outputs": "steps-template-outputs",
"steps": "steps-in-template"
}
}
},
"steps-scope-inputs": {
"description": "Used when evaluating steps scope inputs",
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "steps-scope-input-value"
}
},
"steps-scope-input-value": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env"
],
"one-of": [
"string",
"sequence",
"mapping"
]
},
"steps-scope-outputs": {
"description": "Used when evaluating steps scope outputs",
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "steps-scope-output-value"
}
},
"steps-scope-output-value": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env"
],
"string": {}
},
"steps-template-inputs": {
"description": "Allowed inputs in a steps template",
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "steps-template-input-value"
}
},
"steps-template-input-value": {
"description": "Default input values for a steps template",
"context": [
"github",
"needs",
"strategy",
"matrix"
],
"one-of": [
"string",
"sequence",
"mapping"
]
},
"steps-template-outputs": {
"description": "Output mapping for a steps template",
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "steps-template-output-value"
}
},
"steps-template-output-value": {
"description": "Output values for a steps template",
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"job",
"runner",
"env"
],
"string": {}
},
"workflow-defaults": { "workflow-defaults": {
"mapping": { "mapping": {
"properties": { "properties": {
@@ -240,54 +130,27 @@
"matrix": { "matrix": {
"mapping": { "mapping": {
"properties": { "properties": {
"include": "matrix-include", "include": "matrix-filter",
"exclude": "matrix-exclude" "exclude": "matrix-filter"
}, },
"loose-key-type": "non-empty-string", "loose-key-type": "non-empty-string",
"loose-value-type": "sequence" "loose-value-type": "sequence"
} }
}, },
"matrix-include": { "matrix-filter": {
"sequence": { "sequence": {
"item-type": "matrix-include-item" "item-type": "matrix-filter-item"
} }
}, },
"matrix-include-item": { "matrix-filter-item": {
"mapping": { "mapping": {
"loose-key-type": "non-empty-string", "loose-key-type": "non-empty-string",
"loose-value-type": "any" "loose-value-type": "any"
} }
}, },
"matrix-exclude": {
"sequence": {
"item-type": "matrix-exclude-item"
}
},
"matrix-exclude-item": {
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "matrix-exclude-filter-item"
}
},
"matrix-exclude-filter-item": {
"one-of": [
"string",
"matrix-exclude-mapping-filter"
]
},
"matrix-exclude-mapping-filter": {
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "matrix-exclude-filter-item"
}
},
"runs-on": { "runs-on": {
"context": [ "context": [
"github", "github",
@@ -364,25 +227,10 @@
} }
}, },
"steps-in-template": {
"sequence": {
"item-type": "steps-item-in-template"
}
},
"steps-item": { "steps-item": {
"one-of": [ "one-of": [
"run-step", "run-step",
"regular-step", "regular-step"
"steps-template-reference"
]
},
"steps-item-in-template": {
"one-of": [
"run-step-in-template",
"regular-step-in-template",
"steps-template-reference-in-template"
] ]
}, },
@@ -405,25 +253,6 @@
} }
}, },
"run-step-in-template": {
"mapping": {
"properties": {
"name": "string-steps-context-in-template",
"id": "non-empty-string",
"if": "step-if-in-template",
"timeout-minutes": "number-steps-context-in-template",
"run": {
"type": "string-steps-context-in-template",
"required": true
},
"continue-on-error": "boolean-steps-context-in-template",
"env": "step-env-in-template",
"working-directory": "string-steps-context-in-template",
"shell": "non-empty-string"
}
}
},
"regular-step": { "regular-step": {
"mapping": { "mapping": {
"properties": { "properties": {
@@ -442,24 +271,6 @@
} }
}, },
"regular-step-in-template": {
"mapping": {
"properties": {
"name": "string-steps-context-in-template",
"id": "non-empty-string",
"if": "step-if-in-template",
"continue-on-error": "boolean-steps-context-in-template",
"timeout-minutes": "number-steps-context-in-template",
"uses": {
"type": "non-empty-string",
"required": true
},
"with": "step-with-in-template",
"env": "step-env-in-template"
}
}
},
"step-if": { "step-if": {
"context": [ "context": [
"github", "github",
@@ -479,26 +290,6 @@
"string": {} "string": {}
}, },
"step-if-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"steps",
"inputs",
"job",
"runner",
"env",
"always(0,0)",
"failure(0,0)",
"cancelled(0,0)",
"success(0,0)",
"hashFiles(1,255)"
],
"string": {}
},
"step-if-result": { "step-if-result": {
"context": [ "context": [
"github", "github",
@@ -524,89 +315,6 @@
] ]
}, },
"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": {
"mapping": {
"properties": {
"template": "non-empty-string",
"id": "non-empty-string",
"inputs": "steps-template-reference-inputs"
}
}
},
"steps-template-reference-in-template": {
"mapping": {
"properties": {
"template": "non-empty-string",
"id": "non-empty-string",
"inputs": "steps-template-reference-inputs-in-template"
}
}
},
"steps-template-reference-inputs": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"job",
"runner",
"env"
],
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "string"
}
},
"steps-template-reference-inputs-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env"
],
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "string"
}
},
"step-env": { "step-env": {
"context": [ "context": [
"github", "github",
@@ -626,26 +334,6 @@
} }
}, },
"step-env-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env",
"hashFiles(1,255)"
],
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "string"
}
},
"step-with": { "step-with": {
"context": [ "context": [
"github", "github",
@@ -665,26 +353,6 @@
} }
}, },
"step-with-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env",
"hashFiles(1,255)"
],
"mapping": {
"loose-key-type": "non-empty-string",
"loose-value-type": "string"
}
},
"container": { "container": {
"context": [ "context": [
"github", "github",
@@ -801,23 +469,6 @@
"boolean": {} "boolean": {}
}, },
"boolean-steps-context-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env",
"hashFiles(1,255)"
],
"boolean": {}
},
"number-steps-context": { "number-steps-context": {
"context": [ "context": [
"github", "github",
@@ -834,23 +485,6 @@
"number": {} "number": {}
}, },
"number-steps-context-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env",
"hashFiles(1,255)"
],
"number": {}
},
"string-runner-context": { "string-runner-context": {
"context": [ "context": [
"github", "github",
@@ -880,23 +514,6 @@
"hashFiles(1,255)" "hashFiles(1,255)"
], ],
"string": {} "string": {}
},
"string-steps-context-in-template": {
"context": [
"github",
"needs",
"strategy",
"matrix",
"secrets",
"steps",
"inputs",
"job",
"runner",
"env",
"hashFiles(1,255)"
],
"string": {}
} }
} }
} }

View File

@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Listener
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
TimelineReference timeline = null; TimelineReference timeline = null;
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData(); result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
return result; return result;
} }

View File

@@ -43,7 +43,7 @@ namespace GitHub.Runner.Common.Tests.Listener
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
TimelineReference timeline = null; TimelineReference timeline = null;
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
} }
private JobCancelMessage CreateJobCancelMessage() private JobCancelMessage CreateJobCancelMessage()

View File

@@ -150,7 +150,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,

View File

@@ -26,7 +26,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -102,7 +102,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -153,7 +153,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -251,7 +251,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,
@@ -335,7 +335,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TimelineReference timeline = new TimelineReference(); TimelineReference timeline = new TimelineReference();
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
string jobName = "some job name"; string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource() jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{ {
Alias = Pipelines.PipelineConstants.SelfAlias, Alias = Pipelines.PipelineConstants.SelfAlias,

View File

@@ -98,7 +98,7 @@ namespace GitHub.Runner.Common.Tests.Worker
}; };
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null, null); _message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null);
GitHubContext github = new GitHubContext(); GitHubContext github = new GitHubContext();
github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner"); github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner");
_message.ContextData.Add("github", github); _message.ContextData.Add("github", github);

View File

@@ -60,7 +60,7 @@ namespace GitHub.Runner.Common.Tests.Worker
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
TimelineReference timeline = new Timeline(Guid.NewGuid()); TimelineReference timeline = new Timeline(Guid.NewGuid());
Guid jobId = Guid.NewGuid(); Guid jobId = Guid.NewGuid();
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null); _message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
_message.Variables[Constants.Variables.System.Culture] = "en-US"; _message.Variables[Constants.Variables.System.Culture] = "en-US";
_message.Resources.Endpoints.Add(new ServiceEndpoint() _message.Resources.Endpoints.Add(new ServiceEndpoint()
{ {

View File

@@ -67,7 +67,7 @@ namespace GitHub.Runner.Common.Tests.Worker
new Pipelines.ContextData.DictionaryContextData() new Pipelines.ContextData.DictionaryContextData()
}, },
}; };
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null, null); var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null);
return jobRequest; return jobRequest;
} }