Example #1
0
        internal static ContainerRegistryCredentials ConvertToContainerCredentials(TemplateToken token)
        {
            var credentials = token.AssertMapping(PipelineTemplateConstants.Credentials);
            var result      = new ContainerRegistryCredentials();

            foreach (var credentialProperty in credentials)
            {
                var propertyName = credentialProperty.Key.AssertString($"{PipelineTemplateConstants.Credentials} key");
                switch (propertyName.Value)
                {
                case PipelineTemplateConstants.Username:
                    result.Username = credentialProperty.Value.AssertString(PipelineTemplateConstants.Username).Value;
                    break;

                case PipelineTemplateConstants.Password:
                    result.Password = credentialProperty.Value.AssertString(PipelineTemplateConstants.Password).Value;
                    break;

                default:
                    propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Credentials} key {propertyName}");
                    break;
                }
            }

            return(result);
        }
Example #2
0
        public Dictionary <String, String> EvaluateJobDefaultsRun(
            TemplateToken token,
            DictionaryContextData contextData)
        {
            var result = default(Dictionary <String, String>);

            if (token != null && token.Type != TokenType.Null)
            {
                var context = CreateContext(contextData);
                try
                {
                    token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.JobDefaultsRun, token, 0, null, omitHeader: true);
                    context.Errors.Check();
                    result = new Dictionary <String, String>(StringComparer.OrdinalIgnoreCase);
                    var mapping = token.AssertMapping("defaults run");
                    foreach (var pair in mapping)
                    {
                        // Literal key
                        var key = pair.Key.AssertString("defaults run key");

                        // Literal value
                        var value = pair.Value.AssertString("defaults run value");
                        result[key.Value] = value.Value;
                    }
                }
                catch (Exception ex) when(!(ex is TemplateValidationException))
                {
                    context.Errors.Add(ex);
                }

                context.Errors.Check();
            }

            return(result);
        }
        internal PropertyValue(TemplateToken token)
        {
            if (token is StringToken stringToken)
            {
                Type = stringToken.Value;
            }
            else
            {
                var mapping = token.AssertMapping($"{TemplateConstants.MappingPropertyValue}");
                foreach (var mappingPair in mapping)
                {
                    var mappingKey = mappingPair.Key.AssertString($"{TemplateConstants.MappingPropertyValue} key");
                    switch (mappingKey.Value)
                    {
                    case TemplateConstants.Type:
                        Type = mappingPair.Value.AssertString($"{TemplateConstants.MappingPropertyValue} {TemplateConstants.Type}").Value;
                        break;

                    case TemplateConstants.Required:
                        Required = mappingPair.Value.AssertBoolean($"{TemplateConstants.MappingPropertyValue} {TemplateConstants.Required}").Value;
                        break;

                    default:
                        mappingKey.AssertUnexpectedValue($"{TemplateConstants.MappingPropertyValue} key");
                        break;
                    }
                }
            }
        }
Example #4
0
        internal static Dictionary <String, String> ConvertToStepEnvironment(
            TemplateContext context,
            TemplateToken environment,
            StringComparer keyComparer,
            Boolean allowExpressions = false)
        {
            var result = new Dictionary <String, String>(keyComparer);

            // Expression
            if (allowExpressions && environment is ExpressionToken)
            {
                return(result);
            }

            // Mapping
            var mapping = environment.AssertMapping("environment");

            foreach (var pair in mapping)
            {
                // Expression key
                if (allowExpressions && pair.Key is ExpressionToken)
                {
                    continue;
                }

                // String key
                var key = pair.Key.AssertString("environment key");

                // Expression value
                if (allowExpressions && pair.Value is ExpressionToken)
                {
                    continue;
                }

                // String value
                var value = pair.Value.AssertString("environment value");
                result[key.Value] = value.Value;
            }

            return(result);
        }
