Skip to content

Commit 3c685aa

Browse files
[release/8.0.1xx] Fix the parsing of ContainerImageTags to report invalid tags instead of silently swallowing them. (#38045)
Co-authored-by: Chet Husk <[email protected]>
1 parent a653461 commit 3c685aa

File tree

4 files changed

+76
-31
lines changed

4 files changed

+76
-31
lines changed

src/Containers/Microsoft.NET.Build.Containers/Tasks/ParseContainerProperties.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ public override bool Execute()
100100
Log.LogErrorWithCodeFromResources(nameof(Strings.InvalidTag), nameof(ContainerImageTag), ContainerImageTag);
101101
}
102102
}
103-
else if (ContainerImageTags.Length != 0 && TryValidateTags(ContainerImageTags, out var valids, out var invalids))
103+
else if (ContainerImageTags.Length != 0)
104104
{
105-
validTags = valids;
106-
if (invalids.Any())
105+
(validTags, var invalidTags) = TryValidateTags(ContainerImageTags);
106+
if (invalidTags.Any())
107107
{
108-
Log.LogErrorWithCodeFromResources(nameof(Strings.InvalidTags), nameof(ContainerImageTags), String.Join(",", invalids));
108+
Log.LogErrorWithCodeFromResources(nameof(Strings.InvalidTags), nameof(ContainerImageTags), String.Join(",", invalidTags));
109109
return !Log.HasLoggedErrors;
110110
}
111111
}
@@ -200,7 +200,7 @@ private void ValidateEnvironmentVariables()
200200
}
201201
}
202202

203-
private static bool TryValidateTags(string[] inputTags, out string[] validTags, out string[] invalidTags)
203+
private static (string[] validTags, string[] invalidTags) TryValidateTags(string[] inputTags)
204204
{
205205
var v = new List<string>();
206206
var i = new List<string>();
@@ -215,8 +215,6 @@ private static bool TryValidateTags(string[] inputTags, out string[] validTags,
215215
i.Add(tag);
216216
}
217217
}
218-
validTags = v.ToArray();
219-
invalidTags = i.ToArray();
220-
return invalidTags.Length == 0;
218+
return (v.ToArray(), i.ToArray());
221219
}
222220
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.NET.Build.Containers.IntegrationTests;
5+
6+
using Xunit;
7+
8+
/// <summary>
9+
/// Collection definition for tests that require MSBuild to be run.
10+
/// </summary>
11+
/// <remarks>
12+
/// This collection is used to ensure that tests that require MSBuild are run serially.
13+
/// The MSBuild engine only allows a single logical Build to run at once, so running tests
14+
/// that require MSBuild in parallel can cause tests to fail./
15+
/// </remarks>
16+
[CollectionDefinition(nameof(MSBuildCollection), DisableParallelization = true)]
17+
public class MSBuildCollection : ICollectionFixture<MSBuildCollection>
18+
{
19+
// This class has no code, and is never created. Its purpose is simply
20+
// to be the place to apply [CollectionDefinition] and all the
21+
// ICollectionFixture<> interfaces.
22+
}

src/Tests/Microsoft.NET.Build.Containers.IntegrationTests/ParseContainerPropertiesTests.cs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@
88

99
namespace Microsoft.NET.Build.Containers.Tasks.IntegrationTests;
1010

