Exemple #1
0
        public async void WriteEventPayload()
        {
            //Arrange
            Setup();
            var actionId     = Guid.NewGuid();
            var actionInputs = new MappingToken(null, null, null);

            actionInputs.Add(new StringToken(null, null, null, "input1"), new StringToken(null, null, null, "test1"));
            actionInputs.Add(new StringToken(null, null, null, "input2"), new StringToken(null, null, null, "test2"));
            var action = new Pipelines.ActionStep()
            {
                Name      = "action",
                Id        = actionId,
                Reference = new Pipelines.ContainerRegistryReference()
                {
                    Image = "ubuntu:16.04"
                },
                Inputs = actionInputs
            };

            _actionRunner.Action = action;

            Dictionary <string, string> finialInputs = new Dictionary <string, string>();

            _handlerFactory.Setup(x => x.Create(It.IsAny <IExecutionContext>(), It.IsAny <ActionStepDefinitionReference>(), It.IsAny <IStepHost>(), It.IsAny <ActionExecutionData>(), It.IsAny <Dictionary <string, string> >(), It.IsAny <Dictionary <string, string> >(), It.IsAny <Variables>(), It.IsAny <string>()))
            .Callback((IExecutionContext executionContext, Pipelines.ActionStepDefinitionReference actionReference, IStepHost stepHost, ActionExecutionData data, Dictionary <string, string> inputs, Dictionary <string, string> environment, Variables runtimeVariables, string taskDirectory) =>
            {
                finialInputs = inputs;
            })
            .Returns(new Mock <IHandler>().Object);

            //Act
            await _actionRunner.RunAsync();

            //Assert
            _ec.Verify(x => x.SetGitHubContext("event_path", Path.Combine(_hc.GetDirectory(WellKnownDirectory.Temp), "_github_workflow", "event.json")), Times.Once);
        }