Example #5
0
        internal static Dictionary <String, String> ConvertToStepInputs(
            TemplateContext context,
            TemplateToken inputs,
            Boolean allowExpressions = false)
        {
            var result = new Dictionary <String, String>(StringComparer.OrdinalIgnoreCase);

            // Expression
            if (allowExpressions && inputs is ExpressionToken)
            {
                return(result);
            }

            // Mapping
            var mapping = inputs.AssertMapping("inputs");

            foreach (var pair in mapping)
            {
                // Expression key
                if (allowExpressions && pair.Key is ExpressionToken)
                {
                    continue;
                }

                // Literal key
                var key = pair.Key.AssertString("inputs key");

                // Expression value
                if (allowExpressions && pair.Value is ExpressionToken)
                {
                    continue;
                }

                // Literal value
                var value = pair.Value.AssertString("inputs value");
                result[key.Value] = value.Value;
            }

            return(result);
        }
Example #6
0
        private void ConvertInputs(
            TemplateContext context,
            TemplateToken inputsToken,
            ActionDefinitionData actionDefinition)
        {
            actionDefinition.Inputs = new MappingToken(null, null, null);
            var inputsMapping = inputsToken.AssertMapping("inputs");

            foreach (var input in inputsMapping)
            {
                bool hasDefault    = false;
                var  inputName     = input.Key.AssertString("input name");
                var  inputMetadata = input.Value.AssertMapping("input metadata");
                foreach (var metadata in inputMetadata)
                {
                    var metadataName = metadata.Key.AssertString("input metadata").Value;
                    if (string.Equals(metadataName, "default", StringComparison.OrdinalIgnoreCase))
                    {
                        hasDefault = true;
                        actionDefinition.Inputs.Add(inputName, metadata.Value);
                    }
                    else if (string.Equals(metadataName, "deprecationMessage", StringComparison.OrdinalIgnoreCase))
                    {
                        if (actionDefinition.Deprecated == null)
                        {
                            actionDefinition.Deprecated = new Dictionary <String, String>();
                        }
                        var message = metadata.Value.AssertString("input deprecationMessage");
                        actionDefinition.Deprecated.Add(inputName.Value, message.Value);
                    }
                }

                if (!hasDefault)
                {
                    actionDefinition.Inputs.Add(inputName, new StringToken(null, null, null, string.Empty));
                }
            }
        }
Example #7
0
        internal static List <KeyValuePair <String, JobContainer> > ConvertToJobServiceContainers(
            TemplateContext context,
            TemplateToken services,
            bool allowExpressions = false)
        {
            var result = new List <KeyValuePair <String, JobContainer> >();

            if (allowExpressions && services.Traverse().Any(x => x is ExpressionToken))
            {
                return(result);
            }

            var servicesMapping = services.AssertMapping("services");

            foreach (var servicePair in servicesMapping)
            {
                var networkAlias = servicePair.Key.AssertString("services key").Value;
                var container    = ConvertToJobContainer(context, servicePair.Value);
                result.Add(new KeyValuePair <String, JobContainer>(networkAlias, container));
            }

            return(result);
        }
