diff --git a/.gitignore b/.gitignore index f834920dd1..9aed881a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ _ReSharper.* *.pidb *.vspx *.psess +*.binlog +*.log packages target artifacts diff --git a/build/RepositoryBuild.targets b/build/RepositoryBuild.targets index 7a329f6dca..bef1c6b508 100644 --- a/build/RepositoryBuild.targets +++ b/build/RepositoryBuild.targets @@ -17,15 +17,29 @@ false + + + + + + + + Properties="BuildGroup=%(BatchedRepository.BuildGroup);BuildNumber=$(BuildNumber);IsFinalBuild=$(IsFinalBuild);Configuration=$(Configuration)" /> - + $(RepositoryBuildArguments) /p:BuildNumber=$(BuildNumber) /p:Configuration=$(Configuration) /p:CommitHash=$(CommitHash) @@ -68,16 +82,4 @@ - - - - - - - - - diff --git a/build/repo.targets b/build/repo.targets index 7d105c3107..ad9f7d7c7f 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -106,7 +106,7 @@ + DependsOnTargets="_PrepareRepositories;_CreateRepositoriesListWithCommits;ComputeGraph;_BuildRepositories" /> - - - - - - - - $(BuildDir)$(_RepositoryListFileName) diff --git a/build/tasks/AnalyzeBuildGraph.cs b/build/tasks/AnalyzeBuildGraph.cs index c4f587cc75..2e9de07dd8 100644 --- a/build/tasks/AnalyzeBuildGraph.cs +++ b/build/tasks/AnalyzeBuildGraph.cs @@ -136,8 +136,8 @@ namespace RepoTasks inconsistentVersions.Add(new VersionMismatch { - Solution = sln, - Project = proj, + Solution = solution, + Project = project, PackageId = dependency.Key, ActualVersion = dependency.Value.Version, ExpectedVersion = package.PackageInfo.Version, diff --git a/build/tasks/GenerateLineup.cs b/build/tasks/GenerateLineup.cs index 544284e409..1acbd7c577 100644 --- a/build/tasks/GenerateLineup.cs +++ b/build/tasks/GenerateLineup.cs @@ -25,6 +25,9 @@ namespace RepoTasks // Can be set to filter the lists of packages when produce a list for a specific repository public string Repository { get; set; } + // Items to add to the RestoreAdditionalProjectSources list in project + public ITaskItem[] RestoreAdditionalSources { get; set; } + public bool UseFloatingVersions { get; set; } public string BuildNumber { get; set; } @@ -40,25 +43,25 @@ namespace RepoTasks } var items = new XElement("ItemGroup"); - var root = new XElement("Project", items); + var props = new XElement("PropertyGroup"); + var root = new XElement("Project", props, items); var doc = new XDocument(root); + if (RestoreAdditionalSources.Length > 0) + { + var sources = RestoreAdditionalSources.Aggregate("$(RestoreAdditionalProjectSources)", (sum, piece) => sum + ";" + piece.ItemSpec); + props.Add(new XElement("RestoreAdditionalProjectSources", sources)); + } + var packages = new List(); - foreach (var item in Artifacts) + foreach (var pkg in Artifacts.Select(ArtifactInfo.Parse) + .OfType() + .Where(p => !p.IsSymbolsArtifact + && (string.IsNullOrEmpty(Repository) + || !Repository.Equals(p.RepoName, StringComparison.OrdinalIgnoreCase)))) { - var info = ArtifactInfo.Parse(item); - switch (info) - { - case ArtifactInfo.Package pkg when (!pkg.IsSymbolsArtifact): - // TODO filter this list based on topological sort info - if (string.IsNullOrEmpty(Repository) - || !Repository.Equals(pkg.RepoName, StringComparison.OrdinalIgnoreCase)) - { - packages.Add(pkg.PackageInfo); - } - break; - } + packages.Add(pkg.PackageInfo); } foreach (var pkg in packages.OrderBy(i => i.Id)) diff --git a/build/tasks/PinVersions.cs b/build/tasks/PinVersions.cs deleted file mode 100644 index b98c878173..0000000000 --- a/build/tasks/PinVersions.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using Microsoft.Build.Framework; -using RepoTasks.VersionPinning; - -namespace RepoTasks -{ - public class PinVersions : Microsoft.Build.Utilities.Task - { - [Required] - public string BuildRepositoryRoot { get; set; } - - [Required] - public ITaskItem[] PackageSources { get; set; } - - public string GraphSpecsRoot { get; set; } - - public override bool Execute() - { - if (PackageSources?.Length == 0) - { - Log.LogError($"Missing PackageSources. At least one item source must be specified."); - return false; - } - - var graphSpecProvider = !string.IsNullOrEmpty(GraphSpecsRoot) - ? new DependencyGraphSpecProvider(GraphSpecsRoot) - : DependencyGraphSpecProvider.Default; - - using (graphSpecProvider) - { - var pinVersionUtility = new PinVersionUtility( - BuildRepositoryRoot, - PackageSources.Select(i => i.ItemSpec).ToList(), - graphSpecProvider, - Log); - pinVersionUtility.Execute(); - } - - return true; - } - } -} diff --git a/build/tasks/VersionPinning/DependencyGraphSpecProvider.cs b/build/tasks/VersionPinning/DependencyGraphSpecProvider.cs deleted file mode 100644 index 1a5e2af362..0000000000 --- a/build/tasks/VersionPinning/DependencyGraphSpecProvider.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using NuGet.ProjectModel; - -namespace RepoTasks.VersionPinning -{ - public class DependencyGraphSpecProvider : IDisposable - { - private readonly string _packageSpecDirectory; - private readonly bool _deleteSpecDirectoryOnDispose; - private readonly string _dotnetPath; - - public DependencyGraphSpecProvider(string packageSpecDirectory) - : this(packageSpecDirectory, deleteSpecDirectoryOnDispose: false) - { - } - - private DependencyGraphSpecProvider(string packageSpecDirectory, bool deleteSpecDirectoryOnDispose) - { - _packageSpecDirectory = packageSpecDirectory; - _deleteSpecDirectoryOnDispose = deleteSpecDirectoryOnDispose; - _dotnetPath = Process.GetCurrentProcess().MainModule.FileName; - } - - public static DependencyGraphSpecProvider Default { get; } = - new DependencyGraphSpecProvider(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), deleteSpecDirectoryOnDispose: true); - - public DependencyGraphSpec GetDependencyGraphSpec(string repositoryName, string solutionPath) - { - var outputFile = Path.Combine(_packageSpecDirectory, repositoryName, Path.GetFileName(solutionPath) + ".json"); - - if (!File.Exists(outputFile)) - { - RunMSBuild(solutionPath, outputFile); - } - - return DependencyGraphSpec.Load(outputFile); - } - - private void RunMSBuild(string solutionPath, string outputFile) - { - var psi = new ProcessStartInfo(_dotnetPath); - - var arguments = new List - { - "msbuild", - $"\"{solutionPath}\"", - "/t:GenerateRestoreGraphFile", - "/nologo", - "/v:q", - "/p:BuildProjectReferences=false", - $"/p:RestoreGraphOutputPath=\"{outputFile}\"", - "/p:KoreBuildRestoreTargetsImported=true", - }; - - psi.Arguments = string.Join(" ", arguments); - psi.RedirectStandardOutput = true; - - var process = new Process - { - StartInfo = psi, - EnableRaisingEvents = true, - }; - process.OutputDataReceived += (sender, args) => - { - if (!string.IsNullOrEmpty(args.Data)) - { - Console.WriteLine(args.Data); - } - }; - - using (process) - { - process.Start(); - process.BeginOutputReadLine(); - - process.WaitForExit(60 * 5000); - if (process.ExitCode != 0) - { - throw new Exception($"{psi.FileName} {psi.Arguments} failed. Exit code {process.ExitCode}."); - } - } - } - - public void Dispose() - { - if (_deleteSpecDirectoryOnDispose) - { - Directory.Delete(_packageSpecDirectory, recursive: true); - } - } - } -} diff --git a/build/tasks/VersionPinning/PinVersionUtility.cs b/build/tasks/VersionPinning/PinVersionUtility.cs deleted file mode 100644 index c94e19fc62..0000000000 --- a/build/tasks/VersionPinning/PinVersionUtility.cs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using NuGet.Common; -using NuGet.Frameworks; -using NuGet.LibraryModel; -using NuGet.ProjectModel; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; - -namespace RepoTasks.VersionPinning -{ - internal class PinVersionUtility - { - private readonly string _repositoryRoot; - private readonly FindPackageByIdResource[] _findPackageResources; - private readonly ConcurrentDictionary> _exactMatches = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); - private readonly DependencyGraphSpecProvider _provider; - private readonly SourceCacheContext _sourceCacheContext; - private readonly TaskLoggingHelper _logger; - - public PinVersionUtility( - string repositoryRoot, - List pinSources, - DependencyGraphSpecProvider provider, - TaskLoggingHelper logger) - { - _repositoryRoot = repositoryRoot; - _findPackageResources = new FindPackageByIdResource[pinSources.Count]; - for (var i = 0; i < pinSources.Count; i++) - { - var repository = FactoryExtensionsV3.GetCoreV3(Repository.Factory, pinSources[i].Trim()); - _findPackageResources[i] = repository.GetResource(); - } - _provider = provider; - _sourceCacheContext = new SourceCacheContext(); - _logger = logger; - } - - public void Execute() - { - _logger.LogMessage(MessageImportance.High, $"Pinning package references for projects in {_repositoryRoot}"); - - var solutionPinMetadata = GetProjectPinVersionMetadata(); - foreach (var cliToolReference in solutionPinMetadata.CLIToolReferences) - { - _logger.LogMessage(MessageImportance.Normal, $"Pinning CLI Tool {cliToolReference.Item1.Name}({cliToolReference.Item1.VersionRange} to {cliToolReference.Item2} for all projects in {_repositoryRoot}."); - } - - foreach (var item in solutionPinMetadata.PinVersionLookup) - { - var projectPinMetadata = item.Value; - var specProject = projectPinMetadata.PackageSpec; - - if (!(projectPinMetadata.Packages.Any() || solutionPinMetadata.CLIToolReferences.Any())) - { - _logger.LogMessage(MessageImportance.Normal, $"No package or tool references to pin for {specProject.FilePath}."); - continue; - } - - var projectFileInfo = new FileInfo(specProject.FilePath); - var pinnedReferencesFile = Path.Combine( - specProject.RestoreMetadata.OutputPath, - projectFileInfo.Name + ".pinnedversions.targets"); - - Directory.CreateDirectory(Path.GetDirectoryName(pinnedReferencesFile)); - - if (projectPinMetadata.Packages.Any()) - { - _logger.LogMessage(MessageImportance.Normal, $"Pinning package versions for {specProject.FilePath}."); - } - - var pinnedReferences = new XElement("ItemGroup", new XAttribute("Condition", "'$(PolicyDesignTimeBuild)' != 'true' AND !Exists('$(MSBuildThisFileDirectory)$(MSBuildProjectFile).nugetpolicy.g.targets')")); - foreach (var packageReference in projectPinMetadata.Packages) - { - (var tfm, var libraryRange, var exactVersion) = packageReference; - _logger.LogMessage(MessageImportance.Normal, $"Pinning reference {libraryRange.Name}({libraryRange.VersionRange} to {exactVersion}."); - var metadata = new List - { - new XAttribute("Update", libraryRange.Name), - new XAttribute("Version", exactVersion.ToNormalizedString()), - }; - - if (tfm != NuGetFramework.AnyFramework) - { - metadata.Add(new XAttribute("Condition", $"'$(TargetFramework)'=='{tfm.GetShortFolderName()}'")); - } - - pinnedReferences.Add(new XElement("PackageReference", metadata)); - } - - // CLI Tool references are specified at solution level. - foreach (var toolReference in solutionPinMetadata.CLIToolReferences) - { - (var libraryRange, var exactVersion) = toolReference; - var metadata = new List - { - new XAttribute("Update", libraryRange.Name), - new XAttribute("Version", exactVersion.ToNormalizedString()), - }; - - pinnedReferences.Add(new XElement("DotNetCliToolReference", metadata)); - } - - var pinnedVersionRoot = new XElement("Project", pinnedReferences); - File.WriteAllText(pinnedReferencesFile, pinnedVersionRoot.ToString()); - } - } - - private SolutionPinVersionMetadata GetProjectPinVersionMetadata() - { - var repositoryDirectoryInfo = new DirectoryInfo(_repositoryRoot); - var projects = new Dictionary(StringComparer.OrdinalIgnoreCase); - var cliToolReferences = new List<(LibraryRange, NuGetVersion)>(); - - foreach (var slnFile in repositoryDirectoryInfo.EnumerateFiles("*.sln")) - { - var graphSpec = _provider.GetDependencyGraphSpec(repositoryDirectoryInfo.Name, slnFile.FullName); - foreach (var specProject in graphSpec.Projects) - { - if (!projects.TryGetValue(specProject.FilePath, out var pinMetadata)) - { - pinMetadata = new ProjectPinVersionMetadata(specProject); - projects[specProject.FilePath] = pinMetadata; - } - - var allDependencies = specProject.Dependencies.Select(dependency => new { Dependency = dependency, FrameworkName = NuGetFramework.AnyFramework }) - .Concat(specProject.TargetFrameworks.SelectMany(tfm => tfm.Dependencies.Select(dependency => new { Dependency = dependency, tfm.FrameworkName }))) - .Where(d => d.Dependency.LibraryRange.TypeConstraintAllows(LibraryDependencyTarget.Package)); - - foreach (var dependency in allDependencies) - { - var reference = dependency.Dependency; - var versionRange = reference.LibraryRange.VersionRange; - if (!versionRange.IsFloating) - { - continue; - } - - var exactVersion = GetExactVersion(reference.Name, versionRange); - if (exactVersion == null) - { - continue; - } - - var projectStyle = specProject.RestoreMetadata.ProjectStyle; - if (projectStyle == ProjectStyle.PackageReference) - { - pinMetadata.Packages.Add((dependency.FrameworkName, reference.LibraryRange, exactVersion)); - } - else if (projectStyle == ProjectStyle.DotnetCliTool) - { - cliToolReferences.Add((reference.LibraryRange, exactVersion)); - } - else - { - throw new NotSupportedException($"Unknown project style '{projectStyle}'."); - } - } - } - } - - return new SolutionPinVersionMetadata(projects, cliToolReferences); - } - - private NuGetVersion GetExactVersion(string name, VersionRange range) - { - if (range.MinVersion == null) - { - throw new Exception($"Unsupported version range {range}."); - } - - if (!_exactMatches.TryGetValue(name, out var versionTask)) - { - versionTask = _exactMatches.GetOrAdd(name, GetExactVersionAsync(name, range.MinVersion)); - } - - return versionTask.Result; - } - - private async Task GetExactVersionAsync(string name, NuGetVersion floatingVersion) - { - foreach (var findPackageResource in _findPackageResources) - { - var packageVersions = await findPackageResource.GetAllVersionsAsync(name, _sourceCacheContext, NullLogger.Instance, default(CancellationToken)); - - var matchingVersions = packageVersions.Where(v => v.Version == floatingVersion.Version).ToList(); - switch (matchingVersions.Count) - { - case 0: - continue; - case 1: - return matchingVersions[0]; - default: - throw new Exception($"More than one version for {name} found that matches the specified version constraint: {string.Join(" ", matchingVersions)}."); - } - } - - return null; - } - - private struct SolutionPinVersionMetadata - { - public SolutionPinVersionMetadata( - IDictionary pinVersionLookup, - List<(LibraryRange, NuGetVersion)> cliToolReferences) - { - PinVersionLookup = pinVersionLookup; - CLIToolReferences = cliToolReferences; - } - - public IDictionary PinVersionLookup { get; } - - public List<(LibraryRange, NuGetVersion)> CLIToolReferences { get; } - } - - private struct ProjectPinVersionMetadata - { - public ProjectPinVersionMetadata(PackageSpec packageSpec) - { - PackageSpec = packageSpec; - Packages = new List<(NuGetFramework, LibraryRange, NuGetVersion)>(); - } - - public PackageSpec PackageSpec { get; } - - public List<(NuGetFramework, LibraryRange, NuGetVersion)> Packages { get; } - } - } -}