Skip to content

Commit 8b91924

Browse files
NikolaMilosavljevicViktorHoferMichaelSimons
authored
Add package source mappings unit-tests (#44649)
Co-authored-by: Viktor Hofer <[email protected]> Co-authored-by: Michael Simons <[email protected]>
1 parent b5a9089 commit 8b91924

22 files changed

+1671
-0
lines changed

src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.UnifiedBuild.Tasks/UpdateNuGetConfigPackageSourcesMappings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ private void DiscoverPackagesFromAllSourceBuildSources(XElement pkgSourcesElemen
314314
}
315315

316316
string[] packages = Directory.GetFiles(path, "*.nupkg", SearchOption.AllDirectories);
317+
Array.Sort(packages);
317318
foreach (string package in packages)
318319
{
319320
NupkgInfo info = GetNupkgInfo(package);
@@ -358,6 +359,7 @@ private void DiscoverPackagesFromSbrpCacheSource()
358359
}
359360

360361
string[] nuspecFiles = Directory.GetFiles(SbrpRepoSrcPath, "*.nuspec", SearchOption.AllDirectories);
362+
Array.Sort(nuspecFiles);
361363
foreach (string nuspecFile in nuspecFiles)
362364
{
363365
try
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(NetCurrent)</TargetFramework>
5+
<DefaultExcludesInProjectFolder>$(DefaultExcludesInProjectFolder);assets/**/*</DefaultExcludesInProjectFolder>
6+
<VSTestLogger>console%3bverbosity=normal;trx%3bverbosity=diagnostic%3bLogFileName=$(MSBuildProjectName).trx</VSTestLogger>
7+
<VSTestCLIRunSettings>$(VSTestCLIRunSettings);RunConfiguration.DotNetHostPath=$(DotnetTool)</VSTestCLIRunSettings>
8+
<!--
9+
Required while we're using direct SDK assembly references in
10+
$(RepositoryEngineeringDir)tools/Directory.Build.props for all tools projects
11+
including Microsoft.DotNet.UnifiedBuild.Tasks.
12+
-->
13+
<NoWarn>$(NoWarn);MSB3277</NoWarn>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="$(RepositoryEngineeringDir)tools/tasks/Microsoft.DotNet.UnifiedBuild.Tasks/Microsoft.DotNet.UnifiedBuild.Tasks.csproj" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
22+
</ItemGroup>
23+
24+
<!--
25+
Copied from $(RepositoryEngineeringDir)tools/Directory.Build.props - keep in sync.
26+
27+
Use some assemblies from the SDK, instead of package references. This ensures they match what's
28+
found when the task is loaded by the SDK's MSBuild.
29+
Reference NuGet assemblies, except a command line assembly that causes warnings such as:
30+
MSB3277: Found conflicts between different versions of "System.Collections" that could not be resolved.
31+
-->
32+
<ItemGroup>
33+
<SdkAssembly Include="$([MSBuild]::NormalizePath('$(NetCoreRoot)', 'sdk', '$(NETCoreSdkVersion)', 'Newtonsoft.Json.dll'));
34+
$([MSBuild]::NormalizeDirectory('$(NetCoreRoot)', 'sdk', '$(NETCoreSdkVersion)'))NuGet.*.dll"
35+
Exclude="$([MSBuild]::NormalizePath('$(NetCoreRoot)', 'sdk', '$(NETCoreSdkVersion)', 'NuGet.CommandLine.XPlat.dll'))" />
36+
</ItemGroup>
37+
38+
<ItemGroup>
39+
<ReferencePath Include="@(SdkAssembly)" />
40+
</ItemGroup>
41+
42+
<ItemGroup>
43+
<Content Include="assets\**" CopyToOutputDirectory="PreserveNewest" />
44+
</ItemGroup>
45+
46+
<Target Name="SetRuntimeConfigOptions"
47+
BeforeTargets="_GenerateRuntimeConfigurationFilesInputCache">
48+
<ItemGroup>
49+
<!-- General configs -->
50+
<RuntimeHostConfigurationOption Include="$(MSBuildProjectName).LogsDirectory">
51+
<Value>$(ArtifactsTestResultsDir)</Value>
52+
</RuntimeHostConfigurationOption>
53+
<RuntimeHostConfigurationOption Include="$(MSBuildProjectName).TargetRid">
54+
<Value>$(TargetRid)</Value>
55+
</RuntimeHostConfigurationOption>
56+
<RuntimeHostConfigurationOption Include="$(MSBuildProjectName).PortableRid">
57+
<Value>$(PortableRid)</Value>
58+
</RuntimeHostConfigurationOption>
59+
</ItemGroup>
60+
</Target>
61+
62+
</Project>
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.IO.Compression;
9+
using System.Xml.Linq;
10+
using Microsoft.DotNet.UnifiedBuild.Tasks;
11+
using Xunit;
12+
using Xunit.Abstractions;
13+
14+
namespace Microsoft.DotNet.Tests
15+
{
16+
[Trait("Category", "PackageSourceMappings")]
17+
public class PackageSourceMappingsTests
18+
{
19+
private static readonly PackageSourceMappingsSetup TestSetup = PackageSourceMappingsSetup.Instance;
20+
21+
private const string NetSdkSupportingFeedName = "net-sdk-supporting-feed";
22+
private const string ArcadeSourceName = "source-built-arcade";
23+
private const string RuntimeSourceName = "source-built-runtime";
24+
private const string PrebuiltSourceName = "prebuilt";
25+
private const string PreviouslySourceBuiltSourceName = "previously-source-built";
26+
private const string ReferencePackagesSourceName = "reference-packages";
27+
28+
private ITestOutputHelper OutputHelper { get; }
29+
30+
public PackageSourceMappingsTests(ITestOutputHelper outputHelper)
31+
{
32+
OutputHelper = outputHelper;
33+
}
34+
35+
// Build with mappings - online - no local sources
36+
[Fact]
37+
public void BuildWithMappingsNoLocalSources()
38+
{
39+
string[] sources = [NetSdkSupportingFeedName];
40+
RunTest("ub-mappings-nolocal.config", true, sources, customSources: [NetSdkSupportingFeedName]);
41+
}
42+
43+
// Build with local sources - mappings and no mappings - online
44+
[Theory]
45+
[InlineData("ub-mappings.config")]
46+
[InlineData("ub-nomappings.config")]
47+
public void BuildWithLocalSources(string nugetConfigFilename)
48+
{
49+
string[] sources = [ArcadeSourceName, RuntimeSourceName, NetSdkSupportingFeedName];
50+
RunTest(nugetConfigFilename, true, sources, customSources: [NetSdkSupportingFeedName]);
51+
}
52+
53+
// Source build tests - with and without mappings - online and offline
54+
[Theory]
55+
[InlineData("sb-mappings-online.config", true)]
56+
[InlineData("sb-mappings-offline.config", false)]
57+
[InlineData("sb-nomappings-online.config", true)]
58+
[InlineData("sb-nomappings-offline.config", false)]
59+
public void SourceBuildTests(string nugetConfigFilename, bool useOnlineFeeds)
60+
{
61+
string[] sources = [PrebuiltSourceName, PreviouslySourceBuiltSourceName, ReferencePackagesSourceName,
62+
ArcadeSourceName, RuntimeSourceName];
63+
RunTest(nugetConfigFilename, useOnlineFeeds, sources, sourceBuild: true);
64+
}
65+
66+
// Source build - SBRP repo - online and offline
67+
[Theory]
68+
[InlineData("sb-sbrp-online.config", true)]
69+
[InlineData("sb-sbrp-offline.config", false)]
70+
public void SourceBuildSbrpRepoTests(string nugetConfigFilename, bool useOnlineFeeds)
71+
{
72+
string[] sources = [PrebuiltSourceName, PreviouslySourceBuiltSourceName, ReferencePackagesSourceName];
73+
RunTest(nugetConfigFilename, useOnlineFeeds, sources, sourceBuild: true);
74+
}
75+
76+
private static void RunTest(string nugetConfigFilename, bool useOnlineFeeds, string[] sources, string[]? customSources = null, bool sourceBuild = false)
77+
{
78+
string psmAssetsDir = Path.Combine(Directory.GetCurrentDirectory(), "assets", nameof(PackageSourceMappingsTests));
79+
string originalNugetConfig = Path.Combine(psmAssetsDir, "original", nugetConfigFilename);
80+
string expectedNugetConfig = Path.Combine(psmAssetsDir, "expected", nugetConfigFilename);
81+
82+
string modifiedNugetConfig = Path.Combine(PackageSourceMappingsSetup.PackageSourceMappingsRoot, nugetConfigFilename);
83+
Directory.CreateDirectory(Path.GetDirectoryName(modifiedNugetConfig)!);
84+
File.Copy(originalNugetConfig, modifiedNugetConfig, true);
85+
UpdateNugetConfigTokens(modifiedNugetConfig);
86+
87+
var task = new UpdateNuGetConfigPackageSourcesMappings()
88+
{
89+
SbrpCacheSourceName = "source-build-reference-package-cache",
90+
SbrpRepoSrcPath = TestSetup.SourceBuildReferencePackagesRepo,
91+
SourceBuiltSourceNamePrefix = "source-built-",
92+
NuGetConfigFile = modifiedNugetConfig,
93+
BuildWithOnlineFeeds = useOnlineFeeds,
94+
SourceBuildSources = sources,
95+
CustomSources = customSources
96+
};
97+
98+
if (sourceBuild)
99+
{
100+
task.ReferencePackagesSourceName = ReferencePackagesSourceName;
101+
task.PreviouslySourceBuiltSourceName = PreviouslySourceBuiltSourceName;
102+
task.PrebuiltSourceName = PrebuiltSourceName;
103+
}
104+
105+
task.Execute();
106+
107+
TokenizeLocalNugetConfigFeeds(modifiedNugetConfig);
108+
109+
string expectedNugetConfigContents = File.ReadAllText(expectedNugetConfig);
110+
string modifiedNugetConfigContents = File.ReadAllText(modifiedNugetConfig);
111+
Assert.Equal(expectedNugetConfigContents, modifiedNugetConfigContents);
112+
}
113+
114+
private static void UpdateNugetConfigTokens(string nugetConfigFile)
115+
{
116+
ApplyLocalTokenSourceMappings(nugetConfigFile, updateTokens: true);
117+
}
118+
119+
private static void TokenizeLocalNugetConfigFeeds(string nugetConfigFile)
120+
{
121+
ApplyLocalTokenSourceMappings(nugetConfigFile, tokenize: true);
122+
}
123+
124+
private static void ApplyLocalTokenSourceMappings(string nugetConfigFile, bool updateTokens = false, bool tokenize = false)
125+
{
126+
if (updateTokens == tokenize)
127+
{
128+
throw new InvalidOperationException($"One and only one option should be true, '{nameof(updateTokens)}' or '{nameof(tokenize)}'");
129+
}
130+
131+
string fileContents = File.ReadAllText(nugetConfigFile);
132+
foreach (KeyValuePair<string, string> kvp in TestSetup.LocalTokenSourceMappings)
133+
{
134+
fileContents = updateTokens
135+
? fileContents.Replace(kvp.Key, kvp.Value)
136+
: fileContents.Replace(kvp.Value, kvp.Key);
137+
}
138+
File.WriteAllText(nugetConfigFile, fileContents);
139+
}
140+
141+
internal class PackageSourceMappingsSetup
142+
{
143+
private static PackageSourceMappingsSetup? instance;
144+
private static readonly object myLock = new();
145+
146+
public static readonly string PackageSourceMappingsRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
147+
148+
private Dictionary<string, string>? localTokenSourceMappings;
149+
private readonly string ArcadeSource = Path.Combine(PackageSourceMappingsRoot, "arcade");
150+
private readonly string RuntimeSource = Path.Combine(PackageSourceMappingsRoot, "runtime");
151+
private readonly string PreviouslySourceBuiltSource = Path.Combine(PackageSourceMappingsRoot, "previously-source-built");
152+
private readonly string ReferencePackagesSource = Path.Combine(PackageSourceMappingsRoot, "reference-packages");
153+
private readonly string PrebuiltSource = Path.Combine(PackageSourceMappingsRoot, "prebuilt");
154+
private readonly string SourceBuildReferencePackagesSource = Path.Combine(PackageSourceMappingsRoot, "source-build-reference-package-cache");
155+
156+
public readonly string SourceBuildReferencePackagesRepo = Path.Combine(PackageSourceMappingsRoot, "sbrp");
157+
158+
public Dictionary<string, string> LocalTokenSourceMappings
159+
{
160+
get
161+
{
162+
localTokenSourceMappings ??= new Dictionary<string, string>
163+
{
164+
["%arcade%"] = ArcadeSource,
165+
["%runtime%"] = RuntimeSource,
166+
["%previously-source-built%"] = PreviouslySourceBuiltSource,
167+
["%reference-packages%"] = ReferencePackagesSource,
168+
["%prebuilt%"] = PrebuiltSource,
169+
["%source-build-reference-package-cache%"] = SourceBuildReferencePackagesSource
170+
};
171+
172+
return localTokenSourceMappings;
173+
}
174+
}
175+
176+
public static PackageSourceMappingsSetup Instance
177+
{
178+
get
179+
{
180+
lock (myLock)
181+
{
182+
instance ??= new PackageSourceMappingsSetup();
183+
}
184+
185+
return instance;
186+
}
187+
}
188+
189+
private PackageSourceMappingsSetup()
190+
{
191+
// Create the root directory
192+
Directory.CreateDirectory(PackageSourceMappingsRoot);
193+
194+
// Generate Arcade nuget packages
195+
GenerateNuGetPackage(ArcadeSource, "Arcade.Package1", "1.0.0");
196+
GenerateNuGetPackage(ArcadeSource, "Arcade.Package2", "1.0.0");
197+
198+
// Generate Runtime nuget packages
199+
GenerateNuGetPackage(RuntimeSource, "Runtime.Package1", "1.0.0");
200+
GenerateNuGetPackage(RuntimeSource, "Runtime.Package2", "1.0.0");
201+
202+
// Generate SBRP nuget packages
203+
GenerateNuGetPackage(SourceBuildReferencePackagesSource, "SBRP.Package1", "1.0.0");
204+
GenerateNuGetPackage(SourceBuildReferencePackagesSource, "SBRP.Package2", "1.0.0");
205+
206+
// Generate previously-source-built packages
207+
GenerateNuGetPackage(PreviouslySourceBuiltSource, "PSB.Package1", "1.0.0");
208+
GenerateNuGetPackage(PreviouslySourceBuiltSource, "PSB.Package2", "1.0.0");
209+
210+
// Generate reference packages
211+
GenerateNuGetPackage(ReferencePackagesSource, "Reference.Package1", "1.0.0");
212+
GenerateNuGetPackage(ReferencePackagesSource, "Reference.Package2", "1.0.0");
213+
214+
// Generate prebuilt packages
215+
GenerateNuGetPackage(PrebuiltSource, "Prebuilt.Package", "1.0.0");
216+
217+
// Generate SBRP repo files - nuspecs
218+
GenerateNuspecFile(SourceBuildReferencePackagesRepo, "SBRP.Repo.Package1", "1.0.0");
219+
GenerateNuspecFile(SourceBuildReferencePackagesRepo, "SBRP.Repo.Package2", "1.0.0");
220+
GenerateNuspecFile(SourceBuildReferencePackagesRepo, "SBRP.Repo.Package3", "1.0.0");
221+
GenerateNuspecFile(SourceBuildReferencePackagesRepo, "SBRP.Repo.Package4", "1.0.0");
222+
}
223+
224+
private static void GenerateNuGetPackage(string folder, string name, string version)
225+
{
226+
string nuspecPath = GenerateNuspecFile(folder, name, version);
227+
string packagePath = Path.ChangeExtension(nuspecPath, ".nupkg");
228+
229+
using FileStream stream = File.OpenWrite(packagePath);
230+
using ZipArchive zipArchive = new(stream, ZipArchiveMode.Create);
231+
ZipArchiveEntry entry = zipArchive.CreateEntryFromFile(nuspecPath, Path.GetFileName(nuspecPath));
232+
File.Delete(nuspecPath);
233+
}
234+
235+
private static string GenerateNuspecFile(string folder, string name, string version)
236+
{
237+
Directory.CreateDirectory(folder);
238+
239+
var ns = XNamespace.Get("http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd");
240+
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null));
241+
var root =
242+
new XElement(ns + "package",
243+
new XElement(ns + "metadata",
244+
new XElement(ns + "id", name),
245+
new XElement(ns + "version", version)
246+
)
247+
);
248+
doc.Add(root);
249+
250+
string nuspecPath = Path.Combine(folder, $"{name}.{version}.nuspec");
251+
doc.Save(nuspecPath);
252+
return nuspecPath;
253+
}
254+
}
255+
}
256+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<clear />
5+
<add key="source-built-runtime" value="%runtime%" />
6+
<add key="source-built-arcade" value="%arcade%" />
7+
<add key="reference-packages" value="%reference-packages%" />
8+
<add key="previously-source-built" value="%previously-source-built%" />
9+
<add key="prebuilt" value="%prebuilt%" />
10+
</packageSources>
11+
<!--
12+
****************************** AUTOGENERATED ***********************************
13+
Can re-generate these package source mappings by following the guide here:
14+
https://devblogs.microsoft.com/nuget/quickly-map-your-nuget-packages-to-sources/
15+
16+
In addition, once generated add the following to the top of the generated package
17+
source mapping if it doesn't already existe:
18+
19+
<packageSource key="dotnet-core-internal-tooling">
20+
<package pattern="microsoft.*" />
21+
</packageSource>
22+
<packageSource key="richnav">
23+
<package pattern="richcodenav.envvardump" />
24+
</packageSource>
25+
-->
26+
<packageSourceMapping>
27+
<clear />
28+
<packageSource key="source-built-runtime">
29+
<package pattern="runtime.package1" />
30+
<package pattern="runtime.package2" />
31+
</packageSource>
32+
<packageSource key="source-built-arcade">
33+
<package pattern="arcade.package1" />
34+
<package pattern="arcade.package2" />
35+
</packageSource>
36+
<packageSource key="reference-packages">
37+
<package pattern="reference.package1" />
38+
<package pattern="reference.package2" />
39+
</packageSource>
40+
<packageSource key="previously-source-built">
41+
<package pattern="psb.package1" />
42+
<package pattern="psb.package2" />
43+
</packageSource>
44+
<packageSource key="prebuilt">
45+
<package pattern="prebuilt.package" />
46+
</packageSource>
47+
</packageSourceMapping>
48+
<disabledPackageSources>
49+
<clear />
50+
</disabledPackageSources>
51+
</configuration>

0 commit comments

Comments
 (0)