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); }
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) { }
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; }
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)); }
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); } }
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); }