Exemple #2
0
 protected Definition(MappingToken definition)
 {
     for (var i = 0; i < definition.Count;)
     {
         var definitionKey = definition[i].Key.AssertString($"{TemplateConstants.Definition} key");
         if (String.Equals(definitionKey.Value, TemplateConstants.Context, StringComparison.Ordinal))
         {
             var context = definition[i].Value.AssertSequence($"{TemplateConstants.Context}");
             definition.RemoveAt(i);
             Context = context
                       .Select(x => x.AssertString($"{TemplateConstants.Context} item").Value)
                       .Distinct()
                       .ToArray();
         }
         else if (String.Equals(definitionKey.Value, TemplateConstants.Description, StringComparison.Ordinal))
         {
             definition.RemoveAt(i);
         }
         else
         {
             i++;
         }
     }
 }
        private void HandleMappingWithWellKnownProperties(
            DefinitionInfo definition,
            List <MappingDefinition> mappingDefinitions,
            MappingToken mapping)
        {
            // Check if loose properties are allowed
            String         looseKeyType         = null;
            String         looseValueType       = null;
            DefinitionInfo?looseKeyDefinition   = null;
            DefinitionInfo?looseValueDefinition = null;

            if (!String.IsNullOrEmpty(mappingDefinitions[0].LooseKeyType))
            {
                looseKeyType   = mappingDefinitions[0].LooseKeyType;
                looseValueType = mappingDefinitions[0].LooseValueType;
            }

            var keys = new HashSet <String>(StringComparer.OrdinalIgnoreCase);

            while (m_unraveler.AllowScalar(definition.Expand, out ScalarToken nextKeyScalar))
            {
                // Expression
                if (nextKeyScalar is ExpressionToken)
                {
                    var anyDefinition = new DefinitionInfo(definition, TemplateConstants.Any);
                    mapping.Add(nextKeyScalar, Evaluate(anyDefinition));
                    continue;
                }

                // Not a string, convert
                if (!(nextKeyScalar is StringToken nextKey))
                {
                    nextKey = new StringToken(nextKeyScalar.FileId, nextKeyScalar.Line, nextKeyScalar.Column, nextKeyScalar.ToString());
                }

                // Duplicate
                if (!keys.Add(nextKey.Value))
                {
                    m_context.Error(nextKey, TemplateStrings.ValueAlreadyDefined(nextKey.Value));
                    m_unraveler.SkipMappingValue();
                    continue;
                }

                // Well known
                if (m_schema.TryMatchKey(mappingDefinitions, nextKey.Value, out String nextValueType))
                {
                    var nextValueDefinition = new DefinitionInfo(definition, nextValueType);
                    var nextValue           = Evaluate(nextValueDefinition);
                    mapping.Add(nextKey, nextValue);
                    continue;
                }

                // Loose
                if (looseKeyType != null)
                {
                    if (looseKeyDefinition == null)
                    {
                        looseKeyDefinition   = new DefinitionInfo(definition, looseKeyType);
                        looseValueDefinition = new DefinitionInfo(definition, looseValueType);
                    }

                    Validate(nextKey, looseKeyDefinition.Value);
                    var nextValue = Evaluate(looseValueDefinition.Value);
                    mapping.Add(nextKey, nextValue);
                    continue;
                }

                // Error
                m_context.Error(nextKey, TemplateStrings.UnexpectedValue(nextKey.Value));
                m_unraveler.SkipMappingValue();
            }

            // Only one
            if (mappingDefinitions.Count > 1)
            {
                var hitCount = new Dictionary <String, Int32>();
                foreach (MappingDefinition mapdef in mappingDefinitions)
                {
                    foreach (String key in mapdef.Properties.Keys)
                    {
                        if (!hitCount.TryGetValue(key, out Int32 value))
                        {
                            hitCount.Add(key, 1);
                        }
                        else
                        {
                            hitCount[key] = value + 1;
                        }
                    }
                }

                List <String> nonDuplicates = new List <String>();
                foreach (String key in hitCount.Keys)
                {
                    if (hitCount[key] == 1)
                    {
                        nonDuplicates.Add(key);
                    }
                }
                nonDuplicates.Sort();

                String listToDeDuplicate = String.Join(", ", nonDuplicates);
                m_context.Error(mapping, TemplateStrings.UnableToDetermineOneOf(listToDeDuplicate));
            }

            m_unraveler.ReadMappingEnd();
        }
        private TemplateSchema(MappingToken mapping)
        {
            // Add built-in type: null
            var nullDefinition = new NullDefinition();

            Definitions.Add(TemplateConstants.Null, nullDefinition);

            // Add built-in type: boolean
            var booleanDefinition = new BooleanDefinition();

            Definitions.Add(TemplateConstants.Boolean, booleanDefinition);

            // Add built-in type: number
            var numberDefinition = new NumberDefinition();

            Definitions.Add(TemplateConstants.Number, numberDefinition);

            // Add built-in type: string
            var stringDefinition = new StringDefinition();

            Definitions.Add(TemplateConstants.String, stringDefinition);

            // Add built-in type: sequence
            var sequenceDefinition = new SequenceDefinition {
                ItemType = TemplateConstants.Any
            };

            Definitions.Add(TemplateConstants.Sequence, sequenceDefinition);

            // Add built-in type: mapping
            var mappingDefinition = new MappingDefinition {
                LooseKeyType = TemplateConstants.String, LooseValueType = TemplateConstants.Any
            };

            Definitions.Add(TemplateConstants.Mapping, mappingDefinition);

            // Add built-in type: any
            var anyDefinition = new OneOfDefinition();

            anyDefinition.OneOf.Add(TemplateConstants.Null);
            anyDefinition.OneOf.Add(TemplateConstants.Boolean);
            anyDefinition.OneOf.Add(TemplateConstants.Number);
            anyDefinition.OneOf.Add(TemplateConstants.String);
            anyDefinition.OneOf.Add(TemplateConstants.Sequence);
            anyDefinition.OneOf.Add(TemplateConstants.Mapping);
            Definitions.Add(TemplateConstants.Any, anyDefinition);

            if (mapping != null)
            {
                foreach (var pair in mapping)
                {
                    var key = pair.Key.AssertString($"{TemplateConstants.TemplateSchema} key");
                    switch (key.Value)
                    {
                    case TemplateConstants.Version:
                        var version = pair.Value.AssertString(TemplateConstants.Version);
                        Version = version.Value;
                        break;

                    case TemplateConstants.Definitions:
                        var definitions = pair.Value.AssertMapping(TemplateConstants.Definitions);
                        foreach (var definitionsPair in definitions)
                        {
                            var definitionsKey   = definitionsPair.Key.AssertString($"{TemplateConstants.Definitions} key");
                            var definitionsValue = definitionsPair.Value.AssertMapping(TemplateConstants.Definition);
                            var definition       = default(Definition);
                            foreach (var definitionPair in definitionsValue)
                            {
                                var definitionKey = definitionPair.Key.AssertString($"{TemplateConstants.Definition} key");
                                switch (definitionKey.Value)
                                {
                                case TemplateConstants.Null:
                                    definition = new NullDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.Boolean:
                                    definition = new BooleanDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.Number:
                                    definition = new NumberDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.String:
                                    definition = new StringDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.Sequence:
                                    definition = new SequenceDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.Mapping:
                                    definition = new MappingDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.OneOf:
                                    definition = new OneOfDefinition(definitionsValue);
                                    break;

                                case TemplateConstants.Context:
                                case TemplateConstants.Description:
                                    continue;

                                default:
                                    definitionKey.AssertUnexpectedValue("definition mapping key");         // throws
                                    break;
                                }

                                break;
                            }

                            if (definition == null)
                            {
                                throw new ArgumentException($"Unable to determine definition details. Specify the '{TemplateConstants.Structure}' property");
                            }

                            Definitions.Add(definitionsKey.Value, definition);
                        }
                        break;

                    default:
                        key.AssertUnexpectedValue($"{TemplateConstants.TemplateSchema} key");     // throws
                        break;
                    }
                }
            }
        }
 internal ScalarDefinition(MappingToken definition)
     : base(definition)
 {
 }
