This commit is contained in:
Tingluo Huang
2019-12-11 15:53:03 -05:00
committed by TingluoHuang
parent b37aa3254f
commit 3ea3b5ff59
17 changed files with 0 additions and 1451 deletions

View File

@@ -1,25 +0,0 @@
using System;
using System.ComponentModel;
using System.Runtime.Serialization;
namespace GitHub.DistributedTask.Pipelines
{
[DataContract]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class ConditionResult
{
[DataMember]
public Boolean Value
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public String Trace
{
get;
set;
}
}
}

View File

@@ -146,26 +146,6 @@ namespace GitHub.DistributedTask.Pipelines
/// </summary>
internal Boolean IsLiteral => String.IsNullOrEmpty(m_expression);
/// <summary>
/// Retrieves the referenced value from the provided execution context.
/// </summary>
/// <param name="context">The execution context used for variable resolution</param>
/// <returns>The value of the variable if found; otherwise, null</returns>
public ExpressionResult<T> GetValue(IPipelineContext context = null)
{
if (this.IsLiteral)
{
return new ExpressionResult<T>(m_literalValue, containsSecrets: false);
}
if (context != null)
{
return context.Evaluate<T>(m_expression);
}
return null;
}
/// <summary>
/// Converts the value to a string representation.
/// </summary>

View File

@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using GitHub.DistributedTask.Expressions2;
using GitHub.DistributedTask.Logging;
using GitHub.DistributedTask.Pipelines.ContextData;
using GitHub.DistributedTask.WebApi;
using Newtonsoft.Json.Linq;
namespace GitHub.DistributedTask.Pipelines
{
/// <summary>
/// Provides the environment and services available during build and execution of a pipeline.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IPipelineContext
{
DictionaryContextData Data { get; }
Int32 EnvironmentVersion { get; }
EvaluationOptions ExpressionOptions { get; }
ISecretMasker SecretMasker { get; }
IPipelineTraceWriter Trace { get; }
ISet<String> SystemVariableNames { get; }
IDictionary<String, VariableValue> Variables { get; }
String ExpandVariables(String value, Boolean maskSecrets = false);
ExpressionResult<T> Evaluate<T>(String expression);
ExpressionResult<JObject> Evaluate(JObject value);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IPipelineTraceWriter : ITraceWriter
{
void EnterProperty(String name);
void LeaveProperty(String name);
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.ComponentModel;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IFileProvider
{
String GetFileContent(String path);
String ResolvePath(String defaultRoot, String path);
}
}

View File

@@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
internal sealed class JobDisplayNameBuilder
{
public JobDisplayNameBuilder(String jobFactoryDisplayName)
{
if (!String.IsNullOrEmpty(jobFactoryDisplayName))
{
m_jobFactoryDisplayName = jobFactoryDisplayName;
m_segments = new List<String>();
}
}
public void AppendSegment(String value)
{
if (String.IsNullOrEmpty(value) || m_segments == null)
{
return;
}
m_segments.Add(value);
}
public String Build()
{
if (String.IsNullOrEmpty(m_jobFactoryDisplayName))
{
return null;
}
var displayName = default(String);
if (m_segments.Count == 0)
{
displayName = m_jobFactoryDisplayName;
}
else
{
var joinedSegments = String.Join(", ", m_segments);
displayName = String.Format(CultureInfo.InvariantCulture, "{0} ({1})", m_jobFactoryDisplayName, joinedSegments);
}
const Int32 maxDisplayNameLength = 100;
if (displayName.Length > maxDisplayNameLength)
{
displayName = displayName.Substring(0, maxDisplayNameLength - 3) + "...";
}
m_segments.Clear();
return displayName;
}
private readonly String m_jobFactoryDisplayName;
private readonly List<String> m_segments;
}
}

View File

@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class ParseOptions
{
public ParseOptions()
{
}
internal ParseOptions(ParseOptions copy)
{
MaxFiles = copy.MaxFiles;
MaxFileSize = copy.MaxFileSize;
MaxResultSize = copy.MaxResultSize;
}
public Int32 MaxDepth => 50;
/// <summary>
/// Gets the maximum error message length before the message will be truncated.
/// </summary>
public Int32 MaxErrorMessageLength => 500;
/// <summary>
/// Gets the maximum number of errors that can be recorded when parsing a pipeline.
/// </summary>
public Int32 MaxErrors => 10;
/// <summary>
/// Gets or sets the maximum number of files that can be loaded when parsing a pipeline. Zero or less is treated as infinite.
/// </summary>
public Int32 MaxFiles { get; set; } = 50;
public Int32 MaxFileSize { get; set; } = 1024 * 1024; // 1 mb
public Int32 MaxParseEvents => 1000000; // 1 million
public Int32 MaxResultSize { get; set; } = 10 * 1024 * 1024; // 10 mb
}
}

