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 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(ScalarToken); 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.AssertScalar($"{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, DisplayNameToken = name, Condition = ifCondition, TimeoutInMinutes = timeoutMinutes, Environment = env, Reference = new ScriptReference(), }; var inputs = new MappingToken(null, null, null); inputs.Add(new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.Script), run); if (workingDir != null) { inputs.Add(new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.WorkingDirectory), workingDir); } if (shell != null) { inputs.Add(new StringToken(null, null, null, PipelineConstants.ScriptStepInputs.Shell), shell); } result.Inputs = inputs; return(result); } else { uses.AssertString($"{PipelineTemplateConstants.Steps} item {PipelineTemplateConstants.Uses}"); var result = new ActionStep { ScopeName = scope?.Value, ContextName = id?.Value, ContinueOnError = continueOnError, DisplayNameToken = name, Condition = ifCondition, TimeoutInMinutes = timeoutMinutes, 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); } }