Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 372fc96

Browse files
Fix resources.repositories.*.ref can be an expression (#650)
1 parent 1e73494 commit 372fc96

15 files changed

Lines changed: 154 additions & 70 deletions

File tree

src/ExpandAzurePipelines/App.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@
9999
TraceWriter = new GitHub.DistributedTask.ObjectTemplating.EmptyTraceWriter(),
100100
Flags = GitHub.DistributedTask.Expressions2.ExpressionFlags.DTExpressionsV1 | GitHub.DistributedTask.Expressions2.ExpressionFlags.ExtendedDirectives | GitHub.DistributedTask.Expressions2.ExpressionFlags.AllowAnyForInsert
101101
};
102-
var template = await AzureDevops.ReadTemplate(context, currentFileName);
103-
var pipeline = await new Runner.Server.Azure.Devops.Pipeline().Parse(context.ChildContext(template, currentFileName), template);
102+
var (template, childContext) = await AzureDevops.ReadTemplate(context, currentFileName);
103+
var pipeline = await new Runner.Server.Azure.Devops.Pipeline().Parse(childContext, template);
104104
var newcontent = pipeline.ToYaml();
105105
await _editor2.SetValue(newcontent);
106106
} catch(Exception ex) {

src/Runner.Client/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -988,8 +988,8 @@ public static async Task<string> ExpandCurrentPipeline(Parameters handle, string
988988
cparameters[varname] = AzurePipelinesUtils.ConvertStringToTemplateToken(varval);
989989
}
990990
}
991-
var template = await AzureDevops.ReadTemplate(context, currentFileName, cparameters);
992-
var pipeline = await new Runner.Server.Azure.Devops.Pipeline().Parse(context.ChildContext(template, currentFileName), template);
991+
var (template, childContext) = await AzureDevops.ReadTemplate(context, currentFileName, cparameters);
992+
var pipeline = await new Pipeline().Parse(childContext, template);
993993
return pipeline.ToYaml();
994994
}
995995
}

src/Runner.Server/Controllers/MessageController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,7 +2574,6 @@ private HookResponse AzureDevopsMain(string fileRelativePath, string content, st
25742574
workflowParameters[kv.Key.ToString()] = kv.Value;
25752575
}
25762576
}
2577-
var evaluatedRoot = Runner.Server.Azure.Devops.AzureDevops.ReadTemplate(context, fileRelativePath, workflowParameters).GetAwaiter().GetResult();
25782577
bool forceTaskCacheUpdate = workflowContext.HasFeature("system.runner.server.forceTaskCacheUpdate");
25792578
bool skipTaskCacheUpdate = workflowContext.HasFeature("system.runner.server.skipTaskCacheUpdate");
25802579
bool taskCacheUpdate = workflowContext.HasFeature("system.runner.server.taskCacheUpdate");
@@ -2699,7 +2698,8 @@ private HookResponse AzureDevopsMain(string fileRelativePath, string content, st
26992698
return null;
27002699
} };
27012700

2702-
var pipeline = new Azure.Devops.Pipeline().Parse(context.ChildContext(evaluatedRoot, fileRelativePath), evaluatedRoot).GetAwaiter().GetResult();
2701+
var (evaluatedRoot, childContext) = Azure.Devops.AzureDevops.ReadTemplate(context, fileRelativePath, workflowParameters).GetAwaiter().GetResult();
2702+
var pipeline = new Azure.Devops.Pipeline().Parse(childContext, evaluatedRoot).GetAwaiter().GetResult();
27032703