View File

@@ -1,30 +0,0 @@
using System;
using System.IO;
using GitHub.DistributedTask.ObjectTemplating;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
internal sealed class ParseResult
{
public TemplateContext Context { get; set; }
public TemplateToken Value { get; set; }
public String ToYaml()
{
if (Value == null)
{
return null;
}
// Serialize
using (var stringWriter = new StringWriter())
{
TemplateWriter.Write(new YamlObjectWriter(stringWriter), Value);
stringWriter.Flush();
return stringWriter.ToString();
}
}
}
}

View File

@@ -16,52 +16,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
internal static class PipelineTemplateConverter
{
internal static String ConvertToJobDisplayName(
TemplateContext context,
TemplateToken displayName,
Boolean allowExpressions = false)
{
var result = default(String);
// Expression
if (allowExpressions && displayName is ExpressionToken)
{
return result;
}
// String
var displayNameString = displayName.AssertString($"job {PipelineTemplateConstants.Name}");
result = displayNameString.Value;
return result;
}
internal static Int32? ConvertToJobTimeout(
TemplateContext context,
TemplateToken token,
Boolean allowExpressions = false)
{
if (allowExpressions && token is ExpressionToken)
{
return null;
}
var numberToken = token.AssertNumber($"job {PipelineTemplateConstants.TimeoutMinutes}");
return (Int32)numberToken.Value;
}
internal static Int32? ConvertToJobCancelTimeout(
TemplateContext context,
TemplateToken token,
Boolean allowExpressions = false)
{
if (allowExpressions && token is ExpressionToken)
{
return null;
}
var numberToken = token.AssertNumber($"job {PipelineTemplateConstants.CancelTimeoutMinutes}");
return (Int32)numberToken.Value;
}
internal static Boolean? ConvertToStepContinueOnError(
TemplateContext context,
TemplateToken token,
@@ -291,74 +245,5 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
return result;
}
private static IEnumerable<ContextScope> ConvertToScopes(
TemplateContext context,
TemplateToken scopes)
{
var scopesSequence = scopes.AssertSequence($"job {PipelineTemplateConstants.Scopes}");
foreach (var scopesItem in scopesSequence)
{
var result = new ContextScope();
var scope = scopesItem.AssertMapping($"{PipelineTemplateConstants.Scopes} item");
foreach (var scopeProperty in scope)
{
var propertyName = scopeProperty.Key.AssertString($"{PipelineTemplateConstants.Scopes} item key");
switch (propertyName.Value)
{
case PipelineTemplateConstants.Name:
var nameLiteral = scopeProperty.Value.AssertString($"{PipelineTemplateConstants.Scopes} item {PipelineTemplateConstants.Name}");
result.Name = nameLiteral.Value;
break;
case PipelineTemplateConstants.Inputs:
result.Inputs = scopeProperty.Value.AssertMapping($"{PipelineTemplateConstants.Scopes} item {PipelineTemplateConstants.Inputs}");
break;
case PipelineTemplateConstants.Outputs:
result.Outputs = scopeProperty.Value.AssertMapping($"{PipelineTemplateConstants.Scopes} item {PipelineTemplateConstants.Outputs}");
break;
}
}
yield return result;
}
}
private static readonly INamedValueInfo[] s_jobIfNamedValues = new INamedValueInfo[]
{
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
};
private static readonly INamedValueInfo[] s_stepNamedValues = new INamedValueInfo[]
{
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Strategy),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Matrix),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Steps),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Job),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Runner),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
};
private static readonly INamedValueInfo[] s_stepInTemplateNamedValues = new INamedValueInfo[]
{
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Strategy),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Matrix),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Steps),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Inputs),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Job),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Runner),
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
};
private static readonly IFunctionInfo[] s_stepConditionFunctions = new IFunctionInfo[]
{
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Always, 0, 0),
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Cancelled, 0, 0),
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Failure, 0, 0),
new FunctionInfo<NoOperation>(PipelineTemplateConstants.Success, 0, 0),
};
}
}

View File

