PVP flow support (#15267)

Co-authored-by: Michael Simons <msimons@microsoft.com>
This commit is contained in:
Matt Mitchell 2023-01-17 09:45:40 -08:00 committed by GitHub
parent 9962c6a686
commit 987040517a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 389 additions and 202 deletions

View file

@ -119,9 +119,6 @@
<SourceBuiltToolsetDir>$(LocalBlobStorageRoot)Sdk/</SourceBuiltToolsetDir> <SourceBuiltToolsetDir>$(LocalBlobStorageRoot)Sdk/</SourceBuiltToolsetDir>
<SourceBuiltRuntimeDir>$(LocalBlobStorageRoot)Runtime/</SourceBuiltRuntimeDir> <SourceBuiltRuntimeDir>$(LocalBlobStorageRoot)Runtime/</SourceBuiltRuntimeDir>
<SourceBuiltAspNetCoreRuntime>$(LocalBlobStorageRoot)aspnetcore/Runtime/</SourceBuiltAspNetCoreRuntime> <SourceBuiltAspNetCoreRuntime>$(LocalBlobStorageRoot)aspnetcore/Runtime/</SourceBuiltAspNetCoreRuntime>
<RestoreSourcePropsPath>$(IntermediatePath)RestoreSources.props</RestoreSourcePropsPath>
<PackageVersionPropsPath>$(IntermediatePath)PackageVersions.props</PackageVersionPropsPath>
<CurrentSourceBuiltPackageVersionPropsPath>$(IntermediatePath)CurrentSourceBuiltPackageVersions.props</CurrentSourceBuiltPackageVersionPropsPath>
<LoggingDir>$(BaseOutputPath)logs/</LoggingDir> <LoggingDir>$(BaseOutputPath)logs/</LoggingDir>
<MSBuildDebugPathTargetDir>$(BaseOutputPath)msbuild-debug/</MSBuildDebugPathTargetDir> <MSBuildDebugPathTargetDir>$(BaseOutputPath)msbuild-debug/</MSBuildDebugPathTargetDir>
<RoslynDebugPathTargetDir>$(BaseOutputPath)roslyn-debug/</RoslynDebugPathTargetDir> <RoslynDebugPathTargetDir>$(BaseOutputPath)roslyn-debug/</RoslynDebugPathTargetDir>

View file

@ -9,7 +9,6 @@
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="NuGetPack" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="NuGetPack" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ZipFileExtractToDirectory" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ZipFileExtractToDirectory" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ReplaceTextInFile" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ReplaceTextInFile" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ReplaceRegexInFiles" />
<ItemGroup> <ItemGroup>
<BuildTasksTarget Include="Restore;Build;InstallResolver" /> <BuildTasksTarget Include="Restore;Build;InstallResolver" />
@ -23,7 +22,6 @@
<CallTarget Targets=" <CallTarget Targets="
UnpackTarballs; UnpackTarballs;
BuildXPlatTasks; BuildXPlatTasks;
PatchPackageVersions;
BuildLeakDetection; BuildLeakDetection;
ExtractToolPackage; ExtractToolPackage;
GenerateRootFs; GenerateRootFs;
@ -67,25 +65,6 @@
<Copy SourceFiles="@(UnpackedSourceBuildReferencePackages)" DestinationFiles="$(ReferencePackagesDir)%(Filename)%(Extension)" /> <Copy SourceFiles="@(UnpackedSourceBuildReferencePackages)" DestinationFiles="$(ReferencePackagesDir)%(Filename)%(Extension)" />
<!-- Setup the PackageVersions.props file to be a combination of source built and previously source built packages -->
<Copy SourceFiles="$(PrebuiltSourceBuiltPackagesPath)PackageVersions.props" DestinationFiles="$(IntermediatePath)PreviouslySourceBuiltPackageVersions.props" />
<PropertyGroup>
<PackageVersionsPropsFile>$(IntermediatePath)PackageVersions.props</PackageVersionsPropsFile>
<PackageVersionsPropsContents>
<![CDATA[<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="PreviouslySourceBuiltPackageVersions.props" Condition="Exists('PreviouslySourceBuiltPackageVersions.props')" />
<Import Project="CurrentSourceBuiltPackageVersions.props" Condition="Exists('CurrentSourceBuiltPackageVersions.props')" />
</Project>
]]>
</PackageVersionsPropsContents>
</PropertyGroup>
<WriteLinesToFile File="$(PackageVersionsPropsFile)"
Lines="$(PackageVersionsPropsContents)"
Overwrite="true" />
<WriteLinesToFile File="$(CompletedSemaphorePath)UnpackTarballs.complete" Overwrite="true" /> <WriteLinesToFile File="$(CompletedSemaphorePath)UnpackTarballs.complete" Overwrite="true" />
</Target> </Target>
@ -107,16 +86,6 @@
<WriteLinesToFile File="$(CompletedSemaphorePath)BuildXPlatTasks.complete" Overwrite="true" /> <WriteLinesToFile File="$(CompletedSemaphorePath)BuildXPlatTasks.complete" Overwrite="true" />
</Target> </Target>
<!-- TODO: Remove this when the .NET 8 artifacts tarball no longer includes MicrosoftAspNetCoreAppRuntimePackageVersion -->
<Target Name="PatchPackageVersions">
<!-- Rename MicrosoftAspNetCoreAppRuntimePackageVersion so it isn't used
Fixes https://github.com/dotnet/installer/issues/14492 -->
<ReplaceRegexInFiles
InputFiles="$(IntermediatePath)PreviouslySourceBuiltPackageVersions.props"
OldTextRegex="\bMicrosoftAspNetCoreAppRuntimePackageVersion\b"
NewText="__unused" />
</Target>
<Target Name="BuildLeakDetection" <Target Name="BuildLeakDetection"
DependsOnTargets="ExtractToolPackage" DependsOnTargets="ExtractToolPackage"
Inputs="$(MSBuildProjectFullPath)" Inputs="$(MSBuildProjectFullPath)"

View file

@ -16,8 +16,8 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.UsageReport
{ {
public class WriteUsageReports : Task public class WriteUsageReports : Task
{ {
private const string SnapshotPrefix = "PackageVersions.props.pre."; private const string SnapshotPrefix = "PackageVersions.";
private const string SnapshotSuffix = ".xml"; private const string SnapshotSuffix = ".Current.props";
/// <summary> /// <summary>
/// Source usage data JSON file. /// Source usage data JSON file.
@ -26,7 +26,7 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.UsageReport
public string DataFile { get; set; } public string DataFile { get; set; }
/// <summary> /// <summary>
/// A set of "PackageVersions.props.pre.{repo}.xml" files. They are analyzed to find /// A set of "PackageVersions.{repo}.Current.props" files. They are analyzed to find
/// packages built during source-build, and which repo built them. This info is added to the /// packages built during source-build, and which repo built them. This info is added to the
/// report. New packages are associated to a repo by going through each PVP in ascending /// report. New packages are associated to a repo by going through each PVP in ascending
/// file modification order. /// file modification order.
@ -114,7 +114,7 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.UsageReport
string id = usage.PackageIdentity.Id; string id = usage.PackageIdentity.Id;
string version = usage.PackageIdentity.Version.OriginalVersion; string version = usage.PackageIdentity.Version.OriginalVersion;
string pvpIdent = WriteBuildOutputProps.GetPropertyName(id); string pvpIdent = WritePackageVersionsProps.GetPropertyName(id, WritePackageVersionsProps.VersionPropertySuffix);
var sourceBuildCreator = new StringBuilder(); var sourceBuildCreator = new StringBuilder();
foreach (RepoOutput output in sourceBuildRepoOutputs) foreach (RepoOutput output in sourceBuildRepoOutputs)
@ -200,7 +200,7 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.UsageReport
// Get the creation time element. // Get the creation time element.
?.Element(snapshot.Xml ?.Element(snapshot.Xml
.GetDefaultNamespace() .GetDefaultNamespace()
.GetName(WriteBuildOutputProps.CreationTimePropertyName)) .GetName(WritePackageVersionsProps.CreationTimePropertyName))
?.Value; ?.Value;
if (string.IsNullOrEmpty(creationTime)) if (string.IsNullOrEmpty(creationTime))

View file

@ -1,142 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Microsoft.DotNet.Build.Tasks
{
public class WriteBuildOutputProps : Task
{
private static readonly Regex InvalidElementNameCharRegex = new Regex(@"(^|[^A-Za-z0-9])(?<FirstPartChar>.)");
public const string CreationTimePropertyName = "BuildOutputPropsCreationTime";
[Required]
public ITaskItem[] NuGetPackages { get; set; }
[Required]
public string OutputPath { get; set; }
/// <summary>
/// Adds a second PropertyGroup to the output XML containing a property with the time of
/// creation in UTC DateTime Ticks. This can be used to track creation time in situations
/// where file metadata isn't reliable or preserved.
/// </summary>
public bool IncludeCreationTimeProperty { get; set; }
/// <summary>
/// Properties to add to the build output props, which may not exist as nupkgs.
/// FOr example, this is used to pass the version of the CLI toolset archives.
///
/// %(Identity): Package identity.
/// %(Version): Package version.
/// </summary>
public ITaskItem[] ExtraProperties { get; set; }
/// <summary>
/// Additional assets to be added to the build output props.
/// i.e. /bin/obj/x64/Release/blobs/Toolset/3.0.100
/// This parameter is the <pathToAsset>/<assetName> portion only, and the asset
/// must be in a <AdditionalAssetDir>/<assetVersion> folder.
/// </summary>
public string[] AdditionalAssetDirs { get; set; }
public override bool Execute()
{
PackageIdentity[] latestPackages = NuGetPackages
.Select(item =>
{
using (var reader = new PackageArchiveReader(item.GetMetadata("FullPath")))
{
return reader.GetIdentity();
}
})
.GroupBy(identity => identity.Id)
.Select(g => g.OrderBy(id => id.Version).Last())
.OrderBy(id => id.Id)
.ToArray();
var additionalAssets = (AdditionalAssetDirs ?? new string[0])
.Where(Directory.Exists)
.Where(dir => Directory.GetDirectories(dir).Count() > 0)
.Select(dir => new {
Name = new DirectoryInfo(dir).Name + "Version",
Version = new DirectoryInfo(Directory.EnumerateDirectories(dir).OrderBy(s => s).Last()).Name
}).ToArray();
Directory.CreateDirectory(Path.GetDirectoryName(OutputPath));
using (var outStream = File.Open(OutputPath, FileMode.Create))
using (var sw = new StreamWriter(outStream, new UTF8Encoding(false)))
{
sw.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8""?>");
sw.WriteLine(@"<Project ToolsVersion=""14.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">");
sw.WriteLine(@" <PropertyGroup>");
foreach (PackageIdentity packageIdentity in latestPackages)
{
string propertyName = GetPropertyName(packageIdentity.Id);
sw.WriteLine($" <{propertyName}>{packageIdentity.Version}</{propertyName}>");
propertyName = GetAlternatePropertyName(packageIdentity.Id);
sw.WriteLine($" <{propertyName}>{packageIdentity.Version}</{propertyName}>");
}
foreach (var extraProp in ExtraProperties ?? Enumerable.Empty<ITaskItem>())
{
string propertyName = extraProp.GetMetadata("Identity");
bool doNotOverwrite = false;
string overwriteCondition = string.Empty;
if (bool.TryParse(extraProp.GetMetadata("DoNotOverwrite"), out doNotOverwrite) && doNotOverwrite)
{
overwriteCondition = $" Condition=\"'$({propertyName})' == ''\"";
}
sw.WriteLine($" <{propertyName}{overwriteCondition}>{extraProp.GetMetadata("Version")}</{propertyName}>");
}
foreach (var additionalAsset in additionalAssets)
{
sw.WriteLine($" <{additionalAsset.Name}>{additionalAsset.Version}</{additionalAsset.Name}>");
}
sw.WriteLine(@" </PropertyGroup>");
if (IncludeCreationTimeProperty)
{
sw.WriteLine(@" <PropertyGroup>");
sw.WriteLine($@" <{CreationTimePropertyName}>{DateTime.UtcNow.Ticks}</{CreationTimePropertyName}>");
sw.WriteLine(@" </PropertyGroup>");
}
sw.WriteLine(@"</Project>");
}
return true;
}
public static string GetPropertyName(string id)
{
string formattedId = InvalidElementNameCharRegex.Replace(
id,
match => match.Groups?["FirstPartChar"].Value.ToUpperInvariant()
?? string.Empty);
return $"{formattedId}PackageVersion";
}
public static string GetAlternatePropertyName(string id)
{
string formattedId = InvalidElementNameCharRegex.Replace(
id,
match => match.Groups?["FirstPartChar"].Value.ToUpperInvariant()
?? string.Empty);
return $"{formattedId}Version";
}
}
}

View file

@ -0,0 +1,326 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
namespace Microsoft.DotNet.Build.Tasks
{
public class VersionEntry
{
public string Name;
public string Version;
}
/// <summary>
/// Creates a props file that is used as the input for a repo-level build. The props file
/// includes package version numbers that should be used by the repo build and additional special properties.
///
/// There are two types of input props that can be written:
/// - Versions of union of all packages produced by the builds are added. (AllPackages)
/// - Only versions of packages that are listed as dependencies of a repo are added. (DependenciesOnly)
///
/// The former represents the current way that source build works for most repos. The latter represents the desired
/// methodology (PVP Flow). PVP flow closely matches how the product is built in non-source-build mode.
/// </summary>
public class WritePackageVersionsProps : Microsoft.Build.Utilities.Task
{
private static readonly Regex InvalidElementNameCharRegex = new Regex(@"(^|[^A-Za-z0-9])(?<FirstPartChar>.)");
public const string CreationTimePropertyName = "BuildOutputPropsCreationTime";
public const string VersionPropertySuffix = "Version";
private const string VersionPropertyAlternateSuffix = "PackageVersion";
private const string PinnedAttributeName = "Pinned";
private const string DependencyAttributeName = "Dependency";
private const string NameAttributeName = "Name";
private const string AllPackagesVersionPropsFlowType = "AllPackages";
private const string DependenciesOnlyVersionPropsFlowType = "DependenciesOnly";
private const string DefaultVersionPropsFlowType = AllPackagesVersionPropsFlowType;
/// <summary>
/// Set of input nuget package files to generate version properties for.
/// </summary>
[Required]
public ITaskItem[] NuGetPackages { get; set; }
/// <summary>
/// File where the version properties should be written.
/// </summary>
[Required]
public string OutputPath { get; set; }
/// <summary>
/// Adds a second PropertyGroup to the output XML containing a property with the time of
/// creation in UTC DateTime Ticks. This can be used to track creation time in situations
/// where file metadata isn't reliable or preserved.
/// </summary>
public bool IncludeCreationTimeProperty { get; set; }
/// <summary>
/// Properties to add to the build output props, which may not exist as nupkgs.
/// FOr example, this is used to pass the version of the CLI toolset archives.
///
/// %(Identity): Package identity.
/// %(Version): Package version.
/// </summary>
public ITaskItem[] ExtraProperties { get; set; }
/// <summary>
/// Additional assets to be added to the build output props.
/// i.e. /bin/obj/x64/Release/blobs/Toolset/3.0.100
/// This parameter is the <pathToAsset>/<assetName> portion only, and the asset
/// must be in a <AdditionalAssetDir>/<assetVersion> folder.
/// </summary>
public string[] AdditionalAssetDirs { get; set; }
/// <summary>
/// Indicates which properties will be written into the Version props file.
/// If AllPackages (Default), all packages from previously built repos will be written.
/// If DependenciesOnly, then only those packages appearing as dependencies in
/// Version.Details.xml will show up. The VersionsDetails property must be set to a
/// valid Version.Details.xml path when DependenciesOnly is used.
/// </summary>
public string VersionPropsFlowType { get; set; } = DefaultVersionPropsFlowType;
/// <summary>
/// If VersionPropsFlowType is set to DependenciesOnly, should be the path to the Version.Detail.xml file for the repo.
/// </summary>
public string VersionDetails { get; set; }
/// <summary>
/// Retrieve the set of the dependencies from the repo's Version.Details.Xml file.
/// </summary>
/// <returns>Hash set of dependency names. </returns>
private HashSet<string> GetDependences()
{
XmlDocument document = new XmlDocument();
try
{
document.Load(VersionDetails);
}
catch (Exception e)
{
Log.LogErrorFromException(e);
return null;
}
HashSet<string> dependencyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
// Load the nodes, filter those that are not pinned, and
XmlNodeList dependencyNodes = document.DocumentElement.SelectNodes($"//{DependencyAttributeName}");
foreach (XmlNode dependency in dependencyNodes)
{
if (dependency.NodeType == XmlNodeType.Comment || dependency.NodeType == XmlNodeType.Whitespace)
{
continue;
}
bool isPinned = false;
XmlAttribute pinnedAttribute = dependency.Attributes[PinnedAttributeName];
if (pinnedAttribute != null && !bool.TryParse(pinnedAttribute.Value, out isPinned))
{
Log.LogError($"The '{PinnedAttributeName}' attribute is set but the value " +
$"'{pinnedAttribute.Value}' is not a valid boolean...");
return null;
}
if (isPinned)
{
continue;
}
var name = dependency.Attributes[NameAttributeName]?.Value?.Trim();
if (string.IsNullOrEmpty(name))
{
Log.LogError($"The '{NameAttributeName}' attribute must be specified.");
return null;
}
dependencyNames.Add(name);
}
return dependencyNames;
}
/// <summary>
/// Filter a set of input dependencies to those that appear in <paramref name="dependencies"/>
/// </summary>
/// <param name="input">Input set of entries</param>
/// <param name="dependencies">Set of dependencies</param>
/// <returns>Set of <paramref name="input"/> that appears in <paramref name="dependencies"/></returns>
private IEnumerable<VersionEntry> FilterNonDependencies(IEnumerable<VersionEntry> input, HashSet<string> dependencies)
{
return input.Where(entry => dependencies.Contains(entry.Name));
}
public override bool Execute()
{
if (VersionPropsFlowType != AllPackagesVersionPropsFlowType &&
VersionPropsFlowType != DependenciesOnlyVersionPropsFlowType)
{
Log.LogError($"Valid version flow types are '{DependenciesOnlyVersionPropsFlowType}' and '{AllPackagesVersionPropsFlowType}'");
return !Log.HasLoggedErrors;
}
if (VersionPropsFlowType == DependenciesOnlyVersionPropsFlowType && (string.IsNullOrEmpty(VersionDetails) || !File.Exists(VersionDetails)))
{
Log.LogError($"When version flow type is DependenciesOnly, the VersionDetails task parameter must point to a valid path to the Version.Details.xml file for the repo. " +
"Provided file path '{VersionDetails}' does not exist.");
return !Log.HasLoggedErrors;
}
// First, obtain version information from the packages and additional assets that
// are provided.
var latestPackages = NuGetPackages
.Select(item =>
{
using (var reader = new PackageArchiveReader(item.GetMetadata("FullPath")))
{
return reader.GetIdentity();
}
})
.GroupBy(identity => identity.Id)
.Select(g => g.OrderBy(id => id.Version).Last())
.OrderBy(id => id.Id)
.Select(identity => new VersionEntry()
{
Name = identity.Id,
Version = identity.Version.ToString()
});
var additionalAssets = (AdditionalAssetDirs ?? new string[0])
.Where(Directory.Exists)
.Where(dir => Directory.GetDirectories(dir).Count() > 0)
.Select(dir => new VersionEntry()
{
Name = new DirectoryInfo(dir).Name,
Version = new DirectoryInfo(Directory.EnumerateDirectories(dir).OrderBy(s => s).Last()).Name
});
var packageElementsToWrite = latestPackages;
var additionalAssetElementsToWrite = additionalAssets;
// Then, if version flow type is "DependenciesOnly", filter those
// dependencies that do not appear in the version.details.xml file.
if (VersionPropsFlowType == DependenciesOnlyVersionPropsFlowType)
{
var dependencies = GetDependences();
if (Log.HasLoggedErrors)
{
return false;
}
packageElementsToWrite = FilterNonDependencies(packageElementsToWrite, dependencies);
additionalAssetElementsToWrite = FilterNonDependencies(additionalAssetElementsToWrite, dependencies);
}
Directory.CreateDirectory(Path.GetDirectoryName(OutputPath));
using (var outStream = File.Open(OutputPath, FileMode.Create))
using (var sw = new StreamWriter(outStream, new UTF8Encoding(false)))
{
sw.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8""?>");
sw.WriteLine(@"<Project ToolsVersion=""14.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">");
WriteVersionEntries(sw, packageElementsToWrite, "packages");
WriteExtraProperties(sw);
WriteVersionEntries(sw, additionalAssetElementsToWrite, "additional assets");
if (IncludeCreationTimeProperty)
{
sw.WriteLine(@" <PropertyGroup>");
sw.WriteLine($@" <{CreationTimePropertyName}>{DateTime.UtcNow.Ticks}</{CreationTimePropertyName}>");
sw.WriteLine(@" </PropertyGroup>");
}
sw.WriteLine(@"</Project>");
}
return !Log.HasLoggedErrors;
}
/// <summary>
/// Write properties specified in the "ExtraProperties task parameter
/// </summary>
/// <param name="sw">Stream writer</param>
private void WriteExtraProperties(StreamWriter sw)
{
if (ExtraProperties == null)
{
return;
}
sw.WriteLine(@" <!-- Extra properties -->");
sw.WriteLine(@" <PropertyGroup>");
foreach (var extraProp in ExtraProperties ?? Enumerable.Empty<ITaskItem>())
{
string propertyName = extraProp.GetMetadata("Identity");
bool doNotOverwrite = false;
string overwriteCondition = string.Empty;
if (bool.TryParse(extraProp.GetMetadata("DoNotOverwrite"), out doNotOverwrite) && doNotOverwrite)
{
overwriteCondition = $" Condition=\"'$({propertyName})' == ''\"";
}
sw.WriteLine($" <{propertyName}{overwriteCondition}>{extraProp.GetMetadata("Version")}</{propertyName}>");
}
sw.WriteLine(@" </PropertyGroup>");
}
/// <summary>
/// Write properties for the version numbers required for this repo.
/// </summary>
/// <param name="sw">Stream writer</param>
/// <param name="entries">Version entries</param>
private void WriteVersionEntries(StreamWriter sw, IEnumerable<VersionEntry> entries, string entryType)
{
if (!entries.Any())
{
return;
}
sw.WriteLine($" <!-- Versions of {entryType} produced by earlier stages of the build -->");
if (VersionPropsFlowType == DependenciesOnlyVersionPropsFlowType)
{
sw.WriteLine(@" <!-- Only those packages/assets that are explicit dependencies of this repo are included. -->");
}
sw.WriteLine(@" <PropertyGroup>");
foreach (var package in entries)
{
string propertyName = GetPropertyName(package.Name, VersionPropertySuffix);
string alternatePropertyName = GetPropertyName(package.Name, VersionPropertyAlternateSuffix);
sw.WriteLine($" <{propertyName}>{package.Version}</{propertyName}>");
sw.WriteLine($" <{alternatePropertyName}>{package.Version}</{alternatePropertyName}>");
}
sw.WriteLine(@" </PropertyGroup>");
}
public static string GetPropertyName(string id, string suffix)
{
string formattedId = InvalidElementNameCharRegex.Replace(
id,
match => match.Groups?["FirstPartChar"].Value.ToUpperInvariant()
?? string.Empty);
return $"{formattedId}{suffix}";
}
}
}

View file

@ -22,6 +22,12 @@
Repo specific semaphore path for incremental build Repo specific semaphore path for incremental build
--> -->
<RepoCompletedSemaphorePath>$(CompletedSemaphorePath)$(RepositoryName)/</RepoCompletedSemaphorePath> <RepoCompletedSemaphorePath>$(CompletedSemaphorePath)$(RepositoryName)/</RepoCompletedSemaphorePath>
<!-- Paths to the version props files -->
<CurrentSourceBuiltPackageVersionPropsPath>$(IntermediatePath)PackageVersions.$(RepositoryName).Current.props</CurrentSourceBuiltPackageVersionPropsPath>
<PreviouslySourceBuiltPackageVersionPropsPath>$(IntermediatePath)PackageVersions.$(RepositoryName).Previous.props</PreviouslySourceBuiltPackageVersionPropsPath>
<PackageVersionPropsPath>$(IntermediatePath)PackageVersions.$(RepositoryName).props</PackageVersionPropsPath>
<PackageVersionPropsFlowType>AllPackages</PackageVersionPropsFlowType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(OS)' == 'Windows_NT'"> <PropertyGroup Condition="'$(OS)' == 'Windows_NT'">

View file

@ -13,12 +13,13 @@
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="UpdateJson" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="UpdateJson" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="UpdateNuGetConfigPackageSourcesMappings" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="UpdateNuGetConfigPackageSourcesMappings" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ValidateUsageAgainstBaseline" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ValidateUsageAgainstBaseline" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WriteBuildOutputProps" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WritePackageVersionsProps" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WritePackageUsageData" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WritePackageUsageData" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WriteUsageReports" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WriteUsageReports" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WriteVersionsFile" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="WriteVersionsFile" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ZipFileExtractToDirectory" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ZipFileExtractToDirectory" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ReplaceTextInFile" /> <UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ReplaceTextInFile" />
<UsingTask AssemblyFile="$(XPlatSourceBuildTasksAssembly)" TaskName="ReplaceRegexInFiles" />
<!-- <!--
Central property to define that a repo doesn't implement any of the Repo API. If a repo adds an Central property to define that a repo doesn't implement any of the Repo API. If a repo adds an
@ -169,7 +170,6 @@
<ExtraSourcesNuGetSourceName>ExtraSources</ExtraSourcesNuGetSourceName> <ExtraSourcesNuGetSourceName>ExtraSources</ExtraSourcesNuGetSourceName>
<SourceBuildSources>$(PrebuiltNuGetSourceName);$(PreviouslySourceBuiltNuGetSourceName);$(ReferencePackagesNuGetSourceName);$(SourceBuiltNuGetSourceName)</SourceBuildSources> <SourceBuildSources>$(PrebuiltNuGetSourceName);$(PreviouslySourceBuiltNuGetSourceName);$(ReferencePackagesNuGetSourceName);$(SourceBuiltNuGetSourceName)</SourceBuildSources>
<SourceBuildSources Condition="'$(ExtraRestoreSourcePath)' != ''">$(SourceBuildSources);$(ExtraSourcesNuGetSourceName)</SourceBuildSources> <SourceBuildSources Condition="'$(ExtraRestoreSourcePath)' != ''">$(SourceBuildSources);$(ExtraSourcesNuGetSourceName)</SourceBuildSources>
<SourceBuildSources Condition="'$(VSS_NUGET_EXTERNAL_FEED_ENDPOINTS)' != '' and '$(SetUpInternalTransportFeed)' == 'true'">$(SourceBuildSources);$(DotNet5InternalTransportNuGetSourceName)</SourceBuildSources>
</PropertyGroup> </PropertyGroup>
<!-- Update the detected or manually specified NuGetConfigFile, but also allow multiple. --> <!-- Update the detected or manually specified NuGetConfigFile, but also allow multiple. -->
@ -232,36 +232,67 @@
<WriteLinesToFile File="$(RepoCompletedSemaphorePath)UpdateGlobalJsonVersions.complete" Overwrite="true" /> <WriteLinesToFile File="$(RepoCompletedSemaphorePath)UpdateGlobalJsonVersions.complete" Overwrite="true" />
</Target> </Target>
<Target Name="CreateBuildOutputProps" <!-- Before a repository builds, set up the version property files that override the repo's defaults.
There are 3 files generated -->
<Target Name="CreateBuildInputProps"
BeforeTargets="Build" BeforeTargets="Build"
Inputs="$(MSBuildProjectFullPath)" Inputs="$(MSBuildProjectFullPath)"
Outputs="$(RepoCompletedSemaphorePath)CreateBuildOutputProps.complete"> Outputs="$(RepoCompletedSemaphorePath)CreateBuildInputProps.complete">
<PropertyGroup>
<_PackageVersionPropsBackupPath>$(PackageVersionPropsPath).pre.$(RepositoryName).xml</_PackageVersionPropsBackupPath>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PreviouslySourceBuiltPackages Include="$(SourceBuiltPackagesPath)*.nupkg" <_CurrentSourceBuiltPackages Include="$(SourceBuiltPackagesPath)*.nupkg"
Exclude="$(SourceBuiltPackagesPath)*.symbols.nupkg" /> Exclude="$(SourceBuiltPackagesPath)*.symbols.nupkg" />
<_AdditionalAssetDirs Include="$(SourceBuiltToolsetDir)" Condition="Exists('$(SourceBuiltToolsetDir)')" /> <_PreviouslyBuiltSourceBuiltPackages Include="$(PrebuiltSourceBuiltPackagesPath)*.nupkg" />
<_CurrentAdditionalAssetDirs Include="$(SourceBuiltToolsetDir)" Condition="Exists('$(SourceBuiltToolsetDir)')" />
</ItemGroup> </ItemGroup>
<WriteBuildOutputProps NuGetPackages="@(PreviouslySourceBuiltPackages)" <Error Condition="'$(PackageVersionPropsFlowType)' != 'AllPackages' and '$(PackageVersionPropsFlowType)' != 'DependenciesOnly'"
Text="Invalid PackageVersionPropsFlowType '$(PackageVersionPropsFlowType)'. Must be 'AllPackages' or 'DependenciesOnly'." />
<PropertyGroup>
<_VersionDetailsXml Condition="'$(PackageVersionPropsFlowType)' == 'DependenciesOnly'">$(ProjectDirectory)/eng/Version.Details.xml</_VersionDetailsXml>
</PropertyGroup>
<!-- Write the build input properties, then save off a copy that will be used for generating usage reports later -->
<WritePackageVersionsProps NuGetPackages="@(_CurrentSourceBuiltPackages)"
ExtraProperties="@(ExtraPackageVersionPropsPackageInfo)" ExtraProperties="@(ExtraPackageVersionPropsPackageInfo)"
AdditionalAssetDirs="@(_AdditionalAssetDirs)" VersionPropsFlowType="$(PackageVersionPropsFlowType)"
VersionDetails="$(_VersionDetailsXml)"
AdditionalAssetDirs="@(_CurrentAdditionalAssetDirs)"
OutputPath="$(CurrentSourceBuiltPackageVersionPropsPath)" /> OutputPath="$(CurrentSourceBuiltPackageVersionPropsPath)" />
<WriteBuildOutputProps NuGetPackages="@(PreviouslySourceBuiltPackages)" <!-- Create previously source-built inputs info -->
IncludeCreationTimeProperty="true" <WritePackageVersionsProps NuGetPackages="@(_PreviouslyBuiltSourceBuiltPackages)"
OutputPath="$(_PackageVersionPropsBackupPath)" /> VersionPropsFlowType="$(PackageVersionPropsFlowType)"
VersionDetails="$(_VersionDetailsXml)"
OutputPath="$(PreviouslySourceBuiltPackageVersionPropsPath)" />
<Message Importance="High" Text="$(RepositoryName) using package version properties saved at $(_PackageVersionPropsBackupPath) " /> <!-- Rename MicrosoftAspNetCoreAppRuntimePackageVersion so it isn't used
Fixes https://github.com/dotnet/installer/issues/14492 -->
<ReplaceRegexInFiles InputFiles="$(PreviouslySourceBuiltPackageVersionPropsPath)"
OldTextRegex="\bMicrosoftAspNetCoreAppRuntimePackageVersion\b"
NewText="__unused" />
<ReadNuGetPackageInfos PackagePaths="@(PreviouslySourceBuiltPackages)"> <!-- Write a single file that contains imports for both the current and previously built packages -->
<Output TaskParameter="PackageInfoItems" ItemName="_PreviouslySourceBuiltPackageInfos" /> <PropertyGroup>
</ReadNuGetPackageInfos> <PackageVersionsPropsContents>
<![CDATA[<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(PreviouslySourceBuiltPackageVersionPropsPath)" />
<Import Project="$(CurrentSourceBuiltPackageVersionPropsPath)" />
</Project>
]]>
</PackageVersionsPropsContents>
</PropertyGroup>
<WriteLinesToFile File="$(RepoCompletedSemaphorePath)CreateBuildOutputProps.complete" Overwrite="true" /> <WriteLinesToFile File="$(PackageVersionPropsPath)"
Lines="$(PackageVersionsPropsContents)"
Overwrite="true" />
<Message Importance="High" Text="$(RepositoryName) using package version properties saved at $(CurrentSourceBuiltPackageVersionPropsPath) and $(PreviouslySourceBuiltPackageVersionPropsPath)" />
<WriteLinesToFile File="$(RepoCompletedSemaphorePath)CreateBuildInputProps.complete" Overwrite="true" />
</Target> </Target>
<Target Name="Build" <Target Name="Build"
@ -547,7 +578,7 @@
<ItemGroup> <ItemGroup>
<_PackagesNotCreatedReason Include="^ There may have been a silent failure in the submodule build. To confirm, check the build log file for undetected errors that may have prevented package creation: $(RepoConsoleLogFile)" /> <_PackagesNotCreatedReason Include="^ There may have been a silent failure in the submodule build. To confirm, check the build log file for undetected errors that may have prevented package creation: $(RepoConsoleLogFile)" />
<_PackagesNotCreatedReason Include="^ This error might be a false positive if $(RepositoryName) intentionally builds no nuget packages. If so, set the SkipEnsurePackagesCreated property to true in $(MSBuildProjectFullPath)" /> <_PackagesNotCreatedReason Include="^ This error might be a false positive if $(RepositoryName) intentionally builds no nuget packages. If so, set the SkipEnsurePackagesCreated property to true in $(MSBuildProjectFullPath)" />
<_PackagesNotCreatedReason Include="^ The 'bin' directory might be dirty from a previous build and the package files already existed. If so, perform a clean build, or check which packages were already in 'bin' by opening $(_PackageVersionPropsBackupPath)" /> <_PackagesNotCreatedReason Include="^ The 'bin' directory might be dirty from a previous build and the package files already existed. If so, perform a clean build, or check which packages were already in 'bin' by opening $(CurrentSourceBuiltPackageVersionPropsPath)" />
<_PackagesNotCreatedReason Include="^ The packages may have been written to an unexpected directory. For example, some repos used bin/ and changed to artifacts/ to match Arcade. Check PackagesOutput in $(MSBuildProjectFullPath) (currently '$(PackagesOutput)')" /> <_PackagesNotCreatedReason Include="^ The packages may have been written to an unexpected directory. For example, some repos used bin/ and changed to artifacts/ to match Arcade. Check PackagesOutput in $(MSBuildProjectFullPath) (currently '$(PackagesOutput)')" />
</ItemGroup> </ItemGroup>