mirror of
https://github.com/actions/runner.git
synced 2025-12-11 12:57:05 +00:00
delete un-used code. (#218)
This commit is contained in:
@@ -16,180 +16,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
||||
{
|
||||
internal static class PipelineTemplateConverter
|
||||
{
|
||||
internal static PipelineTemplate ConvertToPipeline(
|
||||
TemplateContext context,
|
||||
RepositoryResource self,
|
||||
TemplateToken pipeline)
|
||||
{
|
||||
var result = new PipelineTemplate();
|
||||
result.Resources.Repositories.Add(self);
|
||||
var defaultStage = new Stage
|
||||
{
|
||||
Name = PipelineConstants.DefaultJobName,
|
||||
};
|
||||
result.Stages.Add(defaultStage);
|
||||
|
||||
try
|
||||
{
|
||||
if (pipeline == null || context.Errors.Count > 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var pipelineMapping = pipeline.AssertMapping("root");
|
||||
|
||||
foreach (var pipelinePair in pipelineMapping)
|
||||
{
|
||||
var pipelineKey = pipelinePair.Key.AssertString("root key");
|
||||
|
||||
switch (pipelineKey.Value)
|
||||
{
|
||||
case PipelineTemplateConstants.On:
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Name:
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Env:
|
||||
result.EnvironmentVariables = pipelinePair.Value;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Jobs:
|
||||
defaultStage.Phases.AddRange(ConvertToJobFactories(context, result.Resources, pipelinePair.Value));
|
||||
break;
|
||||
|
||||
default:
|
||||
pipelineKey.AssertUnexpectedValue("root key"); // throws
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Errors.Add(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (context.Errors.Count > 0)
|
||||
{
|
||||
foreach (var error in context.Errors)
|
||||
{
|
||||
result.Errors.Add(new PipelineValidationError(error.Code, error.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static String ConvertToJobDisplayName(
|
||||
TemplateContext context,
|
||||
TemplateToken displayName,
|
||||
Boolean allowExpressions = false)
|
||||
{
|
||||
var result = default(String);
|
||||
|
||||
// Expression
|
||||
if (allowExpressions && displayName is ExpressionToken)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// String
|
||||
var displayNameString = displayName.AssertString($"job {PipelineTemplateConstants.Name}");
|
||||
result = displayNameString.Value;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static PhaseTarget ConvertToJobTarget(
|
||||
TemplateContext context,
|
||||
TemplateToken runsOn,
|
||||
Boolean allowExpressions = false)
|
||||
{
|
||||
var result = new AgentPoolTarget();
|
||||
|
||||
// Expression
|
||||
if (allowExpressions && runsOn is ExpressionToken)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// String
|
||||
if (runsOn is StringToken runsOnString)
|
||||
{
|
||||
result.Pool = new AgentPoolReference { Name = "GitHub Actions" };
|
||||
result.AgentSpecification = new JObject
|
||||
{
|
||||
{ PipelineTemplateConstants.VmImage, runsOnString.Value }
|
||||
};
|
||||
}
|
||||
// Mapping
|
||||
else
|
||||
{
|
||||
var runsOnMapping = runsOn.AssertMapping($"job {PipelineTemplateConstants.RunsOn}");
|
||||
foreach (var runsOnProperty in runsOnMapping)
|
||||
{
|
||||
// Expression
|
||||
if (allowExpressions && runsOnProperty.Key is ExpressionToken)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// String
|
||||
var propertyName = runsOnProperty.Key.AssertString($"job {PipelineTemplateConstants.RunsOn} key");
|
||||
|
||||
switch (propertyName.Value)
|
||||
{
|
||||
case PipelineTemplateConstants.Pool:
|
||||
// Expression
|
||||
if (allowExpressions && runsOnProperty.Value is ExpressionToken)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Literal
|
||||
var pool = runsOnProperty.Value.AssertString($"job {PipelineTemplateConstants.RunsOn} key");
|
||||
result.Pool = new AgentPoolReference { Name = pool.Value };
|
||||
break;
|
||||
|
||||
default:
|
||||
propertyName.AssertUnexpectedValue($"job {PipelineTemplateConstants.RunsOn} key"); // throws
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static Int32? ConvertToJobTimeout(
|
||||
TemplateContext context,
|
||||
TemplateToken token,
|
||||
Boolean allowExpressions = false)
|
||||
{
|
||||
if (allowExpressions && token is ExpressionToken)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var numberToken = token.AssertNumber($"job {PipelineTemplateConstants.TimeoutMinutes}");
|
||||
return (Int32)numberToken.Value;
|
||||
}
|
||||
|
||||
internal static Int32? ConvertToJobCancelTimeout(
|
||||
TemplateContext context,
|
||||
TemplateToken token,
|
||||
Boolean allowExpressions = false)
|
||||
{
|
||||
if (allowExpressions && token is ExpressionToken)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var numberToken = token.AssertNumber($"job {PipelineTemplateConstants.CancelTimeoutMinutes}");
|
||||
return (Int32)numberToken.Value;
|
||||
}
|
||||
|
||||
internal static Boolean? ConvertToStepContinueOnError(
|
||||
TemplateContext context,
|
||||
TemplateToken token,
|
||||
@@ -315,203 +141,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
||||
return (Int32)numberToken.Value;
|
||||
}
|
||||
|
||||
internal static StrategyResult ConvertToStrategy(
|
||||
TemplateContext context,
|
||||
TemplateToken token,
|
||||
String jobFactoryDisplayName,
|
||||
Boolean allowExpressions = false)
|
||||
{
|
||||
var result = new StrategyResult();
|
||||
|
||||
// Expression
|
||||
if (allowExpressions && token is ExpressionToken)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var strategyMapping = token.AssertMapping(PipelineTemplateConstants.Strategy);
|
||||
var matrixBuilder = default(MatrixBuilder);
|
||||
var hasExpressions = false;
|
||||
|
||||
foreach (var strategyPair in strategyMapping)
|
||||
{
|
||||
// Expression key
|
||||
if (allowExpressions && strategyPair.Key is ExpressionToken)
|
||||
{
|
||||
hasExpressions = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Literal key
|
||||
var strategyKey = strategyPair.Key.AssertString("strategy key");
|
||||
|
||||
switch (strategyKey.Value)
|
||||
{
|
||||
// Fail-Fast
|
||||
case PipelineTemplateConstants.FailFast:
|
||||
if (allowExpressions && strategyPair.Value is ExpressionToken)
|
||||
{
|
||||
hasExpressions = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var failFastBooleanToken = strategyPair.Value.AssertBoolean($"strategy {PipelineTemplateConstants.FailFast}");
|
||||
result.FailFast = failFastBooleanToken.Value;
|
||||
break;
|
||||
|
||||
// Max-Parallel
|
||||
case PipelineTemplateConstants.MaxParallel:
|
||||
if (allowExpressions && strategyPair.Value is ExpressionToken)
|
||||
{
|
||||
hasExpressions = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxParallelNumberToken = strategyPair.Value.AssertNumber($"strategy {PipelineTemplateConstants.MaxParallel}");
|
||||
result.MaxParallel = (Int32)maxParallelNumberToken.Value;
|
||||
break;
|
||||
|
||||
// Matrix
|
||||
case PipelineTemplateConstants.Matrix:
|
||||
|
||||
// Expression
|
||||
if (allowExpressions && strategyPair.Value is ExpressionToken)
|
||||
{
|
||||
hasExpressions = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var matrix = strategyPair.Value.AssertMapping("matrix");
|
||||
hasExpressions = hasExpressions || matrix.Traverse().Any(x => x is ExpressionToken);
|
||||
matrixBuilder = new MatrixBuilder(context, jobFactoryDisplayName);
|
||||
var hasVector = false;
|
||||
|
||||
foreach (var matrixPair in matrix)
|
||||
{
|
||||
// Expression key
|
||||
if (allowExpressions && matrixPair.Key is ExpressionToken)
|
||||
{
|
||||
hasVector = true; // For validation, treat as if a vector is defined
|
||||
continue;
|
||||
}
|
||||
|
||||
var matrixKey = matrixPair.Key.AssertString("matrix key");
|
||||
switch (matrixKey.Value)
|
||||
{
|
||||
case PipelineTemplateConstants.Include:
|
||||
if (allowExpressions && matrixPair.Value is ExpressionToken)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var includeSequence = matrixPair.Value.AssertSequence("matrix includes");
|
||||
matrixBuilder.Include(includeSequence);
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Exclude:
|
||||
if (allowExpressions && matrixPair.Value is ExpressionToken)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var excludeSequence = matrixPair.Value.AssertSequence("matrix excludes");
|
||||
matrixBuilder.Exclude(excludeSequence);
|
||||
break;
|
||||
|
||||
default:
|
||||
hasVector = true;
|
||||
|
||||
if (allowExpressions && matrixPair.Value is ExpressionToken)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var vectorName = matrixKey.Value;
|
||||
var vectorSequence = matrixPair.Value.AssertSequence("matrix vector value");
|
||||
if (vectorSequence.Count == 0)
|
||||
{
|
||||
context.Error(vectorSequence, $"Matrix vector '{vectorName}' does not contain any values");
|
||||
}
|
||||
else
|
||||
{
|
||||
matrixBuilder.AddVector(vectorName, vectorSequence);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasVector)
|
||||
{
|
||||
context.Error(matrix, $"Matrix must defined at least one vector");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
strategyKey.AssertUnexpectedValue("strategy key"); // throws
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasExpressions)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (matrixBuilder != null)
|
||||
{
|
||||
result.Configurations.AddRange(matrixBuilder.Build());
|
||||
}
|
||||
|
||||
for (var i = 0; i < result.Configurations.Count; i++)
|
||||
{
|
||||
var configuration = result.Configurations[i];
|
||||
|
||||
var strategy = new DictionaryContextData()
|
||||
{
|
||||
{
|
||||
"fail-fast",
|
||||
new BooleanContextData(result.FailFast)
|
||||
},
|
||||
{
|
||||
"job-index",
|
||||
new NumberContextData(i)
|
||||
},
|
||||
{
|
||||
"job-total",
|
||||
new NumberContextData(result.Configurations.Count)
|
||||
}
|
||||
};
|
||||
|
||||
if (result.MaxParallel > 0)
|
||||
{
|
||||
strategy.Add(
|
||||
"max-parallel",
|
||||
new NumberContextData(result.MaxParallel)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
strategy.Add(
|
||||
"max-parallel",
|
||||
new NumberContextData(result.Configurations.Count)
|
||||
);
|
||||
}
|
||||
|
||||
configuration.ContextData.Add(PipelineTemplateConstants.Strategy, strategy);
|
||||
context.Memory.AddBytes(PipelineTemplateConstants.Strategy);
|
||||
context.Memory.AddBytes(strategy, traverse: true);
|
||||
|
||||
if (!configuration.ContextData.ContainsKey(PipelineTemplateConstants.Matrix))
|
||||
{
|
||||
configuration.ContextData.Add(PipelineTemplateConstants.Matrix, null);
|
||||
context.Memory.AddBytes(PipelineTemplateConstants.Matrix);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static JobContainer ConvertToJobContainer(
|
||||
TemplateContext context,
|
||||
TemplateToken value,
|
||||
@@ -616,532 +245,5 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<PhaseNode> ConvertToJobFactories(
|
||||
TemplateContext context,
|
||||
PipelineResources resources,
|
||||
TemplateToken workflow)
|
||||
{
|
||||
var jobsMapping = workflow.AssertMapping(PipelineTemplateConstants.Jobs);
|
||||
|
||||
foreach (var jobsPair in jobsMapping)
|
||||
{
|
||||
var jobNameToken = jobsPair.Key.AssertString($"{PipelineTemplateConstants.Jobs} key");
|
||||
if (!NameValidation.IsValid(jobNameToken.Value, true))
|
||||
{
|
||||
context.Error(jobNameToken, $"Job name {jobNameToken.Value} is invalid. Names must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'");
|
||||
}
|
||||
var result = new JobFactory
|
||||
{
|
||||
Name = jobNameToken.Value
|
||||
};
|
||||
|
||||
var jobFactoryDefinition = jobsPair.Value.AssertMapping($"{PipelineTemplateConstants.Jobs} value");
|
||||
|
||||
foreach (var jobFactoryProperty in jobFactoryDefinition)
|
||||
{
|
||||
var propertyName = jobFactoryProperty.Key.AssertString($"job property name");
|
||||
|
||||
switch (propertyName.Value)
|
||||
{
|
||||
case PipelineTemplateConstants.ContinueOnError:
|
||||
var continueOnErrorBooleanToken = jobFactoryProperty.Value.AssertBoolean($"job {PipelineTemplateConstants.ContinueOnError}");
|
||||
result.ContinueOnError = continueOnErrorBooleanToken.Value;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.If:
|
||||
var ifCondition = jobFactoryProperty.Value.AssertString($"job {PipelineTemplateConstants.If}");
|
||||
result.Condition = ConvertToIfCondition(context, ifCondition, true, true);
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Name:
|
||||
var displayName = jobFactoryProperty.Value.AssertScalar($"job {PipelineTemplateConstants.Name}");
|
||||
ConvertToJobDisplayName(context, displayName, allowExpressions: true); // Validate early if possible
|
||||
if (displayName is StringToken)
|
||||
{
|
||||
result.DisplayName = displayName.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
result.JobDisplayName = displayName.Clone(true) as ExpressionToken;
|
||||
}
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Needs:
|
||||
if (jobFactoryProperty.Value is StringToken needsLiteral)
|
||||
{
|
||||
result.DependsOn.Add(needsLiteral.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var needs = jobFactoryProperty.Value.AssertSequence($"job {PipelineTemplateConstants.Needs}");
|
||||
foreach (var needsItem in needs)
|
||||
{
|
||||
var need = needsItem.AssertString($"job {PipelineTemplateConstants.Needs} item");
|
||||
result.DependsOn.Add(need.Value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.RunsOn:
|
||||
ConvertToJobTarget(context, jobFactoryProperty.Value, allowExpressions: true); // Validate early if possible
|
||||
result.JobTarget = jobFactoryProperty.Value.Clone(true);
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Scopes:
|
||||
foreach (var scope in ConvertToScopes(context, jobFactoryProperty.Value))
|
||||
{
|
||||
result.Scopes.Add(scope);
|
||||
}
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Steps:
|
||||
result.Steps.AddRange(ConvertToSteps(context, jobFactoryProperty.Value));
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Strategy:
|
||||
ConvertToStrategy(context, jobFactoryProperty.Value, null, allowExpressions: true); // Validate early if possible
|
||||
result.Strategy = jobFactoryProperty.Value.Clone(true);
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.TimeoutMinutes:
|
||||
ConvertToJobTimeout(context, jobFactoryProperty.Value, allowExpressions: true); // Validate early if possible
|
||||
result.JobTimeout = jobFactoryProperty.Value.Clone(true) as ScalarToken;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.CancelTimeoutMinutes:
|
||||
ConvertToJobCancelTimeout(context, jobFactoryProperty.Value, allowExpressions: true); // Validate early if possible
|
||||
result.JobCancelTimeout = jobFactoryProperty.Value.Clone(true) as ScalarToken;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Container:
|
||||
ConvertToJobContainer(context, jobFactoryProperty.Value, allowExpressions: true);
|
||||
result.JobContainer = jobFactoryProperty.Value.Clone(true);
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Services:
|
||||
ConvertToJobServiceContainers(context, jobFactoryProperty.Value, allowExpressions: true);
|
||||
result.JobServiceContainers = jobFactoryProperty.Value.Clone(true);
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Env:
|
||||
result.EnvironmentVariables = jobFactoryProperty.Value.Clone(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
propertyName.AssertUnexpectedValue("job key"); // throws
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// todo: Move "required" support into schema validation
|
||||
if (result.JobTarget == null)
|
||||
{
|
||||
context.Error(jobFactoryDefinition, $"The '{PipelineTemplateConstants.RunsOn}' property is required");
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(result.DisplayName))
|
||||
{
|
||||
result.DisplayName = result.Name;
|
||||
}
|
||||
|
||||
if (result.Scopes.Count > 0)
|
||||
{
|
||||
result.Steps.Insert(
|
||||
0,
|
||||
new ActionStep
|
||||
{
|
||||
Reference = new ScriptReference(),
|
||||
DisplayName = "WARNING: TEMPLATES ARE HIGHLY EXPERIMENTAL",
|
||||
Inputs = new MappingToken(null, null, null)
|
||||
{
|
||||
{
|
||||
new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.Script),
|
||||
new StringToken(null, null, null, "echo WARNING: TEMPLATES ARE HIGHLY EXPERIMENTAL")
|
||||
}
|
||||
}
|
||||
});
|
||||
result.Steps.Add(
|
||||
new ActionStep
|
||||
{
|
||||
Reference = new ScriptReference(),
|
||||
DisplayName = "WARNING: TEMPLATES ARE HIGHLY EXPERIMENTAL",
|
||||
Inputs = new MappingToken(null, null, null)
|
||||
{
|
||||
{
|
||||
new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.Script),
|
||||
new StringToken(null, null, null, "echo WARNING: TEMPLATES ARE HIGHLY EXPERIMENTAL")
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ContextScope> ConvertToScopes(
|
||||
TemplateContext context,
|
||||
TemplateToken scopes)
|
||||
{
|
||||
var scopesSequence = scopes.AssertSequence($"job {PipelineTemplateConstants.Scopes}");
|
||||
|
||||
foreach (var scopesItem in scopesSequence)
|
||||
{
|
||||
var result = new ContextScope();
|
||||
var scope = scopesItem.AssertMapping($"{PipelineTemplateConstants.Scopes} item");
|
||||
|
||||
foreach (var scopeProperty in scope)
|
||||
{
|
||||
var propertyName = scopeProperty.Key.AssertString($"{PipelineTemplateConstants.Scopes} item key");
|
||||
|
||||
switch (propertyName.Value)
|
||||
{
|
||||
case PipelineTemplateConstants.Name:
|
||||
var nameLiteral = scopeProperty.Value.AssertString($"{PipelineTemplateConstants.Scopes} item {PipelineTemplateConstants.Name}");
|
||||
result.Name = nameLiteral.Value;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Inputs:
|
||||
result.Inputs = scopeProperty.Value.AssertMapping($"{PipelineTemplateConstants.Scopes} item {PipelineTemplateConstants.Inputs}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Outputs:
|
||||
result.Outputs = scopeProperty.Value.AssertMapping($"{PipelineTemplateConstants.Scopes} item {PipelineTemplateConstants.Outputs}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Step> ConvertToSteps(
|
||||
TemplateContext context,
|
||||
TemplateToken steps)
|
||||
{
|
||||
var stepsSequence = steps.AssertSequence($"job {PipelineTemplateConstants.Steps}");
|
||||
|
||||
var result = new List<Step>();
|
||||
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(
|
||||
TemplateContext context,
|
||||
TemplateToken stepsItem)
|
||||
{
|
||||
var step = stepsItem.AssertMapping($"{PipelineTemplateConstants.Steps} item");
|
||||
var continueOnError = default(ScalarToken);
|
||||
var env = default(TemplateToken);
|
||||
var id = default(StringToken);
|
||||
var ifCondition = default(String);
|
||||
var ifToken = default(StringToken);
|
||||
var name = default(ScalarToken);
|
||||
var run = default(ScalarToken);
|
||||
var scope = default(StringToken);
|
||||
var timeoutMinutes = default(ScalarToken);
|
||||
var uses = default(StringToken);
|
||||
var with = default(TemplateToken);
|
||||
var workingDir = default(ScalarToken);
|
||||
var path = default(ScalarToken);
|
||||
var clean = default(ScalarToken);
|
||||
var fetchDepth = default(ScalarToken);
|
||||
var lfs = default(ScalarToken);
|
||||
var submodules = default(ScalarToken);
|
||||
var shell = default(ScalarToken);
|
||||
|
||||
foreach (var stepProperty in step)
|
||||
{
|
||||
var propertyName = stepProperty.Key.AssertString($"{PipelineTemplateConstants.Steps} item key");
|
||||
|
||||
switch (propertyName.Value)
|
||||
{
|
||||
case PipelineTemplateConstants.Clean:
|
||||
clean = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Clean}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.ContinueOnError:
|
||||
ConvertToStepContinueOnError(context, stepProperty.Value, allowExpressions: true); // Validate early if possible
|
||||
continueOnError = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} {PipelineTemplateConstants.ContinueOnError}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Env:
|
||||
ConvertToStepEnvironment(context, stepProperty.Value, StringComparer.Ordinal, allowExpressions: true); // Validate early if possible
|
||||
env = stepProperty.Value;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.FetchDepth:
|
||||
fetchDepth = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.FetchDepth}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Id:
|
||||
id = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Id}");
|
||||
if (!NameValidation.IsValid(id.Value, true))
|
||||
{
|
||||
context.Error(id, $"Step id {id.Value} is invalid. Ids must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'");
|
||||
}
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.If:
|
||||
ifToken = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.If}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Lfs:
|
||||
lfs = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Lfs}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Name:
|
||||
name = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Name}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Path:
|
||||
path = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Path}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Run:
|
||||
run = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Run}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Shell:
|
||||
shell = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Shell}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Scope:
|
||||
scope = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Scope}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Submodules:
|
||||
submodules = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Submodules}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.TimeoutMinutes:
|
||||
ConvertToStepTimeout(context, stepProperty.Value, allowExpressions: true); // Validate early if possible
|
||||
timeoutMinutes = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.TimeoutMinutes}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.Uses:
|
||||
uses = stepProperty.Value.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Uses}");
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.With:
|
||||
ConvertToStepInputs(context, stepProperty.Value, allowExpressions: true); // Validate early if possible
|
||||
with = stepProperty.Value;
|
||||
break;
|
||||
|
||||
case PipelineTemplateConstants.WorkingDirectory:
|
||||
workingDir = stepProperty.Value.AssertScalar($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.WorkingDirectory}");
|
||||
break;
|
||||
|
||||
default:
|
||||
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Steps} item key"); // throws
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup the if-condition
|
||||
var isDefaultScope = String.IsNullOrEmpty(scope?.Value);
|
||||
ifCondition = ConvertToIfCondition(context, ifToken, false, isDefaultScope);
|
||||
|
||||
if (run != null)
|
||||
{
|
||||
var result = new ActionStep
|
||||
{
|
||||
ScopeName = scope?.Value,
|
||||
ContextName = id?.Value,
|
||||
ContinueOnError = continueOnError?.Clone(true) as ScalarToken,
|
||||
DisplayNameToken = name?.Clone(true) as ScalarToken,
|
||||
Condition = ifCondition,
|
||||
TimeoutInMinutes = timeoutMinutes?.Clone(true) as ScalarToken,
|
||||
Environment = env?.Clone(true),
|
||||
Reference = new ScriptReference(),
|
||||
};
|
||||
|
||||
var inputs = new MappingToken(null, null, null);
|
||||
inputs.Add(new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.Script), run.Clone(true));
|
||||
|
||||
if (workingDir != null)
|
||||
{
|
||||
inputs.Add(new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.WorkingDirectory), workingDir.Clone(true));
|
||||
}
|
||||
|
||||
if (shell != null)
|
||||
{
|
||||
inputs.Add(new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.Shell), shell.Clone(true));
|
||||
}
|
||||
|
||||
result.Inputs = inputs;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (uses != null)
|
||||
{
|
||||
var result = new ActionStep
|
||||
{
|
||||
ScopeName = scope?.Value,
|
||||
ContextName = id?.Value,
|
||||
ContinueOnError = continueOnError?.Clone(true) as ScalarToken,
|
||||
DisplayNameToken = name?.Clone(true) as ScalarToken,
|
||||
Condition = ifCondition,
|
||||
TimeoutInMinutes = timeoutMinutes?.Clone(true) as ScalarToken,
|
||||
Inputs = with,
|
||||
Environment = env,
|
||||
};
|
||||
|
||||
if (uses.Value.StartsWith("docker://", StringComparison.Ordinal))
|
||||
{
|
||||
var image = uses.Value.Substring("docker://".Length);
|
||||
result.Reference = new ContainerRegistryReference { Image = image };
|
||||
}
|
||||
else if (uses.Value.StartsWith("./") || uses.Value.StartsWith(".\\"))
|
||||
{
|
||||
result.Reference = new RepositoryPathReference
|
||||
{
|
||||
RepositoryType = PipelineConstants.SelfAlias,
|
||||
Path = uses.Value
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var usesSegments = uses.Value.Split('@');
|
||||
var pathSegments = usesSegments[0].Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var gitRef = usesSegments.Length == 2 ? usesSegments[1] : String.Empty;
|
||||
|
||||
if (usesSegments.Length != 2 ||
|
||||
pathSegments.Length < 2 ||
|
||||
String.IsNullOrEmpty(pathSegments[0]) ||
|
||||
String.IsNullOrEmpty(pathSegments[1]) ||
|
||||
String.IsNullOrEmpty(gitRef))
|
||||
{
|
||||
// todo: loc
|
||||
context.Error(uses, $"Expected format {{org}}/{{repo}}[/path]@ref. Actual '{uses.Value}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
var repositoryName = $"{pathSegments[0]}/{pathSegments[1]}";
|
||||
var directoryPath = pathSegments.Length > 2 ? String.Join("/", pathSegments.Skip(2)) : String.Empty;
|
||||
|
||||
result.Reference = new RepositoryPathReference
|
||||
{
|
||||
RepositoryType = RepositoryTypes.GitHub,
|
||||
Name = repositoryName,
|
||||
Ref = gitRef,
|
||||
Path = directoryPath,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// todo: build a "required" concept into the parser
|
||||
context.Error(step, $"Either '{PipelineTemplateConstants.Uses}' or '{PipelineTemplateConstants.Run}' is required");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String ConvertToIfCondition(
|
||||
TemplateContext context,
|
||||
StringToken ifCondition,
|
||||
Boolean isJob,
|
||||
Boolean isDefaultScope)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(ifCondition?.Value))
|
||||
{
|
||||
return $"{PipelineTemplateConstants.Success}()";
|
||||
}
|
||||
|
||||
var condition = ifCondition.Value;
|
||||
|
||||
var expressionParser = new ExpressionParser();
|
||||
var functions = default(IFunctionInfo[]);
|
||||
var namedValues = default(INamedValueInfo[]);
|
||||
if (isJob)
|
||||
{
|
||||
namedValues = s_jobIfNamedValues;
|
||||
functions = PhaseCondition.FunctionInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
namedValues = isDefaultScope ? s_stepNamedValues : s_stepInTemplateNamedValues;
|
||||
functions = s_stepConditionFunctions;
|
||||
}
|
||||
|
||||
var node = default(ExpressionNode);
|
||||
try
|
||||
{
|
||||
node = expressionParser.CreateTree(condition, null, namedValues, functions) as ExpressionNode;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Error(ifCondition, ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
return $"{PipelineTemplateConstants.Success}()";
|
||||
}
|
||||
|
||||
var hasStatusFunction = node.Traverse().Any(x =>
|
||||
{
|
||||
if (x is Function function)
|
||||
{
|
||||
return String.Equals(function.Name, PipelineTemplateConstants.Always, StringComparison.OrdinalIgnoreCase) ||
|
||||
String.Equals(function.Name, PipelineTemplateConstants.Cancelled, StringComparison.OrdinalIgnoreCase) ||
|
||||
String.Equals(function.Name, PipelineTemplateConstants.Failure, StringComparison.OrdinalIgnoreCase) ||
|
||||
String.Equals(function.Name, PipelineTemplateConstants.Success, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return hasStatusFunction ? condition : $"{PipelineTemplateConstants.Success}() && ({condition})";
|
||||
}
|
||||
|
||||
private static readonly INamedValueInfo[] s_jobIfNamedValues = new INamedValueInfo[]
|
||||
{
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
|
||||
};
|
||||
private static readonly INamedValueInfo[] s_stepNamedValues = new INamedValueInfo[]
|
||||
{
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Strategy),
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Matrix),
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Steps),
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Job),
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Runner),
|
||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
|
||||
};
|
||||
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),
|
||||
};
|
||||
private static readonly IFunctionInfo[] s_stepConditionFunctions = new IFunctionInfo[]
|
||||
{
|
||||
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Always, 0, 0),
|
||||
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Cancelled, 0, 0),
|
||||
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Failure, 0, 0),
|
||||
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Success, 0, 0),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user