@@ -46,85 +46,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public Int32 MaxResultSize { get; set; } = 10 * 1024 * 1024; // 10 mb
public String EvaluateJobDisplayName(
TemplateToken token,
DictionaryContextData contextData,
String defaultDisplayName)
{
var result = default(String);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(contextData);
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StringStrategyContext, token, 0, null, omitHeader: true);
context.Errors.Check();
result = PipelineTemplateConverter.ConvertToJobDisplayName(context, token);
}
catch (Exception ex) when (!(ex is TemplateValidationException))
{
context.Errors.Add(ex);
}
context.Errors.Check();
}
return !String.IsNullOrEmpty(result) ? result : defaultDisplayName;
}
public Int32 EvaluateJobTimeout(
TemplateToken token,
DictionaryContextData contextData)
{
var result = default(Int32?);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(contextData);
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.NumberStrategyContext, token, 0, null, omitHeader: true);
context.Errors.Check();
result = PipelineTemplateConverter.ConvertToJobTimeout(context, token);
}
catch (Exception ex) when (!(ex is TemplateValidationException))
{
context.Errors.Add(ex);
}
context.Errors.Check();
}
return result ?? PipelineConstants.DefaultJobTimeoutInMinutes;
}
public Int32 EvaluateJobCancelTimeout(
TemplateToken token,
DictionaryContextData contextData)
{
var result = default(Int32?);
if (token != null && token.Type != TokenType.Null)
{
var context = CreateContext(contextData);
try
{
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.NumberStrategyContext, token, 0, null, omitHeader: true);
context.Errors.Check();
result = PipelineTemplateConverter.ConvertToJobCancelTimeout(context, token);
}
catch (Exception ex) when (!(ex is TemplateValidationException))
{
context.Errors.Add(ex);
}
context.Errors.Check();
}
return result ?? PipelineConstants.DefaultJobCancelTimeoutInMinutes;
}
public DictionaryContextData EvaluateStepScopeInputs(
TemplateToken token,
DictionaryContextData contextData)

View File

@@ -1,37 +0,0 @@
using GitHub.DistributedTask.Pipelines.ContextData;
using GitHub.DistributedTask.WebApi;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
public static class TaskResultExtensions
{
public static PipelineContextData ToContextData(this TaskResult result)
{
switch (result)
{
case TaskResult.Succeeded:
case TaskResult.SucceededWithIssues:
return new StringContextData(PipelineTemplateConstants.Success);
case TaskResult.Failed:
case TaskResult.Abandoned:
return new StringContextData(PipelineTemplateConstants.Failure);
case TaskResult.Canceled:
return new StringContextData(PipelineTemplateConstants.Cancelled);
case TaskResult.Skipped:
return new StringContextData(PipelineTemplateConstants.Skipped);
}
return null;
}
public static PipelineContextData ToContextData(this TaskResult? result)
{
if (result.HasValue)
{
return result.Value.ToContextData();
}
return null;
}
}
}

View File

