Skip to content

Commit

Permalink
azp: check undefined parameters and report error (#260)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherHX authored Nov 3, 2023
1 parent 4195f5c commit 4deb0bf
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/Sdk/AzurePipelines/AzureDevops.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,15 @@ public static async Task<MappingToken> ReadTemplate(Runner.Server.Azure.Devops.C

templateContext.Errors.Check();

var dict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach(var param in parametersData) {
dict[param.Key] = param.Value;
}

if(rawStaticVariables != null) {
// See "testworkflows/azpipelines/expressions-docs/Conditionally assign a variable.yml"
templateContext = AzureDevops.CreateTemplateContext(context.TraceWriter ?? new EmptyTraceWriter(), templateContext.GetFileTable().ToArray(), context.Flags, contextData);
templateContext.ExpressionValues["parameters"] = new ParametersContextData(dict, templateContext.Errors);
rawStaticVariables = TemplateEvaluator.Evaluate(templateContext, "workflow-value", rawStaticVariables, 0, fileId);
templateContext.Errors.Check();

Expand All @@ -606,6 +612,7 @@ public static async Task<MappingToken> ReadTemplate(Runner.Server.Azure.Devops.C
}

templateContext = AzureDevops.CreateTemplateContext(context.TraceWriter ?? new EmptyTraceWriter(), templateContext.GetFileTable().ToArray(), context.Flags, contextData);
templateContext.ExpressionValues["parameters"] = new ParametersContextData(dict, templateContext.Errors);

var evaluatedResult = TemplateEvaluator.Evaluate(templateContext, schemaName ?? "pipeline-root", pipelineroot, 0, fileId);
templateContext.Errors.Check();
Expand Down
46 changes: 46 additions & 0 deletions src/Sdk/AzurePipelines/ParametersContextData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Collections;
using System.Collections.Generic;
using GitHub.DistributedTask.Expressions2.Sdk;
using GitHub.DistributedTask.ObjectTemplating;

namespace Runner.Server.Azure.Devops
{
class ParametersContextData : IReadOnlyObject
{
private Dictionary<string, object> data;
private TemplateValidationErrors errors;
public ParametersContextData(Dictionary<string, object> data, TemplateValidationErrors errors)
{
this.data = data;
this.errors = errors;
}

public object this[string key] => data[key];

public int Count => data.Count;

public IEnumerable<string> Keys => data.Keys;

public IEnumerable<object> Values => data.Values;

public bool ContainsKey(string key)
{
return data.ContainsKey(key);
}

public IEnumerator GetEnumerator()
{
return data.GetEnumerator();
}

public bool TryGetValue(string key, out object value)
{
if(!data.TryGetValue(key, out value)) {
errors.Add($"Unexpected parameter reference 'parameters.{key}'");
return false;
}
return true;
}
}

}
2 changes: 1 addition & 1 deletion src/Sdk/DTExpressions2/Expressions2/ExpressionConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static ExpressionConstants()
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.ToJson>("converttojson", 1, 1);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.EndsWith>("endsWith", 2, 2);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.Equal>("eq", 2, 2);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.Legacy.Format>("format", 2, Int32.MaxValue);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.Legacy.Format>("format", 1, Int32.MaxValue);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.GreaterThanOrEqual>("ge", 2, 2);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.GreaterThan>("gt", 2, 2);
AddAzureFunction<GitHub.DistributedTask.Expressions2.Sdk.Functions.v1.In>("in", 1, Int32.MaxValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using GitHub.DistributedTask.Expressions2;
using GitHub.DistributedTask.Expressions2.Sdk;
using Index = GitHub.DistributedTask.Expressions2.Sdk.Operators.Index;

namespace GitHub.DistributedTask.ObjectTemplating.Tokens
{
Expand Down Expand Up @@ -252,6 +253,29 @@ public static bool CheckHasRequiredContext(
return true;
}

public static IEnumerable<string> CheckUnknownParameters(
this TemplateToken token,
string context,
string[] names,
ExpressionFlags flags = ExpressionFlags.None)
{
var expressionTokens = token.Traverse()
.OfType<BasicExpressionToken>()
.ToArray();
var parser = new ExpressionParser() { Flags = flags };
foreach (var expressionToken in expressionTokens)
{
var tree = parser.ValidateSyntax(expressionToken.Expression, null);
foreach (var node in tree.Traverse())
{
if (node is Index indexValue && indexValue.Parameters[0] is NamedValue namedValue && string.Equals(namedValue.Name, context, StringComparison.OrdinalIgnoreCase) && indexValue.Parameters[1] is Literal literal && literal.Value is String literalString && names.All(name => !string.Equals(literalString, name, StringComparison.OrdinalIgnoreCase)))
{
yield return literalString;
}
}
}
}

/// <summary>
/// Returns all tokens (depth first)
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# ExpectedException: TemplateValidationException
# ExpectedErrorMessage: test6

parameters:
- name: no
type: number
default: 0
steps:
- script: echo ${{ parameters[format('{0}', 'test6')] }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
- name: no
type: number
default: 2
steps:
- script: echo ${{ coalesce('test', parameters.y) }}

0 comments on commit 4deb0bf

Please sign in to comment.