Exemple #6
0
        private Mock <IActionRunner> CreateStep(TestHostContext hc, TaskResult result, string condition, Boolean continueOnError = false, MappingToken env = null, string name = "Test", bool setOutput = false, string contextName = null)
        {
            // Setup the step.
            var step = new Mock <IActionRunner>();

            step.Setup(x => x.Condition).Returns(condition);
            step.Setup(x => x.ContinueOnError).Returns(new BooleanToken(null, null, null, continueOnError));
            step.Setup(x => x.Action)
            .Returns(new DistributedTask.Pipelines.ActionStep()
            {
                Name        = name,
                Id          = Guid.NewGuid(),
                Environment = env,
                ContextName = contextName ?? "Test"
            });

            // Setup the step execution context.
            var stepContext = new Mock <IExecutionContext>();

            stepContext.SetupAllProperties();
            stepContext.Setup(x => x.WriteDebug).Returns(true);
            stepContext.Setup(x => x.Variables).Returns(_variables);
            stepContext.Setup(x => x.EnvironmentVariables).Returns(_env);
            stepContext.Setup(x => x.ExpressionValues).Returns(_contexts);
            stepContext.Setup(x => x.ExpressionFunctions).Returns(new List <IFunctionInfo>());
            stepContext.Setup(x => x.JobContext).Returns(_jobContext);
            stepContext.Setup(x => x.StepsContext).Returns(_stepContext);
            stepContext.Setup(x => x.ContextName).Returns(step.Object.Action.ContextName);
            stepContext.Setup(x => x.Complete(It.IsAny <TaskResult?>(), It.IsAny <string>(), It.IsAny <string>()))
            .Callback((TaskResult? r, string currentOperation, string resultCode) =>
            {
                if (r != null)
                {
                    stepContext.Object.Result = r;
                }

                _stepContext.SetOutcome("", stepContext.Object.ContextName, (stepContext.Object.Outcome ?? stepContext.Object.Result ?? TaskResult.Succeeded).ToActionResult());
                _stepContext.SetConclusion("", stepContext.Object.ContextName, (stepContext.Object.Result ?? TaskResult.Succeeded).ToActionResult());
            });
            var trace = hc.GetTrace();

            stepContext.Setup(x => x.Write(It.IsAny <string>(), It.IsAny <string>())).Callback((string tag, string message) => { trace.Info($"[{tag}]{message}"); });
            stepContext.Object.Result = result;
            step.Setup(x => x.ExecutionContext).Returns(stepContext.Object);

            if (setOutput)
            {
                step.Setup(x => x.RunAsync()).Callback(() => { _stepContext.SetOutput(null, name, "test", "something", out string reference); }).Returns(Task.CompletedTask);
            }
            else
            {
                step.Setup(x => x.RunAsync()).Returns(Task.CompletedTask);
            }

            return(step);
        }
        private void Setup([CallerMemberName] string name = "")
        {
            _ecTokenSource?.Dispose();
            _ecTokenSource = new CancellationTokenSource();

            // Test host context.
            _hc = new TestHostContext(this, name);

            var actionInputs = new MappingToken(null, null, null);

            actionInputs.Add(new StringToken(null, null, null, "input1"), new StringToken(null, null, null, "input1"));
            actionInputs.Add(new StringToken(null, null, null, "input2"), new StringToken(null, null, null, ""));
            actionInputs.Add(new StringToken(null, null, null, "input3"), new StringToken(null, null, null, "github"));
            var actionDefinition = new Definition()
            {
                Directory = _hc.GetDirectory(WellKnownDirectory.Work),
                Data      = new ActionDefinitionData()
                {
                    Name        = name,
                    Description = name,
                    Inputs      = actionInputs,
                    Execution   = new ScriptActionExecutionData()
                }
            };

            // Mocks.
            _actionManager = new Mock <IActionManager>();
            _actionManager.Setup(x => x.LoadAction(It.IsAny <IExecutionContext>(), It.IsAny <ActionStep>())).Returns(actionDefinition);

            _handlerFactory        = new Mock <IHandlerFactory>();
            _defaultStepHost       = new Mock <IDefaultStepHost>();
            _actionManifestManager = new ActionManifestManager();
            _actionManifestManager.Initialize(_hc);

            var githubContext = new GitHubContext();

            githubContext.Add("event", JToken.Parse("{\"foo\":\"bar\"}").ToPipelineContextData());
            _context.Add("github", githubContext);

#if OS_WINDOWS
            _context["env"] = new DictionaryContextData();
#else
            _context["env"] = new CaseSensitiveDictionaryContextData();
#endif

            _ec = new Mock <IExecutionContext>();
            _ec.Setup(x => x.ExpressionValues).Returns(_context);
            _ec.Setup(x => x.ExpressionFunctions).Returns(new List <IFunctionInfo>());
            _ec.Setup(x => x.IntraActionState).Returns(new Dictionary <string, string>());
            _ec.Setup(x => x.EnvironmentVariables).Returns(new Dictionary <string, string>());
            _ec.Setup(x => x.FileTable).Returns(new List <String>());
            _ec.Setup(x => x.SetGitHubContext(It.IsAny <string>(), It.IsAny <string>()));
            _ec.Setup(x => x.GetGitHubContext(It.IsAny <string>())).Returns("{\"foo\":\"bar\"}");
            _ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
            _ec.Setup(x => x.Variables).Returns(new Variables(_hc, new Dictionary <string, VariableValue>()));
            _ec.Setup(x => x.Write(It.IsAny <string>(), It.IsAny <string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
            _ec.Setup(x => x.AddIssue(It.IsAny <Issue>(), It.IsAny <string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });

            _hc.SetSingleton <IActionManager>(_actionManager.Object);
            _hc.SetSingleton <IHandlerFactory>(_handlerFactory.Object);
            _hc.SetSingleton <IActionManifestManager>(_actionManifestManager);

            _hc.EnqueueInstance <IDefaultStepHost>(_defaultStepHost.Object);

            // Instance to test.
            _actionRunner = new ActionRunner();
            _actionRunner.Initialize(_hc);
            _actionRunner.ExecutionContext = _ec.Object;
        }
Exemple #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));
        }
Exemple #10
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);
            }
        }