@@ -1,197 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
using GitHub.DistributedTask.ObjectTemplating.Schema;
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
using GitHub.DistributedTask.ObjectTemplating;
internal sealed class TemplateReference
{
private TemplateReference(
String scope,
String id,
String generatedId,
StringToken templatePath,
MappingToken inputs)
{
Scope = scope;
TemplatePath = templatePath;
Inputs = inputs;
if (!String.IsNullOrEmpty(generatedId))
{
Id = generatedId;
m_isGeneratedId = true;
}
else
{
Id = id;
}
}
internal String Id { get; }
internal MappingToken Inputs { get; }
internal String Scope { get; }
internal StringToken TemplatePath { get; }
internal String TemplateScope
{
get
{
return !String.IsNullOrEmpty(Scope) ? $"{Scope}.{Id}" : Id;
}
}
internal MappingToken CreateScope(
TemplateContext context,
TemplateToken template)
{
var mapping = template.AssertMapping("template file");
// Get the inputs and outputs from the template
var inputs = default(MappingToken);
var outputs = default(MappingToken);
foreach (var pair in mapping)
{
var propertyName = pair.Key.AssertString("template file property name");
switch (propertyName.Value)
{
case PipelineTemplateConstants.Inputs:
inputs = pair.Value.AssertMapping("template file inputs");
break;
case PipelineTemplateConstants.Outputs:
if (!m_isGeneratedId)
{
outputs = pair.Value.AssertMapping("template file outputs");
}
break;
}
}
// Determine allowed input names
var allowedInputNames = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
if (inputs?.Count > 0)
{
foreach (var pair in inputs)
{
var inputPropertyName = pair.Key.AssertString("template file inputs property");
allowedInputNames.Add(inputPropertyName.Value);
}
}
// Validate override inputs names
var overrideInputs = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
var mergedInputs = new MappingToken(null, null, null);
if (Inputs?.Count > 0)
{
foreach (var pair in Inputs)
{
var inputPropertyName = pair.Key.AssertString("template reference inputs property");
if (!allowedInputNames.Contains(inputPropertyName.Value))
{
context.Error(inputPropertyName, $"Input '{inputPropertyName.Value}' is not allowed");
continue;
}
overrideInputs.Add(inputPropertyName.Value);
mergedInputs.Add(pair.Key, pair.Value);
}
}
// Merge defaults
if (inputs?.Count > 0)
{
foreach (var pair in inputs)
{
var inputPropertyName = pair.Key.AssertString("template file inputs property");
if (!overrideInputs.Contains(inputPropertyName.Value))
{
mergedInputs.Add(pair.Key, pair.Value);
}
}
}
// Build the scope object
var result = new MappingToken(null, null, null);
var namePropertyName = new StringToken(null, null, null, PipelineTemplateConstants.Name);
var namePropertyValue = new StringToken(null, null, null, TemplateScope);
result.Add(namePropertyName, namePropertyValue);
if (mergedInputs.Count > 0)
{
var inputsPropertyName = new StringToken(null, null, null, PipelineTemplateConstants.Inputs);
result.Add(inputsPropertyName, mergedInputs);
}
if (outputs?.Count > 0)
{
var outputsPropertyName = new StringToken(null, null, null, PipelineTemplateConstants.Outputs);
result.Add(outputsPropertyName, outputs);
}
return result;
}
internal static Boolean TryCreate(
MappingToken mapping,
out TemplateReference reference)
{
var scope = default(String);
var id = default(String);
var generatedId = default(String);
var templatePath = default(StringToken);
var inputs = default(MappingToken);
foreach (var property in mapping)
{
var propertyName = property.Key.AssertString("candidate template reference property name");
switch (propertyName.Value)
{
case PipelineTemplateConstants.Scope:
var scopeStringToken = property.Value.AssertString("step scope");
scope = scopeStringToken.Value;
break;
case PipelineTemplateConstants.Id:
var idStringToken = property.Value.AssertString("step id");
id = idStringToken.Value;
break;
case PipelineTemplateConstants.GeneratedId:
var generatedIdStringToken = property.Value.AssertString("step generated id");
generatedId = generatedIdStringToken.Value;
break;
case PipelineTemplateConstants.Template:
templatePath = property.Value.AssertString("step template reference");
break;
case PipelineTemplateConstants.Inputs:
inputs = property.Value.AssertMapping("step template reference inputs");
break;
}
}
if (templatePath != null)
{
reference = new TemplateReference(scope, id, generatedId, templatePath, inputs);
return true;
}
else
{
reference = null;
return false;
}
}
private Boolean m_isGeneratedId;
}
}

View File