27042704
var localJobCompletedEvents = new LocalJobCompletedEvents();
27052705
Action<JobCompletedEvent> jobCompleted = e => {

src/Sdk.Tests/AzurePipelines/Util/LocalFileProvider.cs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace Runner.Server.Azure.Devops
22
{
3-
public class LocalFileProvider : IFileProvider // TODO: Fix IFileProvider namespacing
3+
public class LocalFileProvider : IFileProvider
44
{
55
private IDictionary<string, string> repos = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
66

@@ -22,18 +22,9 @@ public void AddRepo(string repositoryAndRef, string folderPath)
2222
{
2323
folderPath = $"{folderPath}{Path.DirectorySeparatorChar}";
2424
}
25-
string repoName = repositoryAndRef.Split("@")[0];
26-
repos[repoName] = folderPath;
25+
repos[repositoryAndRef] = folderPath;
2726
}
2827

29-
public void AddRepo(string projectName, string repositoryName, string folderPath)
30-
{
31-
var key = $"{projectName}/{repositoryName}".ToUpper();
32-
AddRepo(key, folderPath);
33-
}
34-
35-
36-
3728
private string ResolveFilePath(string repositoryAndRef, string path)
3829
{
3930
var cwd = GetRepoLocalFolder(repositoryAndRef);
@@ -46,8 +37,7 @@ private string ResolveFilePath(string repositoryAndRef, string path)
4637

4738
private string GetRepoLocalFolder(string repositoryAndRef)
4839
{
49-
var repoName = (repositoryAndRef ?? "self").Split("@")[0];
50-
return repos[repoName];
40+
return repos[repositoryAndRef ?? "self"];
5141
}
5242
#endregion
5343
}

src/Sdk.Tests/AzurePipelines/Util/TestContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ public async Task<Pipeline> EvaluateAsync(string fileRelativePath)
6262
{
6363
Context context = GetContext();
6464

65-
var evaluatedRoot = await AzureDevops.ReadTemplate(context, fileRelativePath, null);
65+
var (evaluatedRoot, childContext) = await AzureDevops.ReadTemplate(context, fileRelativePath, null);
6666

67-
var pline = await new Pipeline().Parse(context.ChildContext(evaluatedRoot, fileRelativePath), evaluatedRoot);
67+
var pline = await new Pipeline().Parse(childContext, evaluatedRoot);
6868
pline.CheckPipelineForRuntimeFailure();
6969
return pline;
7070
}

src/Sdk/AzurePipelines/AzureDevops.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ public static async Task ParseStep(Runner.Server.Azure.Devops.Context context, I
317317
throw new TemplateValidationException(new [] {new TemplateValidationError($"{GitHub.DistributedTask.ObjectTemplating.Tokens.TemplateTokenExtensions.GetAssertPrefix(mstep[2].Key)}Unexpected yaml keys {(mstep[2].Key as StringToken)?.Value} after template reference")});
318318
}
319319
try {
320-
var file = await ReadTemplate(context, primaryValue, unparsedTokens.Count == 1 ? unparsedTokens[0].Value.AssertMapping("param").ToDictionary(kv => kv.Key.AssertString("").Value, kv => kv.Value) : null, "step-template-root");
321-
await ParseSteps(context.ChildContext(file, primaryValue), steps, (from e in file where e.Key.AssertString("").Value == "steps" select e.Value).First().AssertSequence(""));
320+
var (file, childContext) = await ReadTemplate(context, primaryValue, unparsedTokens.Count == 1 ? unparsedTokens[0].Value.AssertMapping("param").ToDictionary(kv => kv.Key.AssertString("").Value, kv => kv.Value) : null, "step-template-root");
321+
await ParseSteps(childContext, steps, (from e in file where e.Key.AssertString("").Value == "steps" select e.Value).First().AssertSequence(""));
322322
} catch(TemplateValidationException ex) {
323323
throw new TemplateValidationException(ex.Errors.Prepend(new TemplateValidationError($"{GitHub.DistributedTask.ObjectTemplating.Tokens.TemplateTokenExtensions.GetAssertPrefix(mstep[0].Key)}Found Errors inside Template Reference: {ex.Message}")));
324324
}
@@ -1307,15 +1307,13 @@ private static void CheckConditionalExpressions(TemplateContext m_context, Templ
13071307
}
13081308
}
13091309

1310-
public static async Task<MappingToken> ReadTemplate(Runner.Server.Azure.Devops.Context context, string filenameAndRef, Dictionary<string, TemplateToken> cparameters = null, string schemaName = null)
1310+
public static async Task<(MappingToken, Context)> ReadTemplate(Runner.Server.Azure.Devops.Context context, string filenameAndRef, Dictionary<string, TemplateToken> cparameters = null, string schemaName = null)
13111311
{
13121312
var variables = context.VariablesProvider?.GetVariablesForEnvironment("");
13131313
var (errorTemplateFileName, token) = await ParseTemplate(context, filenameAndRef, schemaName);
13141314

13151315
var pipelineroot = token.AssertMapping("root");
13161316

1317-
var childContext = context.ChildContext(pipelineroot, filenameAndRef);
1318-
13191317
TemplateToken parameters = null;
13201318
TemplateToken rawStaticVariables = null;
13211319
foreach (var kv in pipelineroot)
@@ -1467,6 +1465,12 @@ public static async Task<MappingToken> ReadTemplate(Runner.Server.Azure.Devops.C
14671465
}
14681466

14691467
templateContext = CreateTemplateContext(context.TraceWriter ?? new EmptyTraceWriter(), templateContext.GetFileTable().ToArray(), context.Flags, contextData);
1468+
// bug pipelineroot.resources.repositories.*.ref can be an expression
1469+
// can variables be referenced there?
1470+
// 2026-02-11: Yes, but then the value is null/'' if you attempt to reference templates using it
1471+
var resources = (pipelineroot as IReadOnlyObject)["resources"] as MappingToken;
1472+
resources = resources != null ? await TemplateEvaluator.EvaluateAsync(templateContext, "resources", resources, 0, fileId) as MappingToken : null;
1473+
Context childContext = context.ChildContextWithResource(resources, filenameAndRef);
14701474
templateContext.EvaluateVariable = async (tcontext, mapping, vars) => {
14711475
string template = null;
14721476
TemplateToken parameters = null;
@@ -1507,7 +1511,7 @@ public static async Task<MappingToken> ReadTemplate(Runner.Server.Azure.Devops.C
15071511
else if (template != null)
15081512
{
15091513
var evalp = parameters;
1510-
var file = await ReadTemplate(childContext, template, evalp != null ? evalp.AssertMapping("param").ToDictionary(kv => kv.Key.AssertString("").Value, kv => kv.Value) : null, "variable-template-root");
1514+
var (file, schildContext) = await ReadTemplate(childContext, template, evalp != null ? evalp.AssertMapping("param").ToDictionary(kv => kv.Key.AssertString("").Value, kv => kv.Value) : null, "variable-template-root");
15111515
IDictionary<string, VariableValue> rvars = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
15121516
var vartkn = (from e in file where e.Key.AssertString("").Value == "variables" select e.Value).First();
15131517
ParseVariables(rvars, vartkn);
@@ -1530,7 +1534,7 @@ public static async Task<MappingToken> ReadTemplate(Runner.Server.Azure.Devops.C
15301534
var evaluatedResult = await TemplateEvaluator.EvaluateAsync(templateContext, schemaName ?? "pipeline-root", pipelineroot, 0, fileId);
15311535
templateContext.Errors.Check();
15321536
context.TraceWriter?.Verbose("{0}", evaluatedResult.ToContextData().ToJToken().ToString());
1533-
return evaluatedResult.AssertMapping("root");
1537+
return (evaluatedResult.AssertMapping("root"), childContext);
15341538
}
15351539

15361540
public static IEnumerable<TemplateToken> NormalizeVariableDefinition(TemplateToken vartkn)

src/Sdk/AzurePipelines/Context.cs

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using GitHub.DistributedTask.Expressions2;
2+
using GitHub.DistributedTask.Expressions2.Sdk;
23
using GitHub.DistributedTask.ObjectTemplating;
34
using GitHub.DistributedTask.ObjectTemplating.Tokens;
45
using System;
@@ -38,7 +39,12 @@ public Context Clone() {
3839
return MemberwiseClone() as Context;
3940
}
4041

41-
public Context ChildContext(MappingToken template, string path = null) {
42+
public Context ChildContext(MappingToken template, string path = null)
43+
{
44+
return ChildContextWithResource((template as IReadOnlyObject)["resources"] as MappingToken, path);
45+
}
46+
47+
public Context ChildContextWithResource(MappingToken resources, string path) {
4248
if(Repositories == null) {
4349
Repositories = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
4450
}
@@ -47,37 +53,33 @@ public Context ChildContext(MappingToken template, string path = null) {
4753
childContext.AutoCompleteMatches = null;
4854
childContext.Column = 0;
4955
childContext.Row = 0;
50-
foreach(var kv in template) {
51-
switch(kv.Key.AssertString("key").Value) {
52-
case "resources":
53-
foreach(var resource in kv.Value.AssertMapping("resources")) {
54-
switch(resource.Key.AssertString("").Value) {
55-
case "repositories":
56-
// Use a global dictionary, since resources needs to be resolved for the localcheckout step
57-
// childContext.Repositories = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
58-
foreach(var rawresource in resource.Value.AssertSequence("cres")) {
59-
string alias = null;
60-
string name = null;
61-
string @ref = "main";
62-
foreach(var rkv in rawresource.AssertMapping("")) {
63-
switch(rkv.Key.AssertString("").Value) {
64-
case "repository":
65-
alias = rkv.Value.AssertLiteralString("resources.*.repository");
66-
break;
67-
case "name":
68-
name = rkv.Value.AssertLiteralString("resources.*.name");
69-
break;
70-
case "ref":
71-
@ref = rkv.Value.AssertLiteralString("resources.*.ref");
72-
break;
73-
}
74-
}
75-
childContext.Repositories[alias] = $"{name}@{@ref}";
56+
if(resources != null) {
57+
foreach(var resource in resources) {
58+
switch(resource.Key.AssertString("").Value) {
59+
case "repositories":
60+
// Use a global dictionary, since resources needs to be resolved for the localcheckout step
61+
// childContext.Repositories = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
62+
foreach(var rawresource in resource.Value.AssertSequence("cres")) {
63+
string alias = null;
64+
string name = null;
65+
string @ref = "main";
66+
foreach(var rkv in rawresource.AssertMapping("")) {
67+
switch(rkv.Key.AssertString("").Value) {
68+
case "repository":
69+
alias = rkv.Value.AssertLiteralString("resources.*.repository");
70+
break;
71+
case "name":
72+
name = rkv.Value.AssertLiteralString("resources.*.name");
73+
break;
74+
case "ref":
75+
@ref = rkv.Value.AssertLiteralString("resources.*.ref");
76+
break;
7677
}
77-
break;
78-
}
79-
}
80-
break;
78+
}
79+
childContext.Repositories[alias] = $"{name}@{@ref}";
80+
}
81+
break;
82+
}
8183
}
8284
}
8385
if(path != null) {

src/Sdk/AzurePipelines/Job.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,15 @@ public static async Task ParseJobs(Context context, List<Job> jobs, SequenceToke
238238
continue;
239239
}
240240
MappingToken file;
241+
Context childContext;
241242
try {
242243
try {
243-
file = await AzureDevops.ReadTemplate(context, path, mstep.Count == 2 ? mstep[1].Value.AssertMapping("param").ToDictionary(kv => kv.Key.AssertString("").Value, kv => kv.Value) : null, "job-template-root");
244+
(file, childContext) = await AzureDevops.ReadTemplate(context, path, mstep.Count == 2 ? mstep[1].Value.AssertMapping("param").ToDictionary(kv => kv.Key.AssertString("").Value, kv => kv.Value) : null, "job-template-root");
244245
} catch(Exception ex) when (!(ex is TemplateValidationException)) {
245246
errors.Add(new TemplateValidationError($"{GitHub.DistributedTask.ObjectTemplating.Tokens.TemplateTokenExtensions.GetAssertPrefix(mstep[0].Key)}{ex.Message}"));
246247
continue;
247248
}
248-
await ParseJobs(context.ChildContext(file, path), jobs, (from e in file where e.Key.AssertString("").Value == "jobs" select e.Value).First().AssertSequence(""));
249+
await ParseJobs(childContext, jobs, (from e in file where e.Key.AssertString("").Value == "jobs" select e.Value).First().AssertSequence(""));
249250
} catch(TemplateValidationException ex) {
250251
throw new TemplateValidationException(ex.Errors.Prepend(new TemplateValidationError($"{GitHub.DistributedTask.ObjectTemplating.Tokens.TemplateTokenExtensions.GetAssertPrefix(mstep[0].Key)}Found Errors inside Template Reference: {ex.Message}")));
251252
}

src/Sdk/AzurePipelines/Pipeline.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ public async Task<Pipeline> Parse(Context context, TemplateToken source) {
7070
}
7171
}
7272
try {
73-
var templ = await AzureDevops.ReadTemplate(context, template, parameters, "extend-template-root");
74-
parent = await new Pipeline().Parse(context.ChildContext(templ, template), templ);
73+
var (templ, childContext) = await AzureDevops.ReadTemplate(context, template, parameters, "extend-template-root");
74+
parent = await new Pipeline().Parse(childContext, templ);
7575
} catch(TemplateValidationException ex) {
7676
throw new TemplateValidationException(ex.Errors.Prepend(new TemplateValidationError($"{GitHub.DistributedTask.ObjectTemplating.Tokens.TemplateTokenExtensions.GetAssertPrefix(ext)}Found Errors inside Template Reference: {ex.Message}")));
7777
}

0 commit comments

Comments
 (0)