Exemple #11
0
        private void HandleMappingWithWellKnownProperties(
            DefinitionInfo definition,
            List <MappingDefinition> mappingDefinitions,
            MappingToken mapping)
        {
            // Check if loose properties are allowed
            String         looseKeyType         = null;
            String         looseValueType       = null;
            DefinitionInfo?looseKeyDefinition   = null;
            DefinitionInfo?looseValueDefinition = null;

            if (!String.IsNullOrEmpty(mappingDefinitions[0].LooseKeyType))
            {
                looseKeyType   = mappingDefinitions[0].LooseKeyType;
                looseValueType = mappingDefinitions[0].LooseValueType;
            }

            var keys             = new HashSet <String>(StringComparer.OrdinalIgnoreCase);
            var hasExpressionKey = false;

            while (m_objectReader.AllowLiteral(out LiteralToken rawLiteral))
            {
                var nextKeyScalar = ParseScalar(rawLiteral, definition.AllowedContext);
                // Expression
                if (nextKeyScalar is ExpressionToken)
                {
                    hasExpressionKey = true;
                    // Legal
                    if (definition.AllowedContext.Length > 0)
                    {
                        m_memory.AddBytes(nextKeyScalar);
                        var anyDefinition = new DefinitionInfo(definition, TemplateConstants.Any);
                        mapping.Add(nextKeyScalar, ReadValue(anyDefinition));
                    }
                    // Illegal
                    else
                    {
                        m_context.Error(nextKeyScalar, TemplateStrings.ExpressionNotAllowed());
                        SkipValue();
                    }

                    continue;
                }

                // Not a string, convert
                if (!(nextKeyScalar is StringToken nextKey))
                {
                    nextKey = new StringToken(nextKeyScalar.FileId, nextKeyScalar.Line, nextKeyScalar.Column, nextKeyScalar.ToString());
                }

                // Duplicate
                if (!keys.Add(nextKey.Value))
                {
                    m_context.Error(nextKey, TemplateStrings.ValueAlreadyDefined(nextKey.Value));
                    SkipValue();
                    continue;
                }

                // Well known
                if (m_schema.TryMatchKey(mappingDefinitions, nextKey.Value, out String nextValueType))
                {
                    m_memory.AddBytes(nextKey);
                    var nextValueDefinition = new DefinitionInfo(definition, nextValueType);
                    var nextValue           = ReadValue(nextValueDefinition);
                    mapping.Add(nextKey, nextValue);
                    continue;
                }

                // Loose
                if (looseKeyType != null)
                {
                    if (looseKeyDefinition == null)
                    {
                        looseKeyDefinition   = new DefinitionInfo(definition, looseKeyType);
                        looseValueDefinition = new DefinitionInfo(definition, looseValueType);
                    }

                    Validate(nextKey, looseKeyDefinition.Value);
                    m_memory.AddBytes(nextKey);
                    var nextValue = ReadValue(looseValueDefinition.Value);
                    mapping.Add(nextKey, nextValue);
                    continue;
                }

                // Error
                m_context.Error(nextKey, TemplateStrings.UnexpectedValue(nextKey.Value));
                SkipValue();
            }

            // Only one
            if (mappingDefinitions.Count > 1)
            {
                var hitCount = new Dictionary <String, Int32>();
                foreach (MappingDefinition mapdef in mappingDefinitions)
                {
                    foreach (String key in mapdef.Properties.Keys)
                    {
                        if (!hitCount.TryGetValue(key, out Int32 value))
                        {
                            hitCount.Add(key, 1);
                        }
                        else
                        {
                            hitCount[key] = value + 1;
                        }
                    }
                }

                List <String> nonDuplicates = new List <String>();
                foreach (String key in hitCount.Keys)
                {
                    if (hitCount[key] == 1)
                    {
                        nonDuplicates.Add(key);
                    }
                }
                nonDuplicates.Sort();

                String listToDeDuplicate = String.Join(", ", nonDuplicates);
                m_context.Error(mapping, TemplateStrings.UnableToDetermineOneOf(listToDeDuplicate));
            }
            else if (mappingDefinitions.Count == 1 && !hasExpressionKey)
            {
                foreach (var property in mappingDefinitions[0].Properties)
                {
                    if (property.Value.Required)
                    {
                        if (!keys.Contains(property.Key))
                        {
                            m_context.Error(mapping, $"Required property is missing: {property.Key}");
                        }
                    }
                }
            }
            ExpectMappingEnd();
        }
        internal void AddBytes(MappingToken mapping)
        {
            var bytes = CalculateBytes(mapping);

            AddBytes(bytes);
        }