@@ -1,572 +0,0 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using GitHub.DistributedTask.ObjectTemplating;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
/// <summary>
/// Converts a YAML file into a TemplateToken
/// </summary>
internal sealed class YamlObjectReader : IObjectReader
{
internal YamlObjectReader(
Int32? fileId,
TextReader input)
{
m_fileId = fileId;
m_parser = new Parser(input);
}
public Boolean AllowLiteral(out LiteralToken value)
{
if (EvaluateCurrent() is Scalar scalar)
{
// Tag specified
if (!String.IsNullOrEmpty(scalar.Tag))
{
// String tag
if (String.Equals(scalar.Tag, c_stringTag, StringComparison.Ordinal))
{
value = new StringToken(m_fileId, scalar.Start.Line, scalar.Start.Column, scalar.Value);
MoveNext();
return true;
}
// Not plain style
if (scalar.Style != ScalarStyle.Plain)
{
throw new NotSupportedException($"The scalar style '{scalar.Style}' on line {scalar.Start.Line} and column {scalar.Start.Column} is not valid with the tag '{scalar.Tag}'");
}
// Boolean, Float, Integer, or Null
switch (scalar.Tag)
{
case c_booleanTag:
value = ParseBoolean(scalar);
break;
case c_floatTag:
value = ParseFloat(scalar);
break;
case c_integerTag:
value = ParseInteger(scalar);
break;
case c_nullTag:
value = ParseNull(scalar);
break;
default:
throw new NotSupportedException($"Unexpected tag '{scalar.Tag}'");
}
MoveNext();
return true;
}
// Plain style, determine type using YAML 1.2 "core" schema https://yaml.org/spec/1.2/spec.html#id2804923
if (scalar.Style == ScalarStyle.Plain)
{
if (MatchNull(scalar, out var nullToken))
{
value = nullToken;
}
else if (MatchBoolean(scalar, out var booleanToken))
{
value = booleanToken;
}
else if (MatchInteger(scalar, out var numberToken) ||
MatchFloat(scalar, out numberToken))
{
value = numberToken;
}
else
{
value = new StringToken(m_fileId, scalar.Start.Line, scalar.Start.Column, scalar.Value);
}
MoveNext();
return true;
}
// Otherwise assume string
value = new StringToken(m_fileId, scalar.Start.Line, scalar.Start.Column, scalar.Value);
MoveNext();
return true;
}
value = default;
return false;
}
public Boolean AllowSequenceStart(out SequenceToken value)
{
if (EvaluateCurrent() is SequenceStart sequenceStart)
{
value = new SequenceToken(m_fileId, sequenceStart.Start.Line, sequenceStart.Start.Column);
MoveNext();
return true;
}
value = default;
return false;
}
public Boolean AllowSequenceEnd()
{
if (EvaluateCurrent() is SequenceEnd)
{
MoveNext();
return true;
}
return false;
}
public Boolean AllowMappingStart(out MappingToken value)
{
if (EvaluateCurrent() is MappingStart mappingStart)
{
value = new MappingToken(m_fileId, mappingStart.Start.Line, mappingStart.Start.Column);
MoveNext();
return true;
}
value = default;
return false;
}
public Boolean AllowMappingEnd()
{
if (EvaluateCurrent() is MappingEnd)
{
MoveNext();
return true;
}
return false;
}
/// <summary>
/// Consumes the last parsing events, which are expected to be DocumentEnd and StreamEnd.
/// </summary>
public void ValidateEnd()
{
if (EvaluateCurrent() is DocumentEnd)
{
MoveNext();
}
else
{
throw new InvalidOperationException("Expected document end parse event");
}
if (EvaluateCurrent() is StreamEnd)
{
MoveNext();
}
else
{
throw new InvalidOperationException("Expected stream end parse event");
}
if (MoveNext())
{
throw new InvalidOperationException("Expected end of parse events");
}
}
/// <summary>
/// Consumes the first parsing events, which are expected to be StreamStart and DocumentStart.
/// </summary>
public void ValidateStart()
{
if (EvaluateCurrent() != null)
{
throw new InvalidOperationException("Unexpected parser state");
}
if (!MoveNext())
{
throw new InvalidOperationException("Expected a parse event");
}
if (EvaluateCurrent() is StreamStart)
{
MoveNext();
}
else
{
throw new InvalidOperationException("Expected stream start parse event");
}
if (EvaluateCurrent() is DocumentStart)
{
MoveNext();
}
else
{
throw new InvalidOperationException("Expected document start parse event");
}
}
private ParsingEvent EvaluateCurrent()
{
if (m_current == null)
{
m_current = m_parser.Current;
if (m_current != null)
{
if (m_current is Scalar scalar)
{
// Verify not using achors
if (scalar.Anchor != null)
{
throw new InvalidOperationException($"Anchors are not currently supported. Remove the anchor '{scalar.Anchor}'");
}
}
else if (m_current is MappingStart mappingStart)
{
// Verify not using achors
if (mappingStart.Anchor != null)
{
throw new InvalidOperationException($"Anchors are not currently supported. Remove the anchor '{mappingStart.Anchor}'");
}
}
else if (m_current is SequenceStart sequenceStart)
{
// Verify not using achors
if (sequenceStart.Anchor != null)
{
throw new InvalidOperationException($"Anchors are not currently supported. Remove the anchor '{sequenceStart.Anchor}'");
}
}
else if (!(m_current is MappingEnd) &&
!(m_current is SequenceEnd) &&
!(m_current is DocumentStart) &&
!(m_current is DocumentEnd) &&
!(m_current is StreamStart) &&
!(m_current is StreamEnd))
{
throw new InvalidOperationException($"Unexpected parsing event type: {m_current.GetType().Name}");
}
}
}
return m_current;
}
private Boolean MoveNext()
{
m_current = null;
return m_parser.MoveNext();
}
private BooleanToken ParseBoolean(Scalar scalar)
{
if (MatchBoolean(scalar, out var token))
{
return token;
}
ThrowInvalidValue(scalar, c_booleanTag); // throws
return default;
}
private NumberToken ParseFloat(Scalar scalar)
{
if (MatchFloat(scalar, out var token))
{
return token;
}
ThrowInvalidValue(scalar, c_floatTag); // throws
return default;
}
private NumberToken ParseInteger(Scalar scalar)
{
if (MatchInteger(scalar, out var token))
{
return token;
}
ThrowInvalidValue(scalar, c_integerTag); // throws
return default;
}
private NullToken ParseNull(Scalar scalar)
{
if (MatchNull(scalar, out var token))
{
return token;
}
ThrowInvalidValue(scalar, c_nullTag); // throws
return default;
}
private Boolean MatchBoolean(
Scalar scalar,
out BooleanToken value)
{
// YAML 1.2 "core" schema https://yaml.org/spec/1.2/spec.html#id2804923
switch (scalar.Value ?? String.Empty)
{
case "true":
case "True":
case "TRUE":
value = new BooleanToken(m_fileId, scalar.Start.Line, scalar.Start.Column, true);
return true;
case "false":
case "False":
case "FALSE":
value = new BooleanToken(m_fileId, scalar.Start.Line, scalar.Start.Column, false);
return true;
}
value = default;
return false;
}
private Boolean MatchFloat(
Scalar scalar,
out NumberToken value)
{
// YAML 1.2 "core" schema https://yaml.org/spec/1.2/spec.html#id2804923
var str = scalar.Value;
if (!String.IsNullOrEmpty(str))
{
// Check for [-+]?(\.inf|\.Inf|\.INF)|\.nan|\.NaN|\.NAN
switch (str)
{
case ".inf":
case ".Inf":
case ".INF":
case "+.inf":
case "+.Inf":
case "+.INF":
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, Double.PositiveInfinity);
return true;
case "-.inf":
case "-.Inf":
case "-.INF":
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, Double.NegativeInfinity);
return true;
case ".nan":
case ".NaN":
case ".NAN":
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, Double.NaN);
return true;
}
// Otherwise check [-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?
// Skip leading sign
var index = str[0] == '-' || str[0] == '+' ? 1 : 0;
// Check for integer portion
var length = str.Length;
var hasInteger = false;
while (index < length && str[index] >= '0' && str[index] <= '9')
{
hasInteger = true;
index++;
}
// Check for decimal point
var hasDot = false;
if (index < length && str[index] == '.')
{
hasDot = true;
index++;
}
// Check for decimal portion
var hasDecimal = false;
while (index < length && str[index] >= '0' && str[index] <= '9')
{
hasDecimal = true;
index++;
}
// Check [-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)
if ((hasDot && hasDecimal) || hasInteger)
{
// Check for end
if (index == length)
{
// Try parse
if (Double.TryParse(str, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var doubleValue))
{
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, doubleValue);
return true;
}
// Otherwise exceeds range
else
{
ThrowInvalidValue(scalar, c_floatTag); // throws
}
}
// Check [eE][-+]?[0-9]
else if (index < length && (str[index] == 'e' || str[index] == 'E'))
{
index++;
// Skip sign
if (index < length && (str[index] == '-' || str[index] == '+'))
{
index++;
}
// Check for exponent
var hasExponent = false;
while (index < length && str[index] >= '0' && str[index] <= '9')
{
hasExponent = true;
index++;
}
// Check for end
if (hasExponent && index == length)
{
// Try parse
if (Double.TryParse(str, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var doubleValue))
{
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, (Double)doubleValue);
return true;
}
// Otherwise exceeds range
else
{
ThrowInvalidValue(scalar, c_floatTag); // throws
}
}
}
}
}
value = default;
return false;
}
private Boolean MatchInteger(
Scalar scalar,
out NumberToken value)
{
// YAML 1.2 "core" schema https://yaml.org/spec/1.2/spec.html#id2804923
var str = scalar.Value;
if (!String.IsNullOrEmpty(str))
{
// Check for [0-9]+
var firstChar = str[0];
if (firstChar >= '0' && firstChar <= '9' &&
str.Skip(1).All(x => x >= '0' && x <= '9'))
{
// Try parse
if (Double.TryParse(str, NumberStyles.None, CultureInfo.InvariantCulture, out var doubleValue))
{
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, doubleValue);
return true;
}
// Otherwise exceeds range
ThrowInvalidValue(scalar, c_integerTag); // throws
}
// Check for (-|+)[0-9]+
else if ((firstChar == '-' || firstChar == '+') &&
str.Length > 1 &&
str.Skip(1).All(x => x >= '0' && x <= '9'))
{
// Try parse
if (Double.TryParse(str, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var doubleValue))
{
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, doubleValue);
return true;
}
// Otherwise exceeds range
ThrowInvalidValue(scalar, c_integerTag); // throws
}
// Check for 0x[0-9a-fA-F]+
else if (firstChar == '0' &&
str.Length > 2 &&
str[1] == 'x' &&
str.Skip(2).All(x => (x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F')))
{
// Try parse
if (Int32.TryParse(str.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var integerValue))
{
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, integerValue);
return true;
}
// Otherwise exceeds range
ThrowInvalidValue(scalar, c_integerTag); // throws
}
// Check for 0o[0-9]+
else if (firstChar == '0' &&
str.Length > 2 &&
str[1] == 'o' &&
str.Skip(2).All(x => x >= '0' && x <= '7'))
{
// Try parse
var integerValue = default(Int32);
try
{
integerValue = Convert.ToInt32(str.Substring(2), 8);
}
// Otherwise exceeds range
catch (Exception)
{
ThrowInvalidValue(scalar, c_integerTag); // throws
}
value = new NumberToken(m_fileId, scalar.Start.Line, scalar.Start.Column, integerValue);
return true;
}
}
value = default;
return false;
}
private Boolean MatchNull(
Scalar scalar,
out NullToken value)
{
// YAML 1.2 "core" schema https://yaml.org/spec/1.2/spec.html#id2804923
switch (scalar.Value ?? String.Empty)
{
case "":
case "null":
case "Null":
case "NULL":
case "~":
value = new NullToken(m_fileId, scalar.Start.Line, scalar.Start.Column);
return true;
}
value = default;
return false;
}
private void ThrowInvalidValue(
Scalar scalar,
String tag)
{
throw new NotSupportedException($"The value '{scalar.Value}' on line {scalar.Start.Line} and column {scalar.Start.Column} is invalid for the type '{scalar.Tag}'");
}
private const String c_booleanTag = "tag:yaml.org,2002:bool";
private const String c_floatTag = "tag:yaml.org,2002:float";
private const String c_integerTag = "tag:yaml.org,2002:int";
private const String c_nullTag = "tag:yaml.org,2002:null";
private const String c_stringTag = "tag:yaml.org,2002:string";
private readonly Int32? m_fileId;
private readonly Parser m_parser;
private ParsingEvent m_current;
}
}