Example #8
0
        private ActionExecutionData ConvertRuns(
            IExecutionContext executionContext,
            TemplateContext context,
            TemplateToken inputsToken,
            MappingToken outputs = null)
        {
            var runsMapping         = inputsToken.AssertMapping("runs");
            var usingToken          = default(StringToken);
            var imageToken          = default(StringToken);
            var argsToken           = default(SequenceToken);
            var entrypointToken     = default(StringToken);
            var envToken            = default(MappingToken);
            var mainToken           = default(StringToken);
            var pluginToken         = default(StringToken);
            var preToken            = default(StringToken);
            var preEntrypointToken  = default(StringToken);
            var preIfToken          = default(StringToken);
            var postToken           = default(StringToken);
            var postEntrypointToken = default(StringToken);
            var postIfToken         = default(StringToken);
            var stepsLoaded         = default(List <Pipelines.ActionStep>);

            foreach (var run in runsMapping)
            {
                var runsKey = run.Key.AssertString("runs key").Value;
                switch (runsKey)
                {
                case "using":
                    usingToken = run.Value.AssertString("using");
                    break;

                case "image":
                    imageToken = run.Value.AssertString("image");
                    break;

                case "args":
                    argsToken = run.Value.AssertSequence("args");
                    break;

                case "entrypoint":
                    entrypointToken = run.Value.AssertString("entrypoint");
                    break;

                case "env":
                    envToken = run.Value.AssertMapping("env");
                    break;

                case "main":
                    mainToken = run.Value.AssertString("main");
                    break;

                case "plugin":
                    pluginToken = run.Value.AssertString("plugin");
                    break;

                case "post":
                    postToken = run.Value.AssertString("post");
                    break;

                case "post-entrypoint":
                    postEntrypointToken = run.Value.AssertString("post-entrypoint");
                    break;

                case "post-if":
                    postIfToken = run.Value.AssertString("post-if");
                    break;

                case "pre":
                    preToken = run.Value.AssertString("pre");
                    break;

                case "pre-entrypoint":
                    preEntrypointToken = run.Value.AssertString("pre-entrypoint");
                    break;

                case "pre-if":
                    preIfToken = run.Value.AssertString("pre-if");
                    break;

                case "steps":
                    if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
                    {
                        var steps     = run.Value.AssertSequence("steps");
                        var evaluator = executionContext.ToPipelineTemplateEvaluator();
                        stepsLoaded = evaluator.LoadCompositeSteps(steps);
                        break;
                    }
                    throw new Exception("You aren't supposed to be using Composite Actions yet!");

                default:
                    Trace.Info($"Ignore run property {runsKey}.");
                    break;
                }
            }

            if (usingToken != null)
            {
                if (string.Equals(usingToken.Value, "docker", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(imageToken?.Value))
                    {
                        throw new ArgumentNullException($"Image is not provided.");
                    }
                    else
                    {
                        return(new ContainerActionExecutionData()
                        {
                            Image = imageToken.Value,
                            Arguments = argsToken,
                            EntryPoint = entrypointToken?.Value,
                            Environment = envToken,
                            Pre = preEntrypointToken?.Value,
                            InitCondition = preIfToken?.Value ?? "always()",
                            Post = postEntrypointToken?.Value,
                            CleanupCondition = postIfToken?.Value ?? "always()"
                        });
                    }
                }
                else if (string.Equals(usingToken.Value, "node12", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(mainToken?.Value))
                    {
                        throw new ArgumentNullException($"Entry javascript file is not provided.");
                    }
                    else
                    {
                        return(new NodeJSActionExecutionData()
                        {
                            Script = mainToken.Value,
                            Pre = preToken?.Value,
                            InitCondition = preIfToken?.Value ?? "always()",
                            Post = postToken?.Value,
                            CleanupCondition = postIfToken?.Value ?? "always()"
                        });
                    }
                }
                else if (string.Equals(usingToken.Value, "composite", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
                {
                    if (stepsLoaded == null)
                    {
                        // 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.");
                    }
                    else
                    {
                        return(new CompositeActionExecutionData()
                        {
                            Steps = stepsLoaded,
                            Outputs = outputs
                        });
                    }
                }
                else
                {
                    throw new ArgumentOutOfRangeException($"'using: {usingToken.Value}' is not supported, use 'docker' or 'node12' instead.");
                }
            }
            else if (pluginToken != null)
            {
                return(new PluginActionExecutionData()
                {
                    Plugin = pluginToken.Value
                });
            }

            throw new NotSupportedException(nameof(ConvertRuns));
        }
        private ActionExecutionData ConvertRuns(
            IExecutionContext executionContext,
            TemplateContext templateContext,
            TemplateToken inputsToken,
            String fileRelativePath,
            MappingToken outputs = null)
        {
            var runsMapping         = inputsToken.AssertMapping("runs");
            var usingToken          = default(StringToken);
            var imageToken          = default(StringToken);
            var argsToken           = default(SequenceToken);
            var entrypointToken     = default(StringToken);
            var envToken            = default(MappingToken);
            var mainToken           = default(StringToken);
            var pluginToken         = default(StringToken);
            var preToken            = default(StringToken);
            var preEntrypointToken  = default(StringToken);
            var preIfToken          = default(StringToken);
            var postToken           = default(StringToken);
            var postEntrypointToken = default(StringToken);
            var postIfToken         = default(StringToken);
            var steps = default(List <Pipelines.Step>);

            foreach (var run in runsMapping)
            {
                var runsKey = run.Key.AssertString("runs key").Value;
                switch (runsKey)
                {
                case "using":
                    usingToken = run.Value.AssertString("using");
                    break;

                case "image":
                    imageToken = run.Value.AssertString("image");
                    break;

                case "args":
                    argsToken = run.Value.AssertSequence("args");
                    break;

                case "entrypoint":
                    entrypointToken = run.Value.AssertString("entrypoint");
                    break;

                case "env":
                    envToken = run.Value.AssertMapping("env");
                    break;

                case "main":
                    mainToken = run.Value.AssertString("main");
                    break;

                case "plugin":
                    pluginToken = run.Value.AssertString("plugin");
                    break;

                case "post":
                    postToken = run.Value.AssertString("post");
                    break;

                case "post-entrypoint":
                    postEntrypointToken = run.Value.AssertString("post-entrypoint");
                    break;

                case "post-if":
                    postIfToken = run.Value.AssertString("post-if");
                    break;

                case "pre":
                    preToken = run.Value.AssertString("pre");
                    break;

                case "pre-entrypoint":
                    preEntrypointToken = run.Value.AssertString("pre-entrypoint");
                    break;

                case "pre-if":
                    preIfToken = run.Value.AssertString("pre-if");
                    break;

                case "steps":
                    if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
                    {
                        var stepsToken = run.Value.AssertSequence("steps");
                        steps = PipelineTemplateConverter.ConvertToSteps(templateContext, stepsToken);
                        templateContext.Errors.Check();
                        break;
                    }
                    throw new Exception("You aren't supposed to be using Composite Actions yet!");

                default:
                    Trace.Info($"Ignore run property {runsKey}.");
                    break;
                }
            }

            if (usingToken != null)
            {
                if (string.Equals(usingToken.Value, "docker", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(imageToken?.Value))
                    {
                        throw new ArgumentNullException($"You are using a Container Action but an image is not provided in {fileRelativePath}.");
                    }
                    else
                    {
                        return(new ContainerActionExecutionData()
                        {
                            Image = imageToken.Value,
                            Arguments = argsToken,
                            EntryPoint = entrypointToken?.Value,
                            Environment = envToken,
                            Pre = preEntrypointToken?.Value,
                            InitCondition = preIfToken?.Value ?? "always()",
                            Post = postEntrypointToken?.Value,
                            CleanupCondition = postIfToken?.Value ?? "always()"
                        });
                    }
                }
                else if (string.Equals(usingToken.Value, "node12", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(mainToken?.Value))
                    {
                        throw new ArgumentNullException($"You are using a JavaScript Action but there is not an entry JavaScript file provided in {fileRelativePath}.");
                    }
                    else
                    {
                        return(new NodeJSActionExecutionData()
                        {
                            Script = mainToken.Value,
                            Pre = preToken?.Value,
                            InitCondition = preIfToken?.Value ?? "always()",
                            Post = postToken?.Value,
                            CleanupCondition = postIfToken?.Value ?? "always()"
                        });
                    }
                }
                else if (string.Equals(usingToken.Value, "composite", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
                {
                    if (steps == null)
                    {
                        throw new ArgumentNullException($"You are using a composite action but there are no steps provided in {fileRelativePath}.");
                    }
                    else
                    {
                        return(new CompositeActionExecutionData()
                        {
                            Steps = steps.Cast <Pipelines.ActionStep>().ToList(),
                            Outputs = outputs
                        });
                    }
                }
                else
                {
                    throw new ArgumentOutOfRangeException($"'using: {usingToken.Value}' is not supported, use 'docker' or 'node12' instead.");
                }
            }
            else if (pluginToken != null)
            {
                return(new PluginActionExecutionData()
                {
                    Plugin = pluginToken.Value
                });
            }

            throw new NotSupportedException(nameof(ConvertRuns));
        }
Example #10
0
        private ActionExecutionData ConvertRuns(
            TemplateContext context,
            TemplateToken inputsToken)
        {
            var runsMapping         = inputsToken.AssertMapping("runs");
            var usingToken          = default(StringToken);
            var imageToken          = default(StringToken);
            var argsToken           = default(SequenceToken);
            var entrypointToken     = default(StringToken);
            var envToken            = default(MappingToken);
            var mainToken           = default(StringToken);
            var pluginToken         = default(StringToken);
            var postToken           = default(StringToken);
            var postEntrypointToken = default(StringToken);
            var postIfToken         = default(StringToken);

            foreach (var run in runsMapping)
            {
                var runsKey = run.Key.AssertString("runs key").Value;
                switch (runsKey)
                {
                case "using":
                    usingToken = run.Value.AssertString("using");
                    break;

                case "image":
                    imageToken = run.Value.AssertString("image");
                    break;

                case "args":
                    argsToken = run.Value.AssertSequence("args");
                    break;

                case "entrypoint":
                    entrypointToken = run.Value.AssertString("entrypoint");
                    break;

                case "env":
                    envToken = run.Value.AssertMapping("env");
                    break;

                case "main":
                    mainToken = run.Value.AssertString("main");
                    break;

                case "plugin":
                    pluginToken = run.Value.AssertString("plugin");
                    break;

                case "post":
                    postToken = run.Value.AssertString("post");
                    break;

                case "post-entrypoint":
                    postEntrypointToken = run.Value.AssertString("post-entrypoint");
                    break;

                case "post-if":
                    postIfToken = run.Value.AssertString("post-if");
                    break;

                default:
                    Trace.Info($"Ignore run property {runsKey}.");
                    break;
                }
            }

            if (usingToken != null)
            {
                if (string.Equals(usingToken.Value, "docker", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(imageToken?.Value))
                    {
                        throw new ArgumentNullException($"Image is not provided.");
                    }
                    else
                    {
                        return(new ContainerActionExecutionData()
                        {
                            Image = imageToken.Value,
                            Arguments = argsToken,
                            EntryPoint = entrypointToken?.Value,
                            Environment = envToken,
                            Cleanup = postEntrypointToken?.Value,
                            CleanupCondition = postIfToken?.Value
                        });
                    }
                }
                else if (string.Equals(usingToken.Value, "node12", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(mainToken?.Value))
                    {
                        throw new ArgumentNullException($"Entry javascript fils is not provided.");
                    }
                    else
                    {
                        return(new NodeJSActionExecutionData()
                        {
                            Script = mainToken.Value,
                            Cleanup = postToken?.Value,
                            CleanupCondition = postIfToken?.Value
                        });
                    }
                }
                else
                {
                    throw new ArgumentOutOfRangeException($"'using: {usingToken.Value}' is not supported, use 'docker' or 'node12' instead.");
                }
            }
            else if (pluginToken != null)
            {
                return(new PluginActionExecutionData()
                {
                    Plugin = pluginToken.Value
                });
            }

            throw new NotSupportedException(nameof(ConvertRuns));
        }
Example #11
0
        private static ActionStep ConvertToStep(
            TemplateContext context,
            TemplateToken stepsItem,
            ReferenceNameBuilder nameBuilder)
        {
            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 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 (!String.IsNullOrEmpty(id.Value))
                    {
                        if (!nameBuilder.TryAddKnownName(id.Value, out var error))
                        {
                            context.Error(id, error);
                        }
                    }
                    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.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
            ifCondition = ConvertToIfCondition(context, ifToken, false);

            if (run != null)
            {
                var result = new ActionStep
                {
                    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
                {
                    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);
            }
        }
Example #12
0
        internal static JobContainer ConvertToJobContainer(
            TemplateContext context,
            TemplateToken value,
            bool allowExpressions = false)
        {
            var result = new JobContainer();

            if (allowExpressions && value.Traverse().Any(x => x is ExpressionToken))
            {
                return(result);
            }

            if (value is StringToken containerLiteral)
            {
                if (String.IsNullOrEmpty(containerLiteral.Value))
                {
                    return(null);
                }

                result.Image = containerLiteral.Value;
            }
            else
            {
                var containerMapping = value.AssertMapping($"{PipelineTemplateConstants.Container}");
                foreach (var containerPropertyPair in containerMapping)
                {
                    var propertyName = containerPropertyPair.Key.AssertString($"{PipelineTemplateConstants.Container} key");

                    switch (propertyName.Value)
                    {
                    case PipelineTemplateConstants.Image:
                        result.Image = containerPropertyPair.Value.AssertString($"{PipelineTemplateConstants.Container} {propertyName}").Value;
                        break;

                    case PipelineTemplateConstants.Env:
                        var env     = containerPropertyPair.Value.AssertMapping($"{PipelineTemplateConstants.Container} {propertyName}");
                        var envDict = new Dictionary <String, String>(env.Count);
                        foreach (var envPair in env)
                        {
                            var envKey   = envPair.Key.ToString();
                            var envValue = envPair.Value.AssertString($"{PipelineTemplateConstants.Container} {propertyName} {envPair.Key.ToString()}").Value;
                            envDict.Add(envKey, envValue);
                        }
                        result.Environment = envDict;
                        break;

                    case PipelineTemplateConstants.Options:
                        result.Options = containerPropertyPair.Value.AssertString($"{PipelineTemplateConstants.Container} {propertyName}").Value;
                        break;

                    case PipelineTemplateConstants.Ports:
                        var ports    = containerPropertyPair.Value.AssertSequence($"{PipelineTemplateConstants.Container} {propertyName}");
                        var portList = new List <String>(ports.Count);
                        foreach (var portItem in ports)
                        {
                            var portString = portItem.AssertString($"{PipelineTemplateConstants.Container} {propertyName} {portItem.ToString()}").Value;
                            portList.Add(portString);
                        }
                        result.Ports = portList;
                        break;

                    case PipelineTemplateConstants.Volumes:
                        var volumes    = containerPropertyPair.Value.AssertSequence($"{PipelineTemplateConstants.Container} {propertyName}");
                        var volumeList = new List <String>(volumes.Count);
                        foreach (var volumeItem in volumes)
                        {
                            var volumeString = volumeItem.AssertString($"{PipelineTemplateConstants.Container} {propertyName} {volumeItem.ToString()}").Value;
                            volumeList.Add(volumeString);
                        }
                        result.Volumes = volumeList;
                        break;

                    case PipelineTemplateConstants.Credentials:
                        result.Credentials = ConvertToContainerCredentials(containerPropertyPair.Value);
                        break;

                    default:
                        propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Container} key");
                        break;
                    }
                }
            }

            if (result.Image.StartsWith("docker://", StringComparison.Ordinal))
            {
                result.Image = result.Image.Substring("docker://".Length);
            }

            if (String.IsNullOrEmpty(result.Image))
            {
                context.Error(value, "Container image cannot be empty");
            }

            return(result);
        }