Skip to content

Commit c62981d

Browse files
committed
Add tests for implicit ASP.NET versions, and fix behavior
1 parent 742f28e commit c62981d

File tree

5 files changed

+253
-25
lines changed

5 files changed

+253
-25
lines changed

src/Tasks/Microsoft.NET.Build.Tasks/ApplyImplicitVersions.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
namespace Microsoft.NET.Build.Tasks
88
{
9-
10-
// TODO: Provide way to opt out of warning when Version is specified (possibly with the DisableImplicitFrameworkReferences property)
11-
// TODO: Add behavior (and test) for duplicate PackageReferences
129
public sealed class ApplyImplicitVersions : TaskBase
1310
{
1411
public string TargetFrameworkVersion { get; set; }

src/Tasks/Microsoft.NET.Build.Tasks/CheckForImplicitPackageReferenceOverrides.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ namespace Microsoft.NET.Build.Tasks
99
{
1010
public class CheckForImplicitPackageReferenceOverrides : TaskBase
1111
{
12-
const string MetadataKeyForItemsToRemove = "IsImplicitlyDefined";
13-
1412
[Required]
1513
public ITaskItem [] PackageReferenceItems { get; set; }
1614

@@ -20,21 +18,44 @@ public class CheckForImplicitPackageReferenceOverrides : TaskBase
2018
[Output]
2119
public ITaskItem[] ItemsToRemove { get; set; }
2220

21+
[Output]
22+
public ITaskItem[] ItemsToAdd { get; set; }
23+
2324
protected override void ExecuteCore()
2425
{
2526
var duplicateItems = PackageReferenceItems.GroupBy(i => i.ItemSpec, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1);
26-
var duplicateItemsToRemove = duplicateItems.SelectMany(g => g.Where(
27-
item => item.GetMetadata(MetadataKeyForItemsToRemove).Equals("true", StringComparison.OrdinalIgnoreCase)));
2827

29-
ItemsToRemove = duplicateItemsToRemove.ToArray();
30-
31-
foreach (var itemToRemove in ItemsToRemove)
28+
if (duplicateItems.Any())
3229
{
33-
string message = string.Format(CultureInfo.CurrentCulture, Strings.PackageReferenceOverrideWarning,
34-
itemToRemove.ItemSpec,
35-
MoreInformationLink);
36-
37-
Log.LogWarning(message);
30+
List<ITaskItem> itemsToRemove = new List<ITaskItem>();
31+
List<ITaskItem> itemsToAdd = new List<ITaskItem>();
32+
foreach (var duplicateItemGroup in duplicateItems)
33+
{
34+
foreach (var item in duplicateItemGroup)
35+
{
36+
if (item.GetMetadata(MetadataKeys.IsImplicitlyDefined).Equals("true", StringComparison.OrdinalIgnoreCase))
37+
{
38+
itemsToRemove.Add(item);
39+
string message = string.Format(CultureInfo.CurrentCulture, Strings.PackageReferenceOverrideWarning,
40+
item.ItemSpec,
41+
MoreInformationLink);
42+
43+
Log.LogWarning(message);
44+
}
45+
else
46+
{
47+
// For the explicit items, we want to add metadata to them so that the ApplyImplicitVersions task
48+
// won't generate another error. The easiest way to do this is to add them both to a list of
49+
// items to remove, and then a list of items which gets added back.
50+
itemsToRemove.Add(item);
51+
item.SetMetadata(MetadataKeys.AllowExplicitVersion, "true");
52+
itemsToAdd.Add(item);
53+
}
54+
}
55+
}
56+
57+
ItemsToRemove = itemsToRemove.ToArray();
58+
ItemsToAdd = itemsToAdd.ToArray();
3859
}
3960
}
4061
}

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,14 @@ Copyright (c) .NET Foundation. All rights reserved.
198198
PackageReferenceItems="@(PackageReference)"
199199
MoreInformationLink="$(ImplicitPackageReferenceInformationLink)">
200200
<Output TaskParameter="ItemsToRemove" ItemName="_PackageReferenceToRemove" />
201+
<Output TaskParameter="ItemsToAdd" ItemName="_PackageReferenceToAdd" />
201202
</CheckForImplicitPackageReferenceOverrides>
202203

203204
<ItemGroup>
204-
<!-- Note that the condition here is important, otherwise the Remove will operate based just on item identity and remove all items
205-
that had duplicates, instead of leaving the ones without IsImplicitlyDefined set to true. -->
206-
<PackageReference Remove="@(_PackageReferenceToRemove)" Condition="'%(PackageReference.IsImplicitlyDefined)' == 'true' "/>
207-
208-
<!-- If we've already warned that an implicit PackageReference was overridden, don't also warn that the version was explicitly
209-
specified -->
210-
<PackageReference Update="@(_PackageReferenceToRemove)" AllowExplicitVersion="true"/>
205+
<!-- Remove and add the PackageReference items according to the output from the task -->
206+
<PackageReference Remove="@(_PackageReferenceToRemove)" />
207+
208+
<PackageReference Include="@(_PackageReferenceToAdd)" />
211209
</ItemGroup>
212210

213211
<!-- If any implicit package references were overridden, then don't check that RuntimeFrameworkVersion matches the package version -->
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using FluentAssertions;
7+
using Microsoft.NET.TestFramework;
8+
using Microsoft.NET.TestFramework.Assertions;
9+
using Microsoft.NET.TestFramework.Commands;
10+
using Microsoft.NET.TestFramework.ProjectConstruction;
11+
using NuGet.Common;
12+
using NuGet.Frameworks;
13+
using NuGet.ProjectModel;
14+
using NuGet.Versioning;
15+
using Xunit;
16+
using Xunit.Abstractions;
17+
18+
namespace Microsoft.NET.Build.Tests
19+
{
20+
public class ImplicitAspNetVersions : SdkTest
21+
{
22+
public ImplicitAspNetVersions(ITestOutputHelper log) : base(log)
23+
{
24+
}
25+
26+
[Theory]
27+
[InlineData("Microsoft.AspNetCore.App")]
28+
[InlineData("Microsoft.AspNetCore.All")]
29+
public void AspNetCoreVersionIsSetImplicitly(string aspnetPackageName)
30+
{
31+
var testProject = new TestProject()
32+
{
33+
Name = "AspNetImplicitVersion",
34+
TargetFrameworks = "netcoreapp2.1",
35+
IsSdkProject = true,
36+
IsExe = true
37+
};
38+
39+
// Add versionless PackageReference
40+
testProject.PackageReferences.Add(new TestPackageReference(aspnetPackageName, null));
41+
42+
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: aspnetPackageName)
43+
.Restore(Log, testProject.Name);
44+
45+
var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
46+
47+
buildCommand
48+
.Execute()
49+
.Should()
50+
.Pass();
51+
52+
var aspnetVersion = GetLibraryVersion(testProject, buildCommand, aspnetPackageName);
53+
54+
// Version of AspNetCore packages is 2.1.1 because 2.1.0 packages had exact version constraints, which was broken
55+
aspnetVersion.ToString().Should().Be("2.1.1");
56+
}
57+
58+
[Theory]
59+
[InlineData("Microsoft.AspNetCore.App")]
60+
[InlineData("Microsoft.AspNetCore.All")]
61+
public void AspNetCoreVersionRollsForward(string aspnetPackageName)
62+
{
63+
var testProject = new TestProject()
64+
{
65+
Name = "AspNetImplicitVersion",
66+
TargetFrameworks = "netcoreapp2.1",
67+
IsSdkProject = true,
68+
IsExe = true,
69+
70+
};
71+
72+
testProject.RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid(testProject.TargetFrameworks);
73+
74+
// Add versionless PackageReference
75+
testProject.PackageReferences.Add(new TestPackageReference(aspnetPackageName, null));
76+
77+
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: aspnetPackageName)
78+
.Restore(Log, testProject.Name);
79+
80+
var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
81+
82+
buildCommand
83+
.Execute()
84+
.Should()
85+
.Pass();
86+
87+
var aspnetVersion = GetLibraryVersion(testProject, buildCommand, aspnetPackageName);
88+
89+
// Self-contained app (because RID is specified) should roll forward to later patch
90+
aspnetVersion.CompareTo(new SemanticVersion(2, 1, 1)).Should().BeGreaterThan(0);
91+
}
92+
93+
[Theory]
94+
[InlineData("Microsoft.AspNetCore.App")]
95+
[InlineData("Microsoft.AspNetCore.All")]
96+
public void ExplicitVersionsOfAspNetCoreWarn(string aspnetPackageName)
97+
{
98+
var testProject = new TestProject()
99+
{
100+
Name = "AspNetExplicitVersion",
101+
TargetFrameworks = "netcoreapp2.1",
102+
IsSdkProject = true,
103+
IsExe = true
104+
};
105+
106+
string explicitVersion = "2.1.0";
107+
108+
testProject.PackageReferences.Add(new TestPackageReference(aspnetPackageName, explicitVersion));
109+
110+
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: aspnetPackageName)
111+
.Restore(Log, testProject.Name);
112+
113+
var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
114+
115+
buildCommand
116+
.Execute()
117+
.Should()
118+
.Pass()
119+
.And
120+
.HaveStdOutContaining("NETSDK1071");
121+
122+
var aspnetVersion = GetLibraryVersion(testProject, buildCommand, aspnetPackageName);
123+
124+
aspnetVersion.ToString().Should().Be(explicitVersion);
125+
}
126+
127+
[Theory]
128+
[InlineData("netcoreapp2.0", "Microsoft.AspNetCore.All", "2.0.9")]
129+
[InlineData("netcoreapp1.1", "Microsoft.AspNetCore", "1.1.7")]
130+
public void ExplicitVersionsDontWarnForOlderVersions(string targetFramework, string packageName, string packageVersion)
131+
{
132+
var testProject = new TestProject()
133+
{
134+
Name = "AspNetPreviousVersion",
135+
TargetFrameworks = targetFramework,
136+
IsSdkProject = true,
137+
IsExe = true
138+
};
139+
140+
testProject.PackageReferences.Add(new TestPackageReference(packageName, packageVersion));
141+
142+
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
143+
.Restore(Log, testProject.Name);
144+
145+
var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
146+
147+
buildCommand
148+
.Execute()
149+
.Should()
150+
.Pass()
151+
.And
152+
.NotHaveStdOutContaining("warning");
153+
154+
var aspnetVersion = GetLibraryVersion(testProject, buildCommand, packageName);
155+
156+
aspnetVersion.ToString().Should().Be(packageVersion);
157+
}
158+
159+
[Fact]
160+
public void MultipleWarningsAreGeneratedForMultipleExplicitReferences()
161+
{
162+
var testProject = new TestProject()
163+
{
164+
Name = "MultipleExplicitReferences",
165+
TargetFrameworks = "netcoreapp2.1",
166+
IsSdkProject = true,
167+
IsExe = true
168+
};
169+
170+
testProject.PackageReferences.Add(new TestPackageReference("Microsoft.NETCore.App", "2.1.0"));
171+
testProject.PackageReferences.Add(new TestPackageReference("Microsoft.AspNetCore.App", "2.1.0"));
172+
173+
var testAsset = _testAssetsManager.CreateTestProject(testProject);
174+
175+
var restoreCommand = new RestoreCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
176+
restoreCommand
177+
.Execute()
178+
.Should()
179+
.Pass()
180+
.And
181+
.NotHaveStdOutContaining("NETSDK1071");
182+
183+
184+
var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
185+
186+
buildCommand
187+
.Execute()
188+
.Should()
189+
.Pass()
190+
.And
191+
.HaveStdOutContaining("NETSDK1071")
192+
.And
193+
.HaveStdOutContaining("NETSDK1023");
194+
}
195+
196+
static NuGetVersion GetLibraryVersion(TestProject testProject, BuildCommand buildCommand, string libraryName)
197+
{
198+
LockFile lockFile = LockFileUtilities.GetLockFile(
199+
Path.Combine(buildCommand.GetBaseIntermediateDirectory().FullName, "project.assets.json"),
200+
NullLogger.Instance);
201+
202+
var target = lockFile.GetTarget(NuGetFramework.Parse(testProject.TargetFrameworks), testProject.RuntimeIdentifier);
203+
var lockFileLibrary = target.Libraries.Single(l => l.Name == libraryName);
204+
205+
return lockFileLibrary.Version;
206+
}
207+
}
208+
}

src/Tests/Microsoft.NET.TestFramework/ProjectConstruction/TestProject.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,13 @@ internal void Create(TestAsset targetTestAsset, string testProjectsSourceFolder)
145145

146146
foreach (TestPackageReference packageReference in PackageReferences)
147147
{
148-
packageReferenceItemGroup.Add(new XElement(ns + "PackageReference",
149-
new XAttribute("Include", $"{packageReference.ID}"),
150-
new XAttribute("Version", $"{packageReference.Version}")));
148+
var packageReferenceElement = new XElement(ns + "PackageReference",
149+
new XAttribute("Include", packageReference.ID));
150+
if (packageReference.Version != null)
151+
{
152+
packageReferenceElement.Add(new XAttribute("Version", packageReference.Version));
153+
}
154+
packageReferenceItemGroup.Add(packageReferenceElement);
151155
}
152156

153157
foreach (TestPackageReference dotnetCliToolReference in DotNetCliToolReferences)

0 commit comments

Comments
 (0)