View File

@@ -1,73 +0,0 @@
using System;
using System.Globalization;
using System.IO;
using GitHub.DistributedTask.ObjectTemplating;
using YamlDotNet.Core.Events;
namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
{
/// <summary>
/// Converts a TemplateToken into YAML
/// </summary>
internal sealed class YamlObjectWriter : IObjectWriter
{
internal YamlObjectWriter(StringWriter writer)
{
m_emitter = new YamlDotNet.Core.Emitter(writer);
}
public void WriteString(String value)
{
m_emitter.Emit(new Scalar(value ?? String.Empty));
}
public void WriteBoolean(Boolean value)
{
m_emitter.Emit(new Scalar(value ? "true" : "false"));
}
public void WriteNumber(Double value)
{
m_emitter.Emit(new Scalar(value.ToString("G15", CultureInfo.InvariantCulture)));
}
public void WriteNull()
{
m_emitter.Emit(new Scalar("null"));
}
public void WriteSequenceStart()
{
m_emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Block));
}
public void WriteSequenceEnd()
{
m_emitter.Emit(new SequenceEnd());
}
public void WriteMappingStart()
{
m_emitter.Emit(new MappingStart());
}
public void WriteMappingEnd()
{
m_emitter.Emit(new MappingEnd());
}
public void WriteStart()
{
m_emitter.Emit(new StreamStart());
m_emitter.Emit(new DocumentStart());
}
public void WriteEnd()
{
m_emitter.Emit(new DocumentEnd(isImplicit: true));
m_emitter.Emit(new StreamEnd());
}
private readonly YamlDotNet.Core.IEmitter m_emitter;
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using GitHub.DistributedTask.WebApi;
using Newtonsoft.Json.Linq;
namespace GitHub.DistributedTask.Pipelines
{
@@ -12,18 +9,8 @@ namespace GitHub.DistributedTask.Pipelines
[EditorBrowsable(EditorBrowsableState.Never)]
public static class PipelineConstants
{
/// <summary>
/// The minimum agent version when performing an advanced checkout. This demand
/// is required when multiple checkout steps are used, when the checkout step
/// is not the first step, or when any repository is checked out other than self
/// or none.
/// </summary>
public static readonly String AdvancedCheckoutMinAgentVersion = "2.137.0";
public static readonly String AgentVersionDemandName = "Runner.Version";
public static readonly String AgentName = "Agent.Name";
/// <summary>
/// The default job cancel timeout in minutes.
/// </summary>
@@ -50,21 +37,11 @@ namespace GitHub.DistributedTask.Pipelines
/// </summary>
public static readonly Int32 MaxNodeNameLength = 100;
/// <summary>
/// The repository alias to use for dont-sync-sources.
/// </summary>
public static readonly String NoneAlias = "none";
/// <summary>
/// Alias for the self repository.
/// </summary>
public static readonly String SelfAlias = "self";
/// <summary>
/// Alias for the repository coming from designer build definition.
/// </summary>
public static readonly String DesignerRepo = "__designer_repo";
/// <summary>
/// Error code during graph validation.
/// </summary>
@@ -90,9 +67,6 @@ namespace GitHub.DistributedTask.Pipelines
/// </summary>
internal const String StartingPointNotFound = nameof(StartingPointNotFound);
internal const String CheckpointNodeInstanceNameClaimKey = "nodeInstanceName";
internal const String CheckpointIdClaimKey = "checkpointId";
public static class CheckoutTaskInputs
{
public static readonly String Repository = "repository";
@@ -120,20 +94,5 @@ namespace GitHub.DistributedTask.Pipelines
public static readonly String Resources = "resources";
public static readonly String All = "all";
}
public static class EnvironmentVariables
{
public static readonly String EnvironmentId = "Environment.Id";
public static readonly String EnvironmentName = "Environment.Name";
public static readonly String EnvironmentResourceId = "Environment.ResourceId";
public static readonly String EnvironmentResourceName = "Environment.ResourceName";
}
public static class ScriptStepInputs
{
public static readonly String Script = "script";
public static readonly String WorkingDirectory = "workingDirectory";
public static readonly String Shell = "shell";
}
}
}