11-
[Collection("Docker tests")]
11+
[Collection(nameof(MSBuildCollection))]
1212
public class ParseContainerPropertiesTests
1313
{
14-
[DockerAvailableFact]
14+
[Fact]
1515
public void Baseline()
1616
{
17-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
17+
var (project, logs, d) = ProjectInitializer.InitProject(new()
18+
{
1819
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:7.0",
1920
[ContainerRegistry] = "localhost:5010",
2021
[ContainerRepository] = "dotnet/testimage",
2122
[ContainerImageTags] = "7.0;latest"
2223
});
2324
using var _ = d;
2425
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
25-
Assert.True(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
26+
Assert.True(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
2627

2728
Assert.Equal("mcr.microsoft.com", instance.GetPropertyValue(ContainerBaseRegistry));
2829
Assert.Equal("dotnet/runtime", instance.GetPropertyValue(ContainerBaseName));
@@ -33,58 +34,62 @@ public void Baseline()
3334
instance.GetItems("ProjectCapability").Select(i => i.EvaluatedInclude).ToArray().Should().BeEquivalentTo(new[] { "NetSdkOCIImageBuild" });
3435
}
3536

36-
[DockerAvailableFact]
37+
[Fact]
3738
public void SpacesGetReplacedWithDashes()
3839
{
39-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
40+
var (project, logs, d) = ProjectInitializer.InitProject(new()
41+
{
4042
[ContainerBaseImage] = "mcr.microsoft.com/dotnet runtime:7.0",
4143
[ContainerRegistry] = "localhost:5010"
4244
});
4345
using var _ = d;
4446
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
45-
Assert.True(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
47+
Assert.True(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
4648

47-
Assert.Equal("mcr.microsoft.com",instance.GetPropertyValue(ContainerBaseRegistry));
49+
Assert.Equal("mcr.microsoft.com", instance.GetPropertyValue(ContainerBaseRegistry));
4850
Assert.Equal("dotnet-runtime", instance.GetPropertyValue(ContainerBaseName));
4951
Assert.Equal("7.0", instance.GetPropertyValue(ContainerBaseTag));
5052
}
5153

52-
[DockerAvailableFact]
54+
[Fact]
5355
public void RegexCatchesInvalidContainerNames()
5456
{
55-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
57+
var (project, logs, d) = ProjectInitializer.InitProject(new()
58+
{
5659
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:7.0",
5760
[ContainerRegistry] = "localhost:5010",
5861
[ContainerRepository] = "dotnet testimage",
5962
[ContainerImageTag] = "5.0"
6063
});
6164
using var _ = d;
6265
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
63-
Assert.True(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
66+
Assert.True(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
6467
Assert.Contains(logs.Messages, m => m.Message?.Contains("'dotnet testimage' was not a valid container image name, it was normalized to 'dotnet-testimage'") == true);
6568
}
6669

67-
[DockerAvailableFact]
70+
[Fact]
6871
public void RegexCatchesInvalidContainerTags()
6972
{
70-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
73+
var (project, logs, d) = ProjectInitializer.InitProject(new()
74+
{
7175
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:7.0",
7276
[ContainerRegistry] = "localhost:5010",
7377
[ContainerRepository] = "dotnet/testimage",
7478
[ContainerImageTag] = "5 0"
7579
});
7680
using var _ = d;
7781
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
78-
Assert.False(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
82+
Assert.False(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
7983

8084
Assert.True(logs.Errors.Count > 0);
8185
Assert.Equal(logs.Errors[0].Code, ErrorCodes.CONTAINER2007);
8286
}
8387

84-
[DockerAvailableFact]
88+
[Fact]
8589
public void CanOnlySupplyOneOfTagAndTags()
8690
{
87-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
91+
var (project, logs, d) = ProjectInitializer.InitProject(new()
92+
{
8893
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:7.0",
8994
[ContainerRegistry] = "localhost:5010",
9095
[ContainerRepository] = "dotnet/testimage",
@@ -93,41 +98,60 @@ public void CanOnlySupplyOneOfTagAndTags()
9398
});
9499
using var _ = d;
95100
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
96-
Assert.False(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
101+
Assert.False(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
97102

98103
Assert.True(logs.Errors.Count > 0);
99104
Assert.Equal(logs.Errors[0].Code, ErrorCodes.CONTAINER2008);
100105
}
101106

102-
[DockerAvailableFact]
107+
[Fact]
108+
public void InvalidTagsThrowError()
109+
{
110+
var (project, logs, d) = ProjectInitializer.InitProject(new()
111+
{
112+
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/aspnet:8.0",
113+
[ContainerRepository] = "dotnet/testimage",
114+
[ContainerImageTags] = "'latest;oldest'"
115+
});
116+
using var _ = d;
117+
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
118+
Assert.False(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
119+
120+
Assert.True(logs.Errors.Count > 0);
121+
Assert.Equal(logs.Errors[0].Code, ErrorCodes.CONTAINER2010);
122+
}
123+
124+
[Fact]
103125
public void FailsOnCompletelyInvalidRepositoryNames()
104126
{
105-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
127+
var (project, logs, d) = ProjectInitializer.InitProject(new()
128+
{
106129
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:7.0",
107130
[ContainerRegistry] = "localhost:5010",
108131
[ContainerImageName] = "㓳㓴㓵㓶㓷㓹㓺㓻",
109132
[ContainerImageTag] = "5.0"
110133
});
111134
using var _ = d;
112135
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
113-
Assert.False(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
136+
Assert.False(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
114137

115138
Assert.True(logs.Errors.Count > 0);
116139
Assert.Equal(logs.Errors[0].Code, ErrorCodes.CONTAINER2005);
117140
}
118141

119-
[DockerAvailableFact]
142+
[Fact]
120143
public void FailsWhenFirstCharIsAUnicodeLetterButNonLatin()
121144
{
122-
var (project, logs, d) = ProjectInitializer.InitProject(new () {
145+
var (project, logs, d) = ProjectInitializer.InitProject(new()
146+
{
123147
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:7.0",
124148
[ContainerRegistry] = "localhost:5010",
125149
[ContainerImageName] = "㓳but-otherwise-valid",
126150
[ContainerImageTag] = "5.0"
127151
});
128152
using var _ = d;
129153
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
130-
Assert.False(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
154+
Assert.False(instance.Build(new[] { ComputeContainerConfig }, new[] { logs }, null, out var outputs));
131155

132156
Assert.True(logs.Errors.Count > 0);
133157
Assert.Equal(logs.Errors[0].Code, ErrorCodes.CONTAINER2005);

src/Tests/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Microsoft.NET.Build.Containers.Targets.IntegrationTests;
99

10+
[Collection(nameof(MSBuildCollection))]
1011
public class TargetsTests
1112
{
1213
[InlineData("SelfContained", true, "/app/foo.exe")]

0 commit comments

Comments
 (0)