View File

@@ -9,70 +9,9 @@ namespace GitHub.DistributedTask.Pipelines
public static class RepositoryPropertyNames
{
public static readonly String Id = "id";
public static readonly String Mappings = "mappings";
public static readonly String Name = "name";
public static readonly String Ref = "ref";
public static readonly String Type = "type";
public static readonly String Url = "url";
public static readonly String Version = "version";
public static readonly String VersionInfo = "versionInfo";
public static readonly String VersionSpec = "versionSpec";
public static readonly String Shelveset = "shelveset";
public static readonly String Project = "project";
public static readonly String Path = "path";
public static readonly String CheckoutOptions = "checkoutOptions";
public static readonly String DefaultBranch = "defaultBranch";
public static readonly String ExternalId = "externalId";
public static readonly String IsJustInTimeRepository = "isJustInTimeRepository";
}
[DataContract]
[EditorBrowsable(EditorBrowsableState.Never)]
public class VersionInfo
{
[DataMember(EmitDefaultValue = false)]
public String Author { get; set; }
[DataMember(EmitDefaultValue = false)]
public String Message { get; set; }
}
[DataContract]
[EditorBrowsable(EditorBrowsableState.Never)]
public class CheckoutOptions
{
[JsonConstructor]
public CheckoutOptions()
{ }
private CheckoutOptions(CheckoutOptions optionsToCopy)
{
this.Clean = optionsToCopy.Clean;
this.FetchDepth = optionsToCopy.FetchDepth;
this.Lfs = optionsToCopy.Lfs;
this.Submodules = optionsToCopy.Submodules;
this.PersistCredentials = optionsToCopy.PersistCredentials;
}
[DataMember(EmitDefaultValue = false)]
public String Clean{ get; set; }
[DataMember(EmitDefaultValue = false)]
public String FetchDepth{ get; set; }
[DataMember(EmitDefaultValue = false)]
public String Lfs { get; set; }
[DataMember(EmitDefaultValue = false)]
public String Submodules { get; set; }
[DataMember(EmitDefaultValue = false)]
public String PersistCredentials { get; set; }
public CheckoutOptions Clone()
{
return new CheckoutOptions(this);
}
}
/// <summary>

View File

@@ -4,12 +4,6 @@ namespace GitHub.DistributedTask.Pipelines
{
public static class RepositoryTypes
{
public static readonly String Bitbucket = nameof(Bitbucket);
public static readonly String ExternalGit = nameof(ExternalGit);
public static readonly String Git = nameof(Git);
public static readonly String GitHub = nameof(GitHub);
public static readonly String GitHubEnterprise = nameof(GitHubEnterprise);
public static readonly String Tfvc = nameof(Tfvc);
public static readonly String Svn = nameof(Svn);
}
}

View File

@@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
using GitHub.DistributedTask.Pipelines.ContextData;
namespace GitHub.DistributedTask.Pipelines
{
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class StrategyResult
{
public StrategyResult()
{
FailFast = true;
}
public Boolean FailFast { get; set; }
public int MaxParallel { get; set; }
public IList<StrategyConfiguration> Configurations { get; } = new List<StrategyConfiguration>();
}
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class StrategyConfiguration
{
public String DisplayName { get; set; }
public String Name { get; set; }
public IDictionary<String, PipelineContextData> ContextData { get; } = new Dictionary<String, PipelineContextData>(StringComparer.Ordinal);
}
}