Copy packages to ship/noship and verify coherent versions (#560)
This commit is contained in:
parent
351156f455
commit
177fa71634
|
|
@ -0,0 +1,29 @@
|
||||||
|
; EditorConfig to support per-solution formatting.
|
||||||
|
; Use the EditorConfig VS add-in to make this work.
|
||||||
|
; http://editorconfig.org/
|
||||||
|
|
||||||
|
; This is the default for the codeline.
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{cs}]
|
||||||
|
indent_size = 4
|
||||||
|
dotnet_sort_system_directives_first = true:warning
|
||||||
|
|
||||||
|
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.json]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{ps1,psm1}]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<Project>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageArtifact Include="Microsoft.AspNet.Identity.AspNetCoreCompat" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.All" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Diagnostics" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Diagnostics.Abstractions" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Diagnostics.Elm" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Diagnostics.Identity.Service" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Specification.Tests" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.Core" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.Abstractions" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.AzureKeyVault" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.IntegratedWebClient" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.Mvc" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Identity.Service.Specification.Tests" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.MiddlewareAnalysis" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Abstractions" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.ApiExplorer" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Core" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Cors" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.DataAnnotations" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Formatters.Xml" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Localization" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Razor" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.RazorPages" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.TagHelpers" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.Testing" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.NodeServices" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.NodeServices.Sockets" Category="noship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.AspNetCore.SpaServices" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Design" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.InMemory" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Relational" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Relational.Design.Specification.Tests" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Relational.Specification.Tests" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Specification.Tests" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Sqlite" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.SqlServer" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Tools" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.Extensions.Identity.Core" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.Extensions.Identity.Stores" Category="ship" Metapackage="include" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Contracts" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Core" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Templating" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Utils" Category="ship" Metapackage="exclude" />
|
||||||
|
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGenerators.Mvc" Category="ship" Metapackage="exclude" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -3,4 +3,6 @@
|
||||||
<!-- This repo does not have solutions to build -->
|
<!-- This repo does not have solutions to build -->
|
||||||
<DisableDefaultTargets>true</DisableDefaultTargets>
|
<DisableDefaultTargets>true</DisableDefaultTargets>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="artifacts.props" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@
|
||||||
|
|
||||||
<PrepareDependsOn>$(PrepareDependsOn);CleanArtifacts;CleanUniverseArtifacts</PrepareDependsOn>
|
<PrepareDependsOn>$(PrepareDependsOn);CleanArtifacts;CleanUniverseArtifacts</PrepareDependsOn>
|
||||||
<CleanDependsOn>$(CleanDependsOn);CleanUniverseArtifacts</CleanDependsOn>
|
<CleanDependsOn>$(CleanDependsOn);CleanUniverseArtifacts</CleanDependsOn>
|
||||||
<BuildDependsOn>$(BuildDependsOn);CloneRepositories;BuildRepositories</BuildDependsOn>
|
<CompileDependsOn>$(CompileDependsOn);CloneRepositories;BuildRepositories</CompileDependsOn>
|
||||||
|
<PackageDependsOn>$(PackageDependsOn);SplitPackages</PackageDependsOn>
|
||||||
|
<VerifyDependsOn>$(VerifyDependsOn);VerifyCoherentVersions</VerifyDependsOn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Import Project="$(_RepositoryListToImport)" />
|
<Import Project="$(_RepositoryListToImport)" />
|
||||||
|
|
@ -181,6 +183,26 @@
|
||||||
BuildNumber="$(BuildNumber)" />
|
BuildNumber="$(BuildNumber)" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="SplitPackages">
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageArtifactFile Include="$(BuildDir)*.nupkg" Exclude="$(BuildDir)*.symbols.nupkg" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<RepoTasks.CopyPackagesToSplitFolders
|
||||||
|
Packages="@(PackageArtifact)"
|
||||||
|
Files="@(PackageArtifactFile)"
|
||||||
|
DestinationFolder="$(ArtifactsDir)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="VerifyCoherentVersions">
|
||||||
|
<ItemGroup>
|
||||||
|
<ShippingPackageFiles Include="$(ArtifactsDir)ship\*.nupkg" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<RepoTasks.VerifyCoherentVersions
|
||||||
|
PackageFiles="@(ShippingPackageFiles)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
<Target Name="_CreateRepositoriesListWithCommits" DependsOnTargets="_GetRepositoryCommits">
|
<Target Name="_CreateRepositoriesListWithCommits" DependsOnTargets="_GetRepositoryCommits">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<RepositoryFileWithCommit>$(BuildDir)$(_RepositoryListFileName)</RepositoryFileWithCommit>
|
<RepositoryFileWithCommit>$(BuildDir)$(_RepositoryListFileName)</RepositoryFileWithCommit>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
// 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.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using NuGet.Packaging;
|
||||||
|
using NuGet.Packaging.Core;
|
||||||
|
using RepoTasks.Utilities;
|
||||||
|
|
||||||
|
namespace RepoTasks
|
||||||
|
{
|
||||||
|
public class CopyPackagesToSplitFolders : Microsoft.Build.Utilities.Task
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The item group containing the nuget packages to split in different folders.
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] Packages { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] Files { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The folder where packages should be copied. Subfolders will be created based on package category.
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string DestinationFolder { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (Files?.Length == 0)
|
||||||
|
{
|
||||||
|
Log.LogError("No packages were found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedPackages = PackageCollection.FromItemGroup(Packages);
|
||||||
|
|
||||||
|
Directory.CreateDirectory(DestinationFolder);
|
||||||
|
|
||||||
|
foreach (var file in Files)
|
||||||
|
{
|
||||||
|
PackageIdentity identity;
|
||||||
|
using (var reader = new PackageArchiveReader(file.ItemSpec))
|
||||||
|
{
|
||||||
|
identity = reader.GetIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expectedPackages.TryGetCategory(identity.Id, out var category))
|
||||||
|
{
|
||||||
|
Log.LogError($"Unexpected package artifact with id: {identity.Id}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string destDir;
|
||||||
|
switch (category)
|
||||||
|
{
|
||||||
|
case PackageCategory.Unknown:
|
||||||
|
throw new InvalidOperationException($"Package {identity} does not have a recognized package category.");
|
||||||
|
case PackageCategory.Shipping:
|
||||||
|
destDir = Path.Combine(DestinationFolder, "ship");
|
||||||
|
break;
|
||||||
|
case PackageCategory.NoShip:
|
||||||
|
destDir = Path.Combine(DestinationFolder, "noship");
|
||||||
|
break;
|
||||||
|
case PackageCategory.ShipOob:
|
||||||
|
destDir = Path.Combine(DestinationFolder, "shipoob");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.CreateDirectory(destDir);
|
||||||
|
|
||||||
|
var destFile = Path.Combine(destDir, Path.GetFileName(file.ItemSpec));
|
||||||
|
|
||||||
|
Log.LogMessage($"Copying {file.ItemSpec} to {destFile}");
|
||||||
|
|
||||||
|
File.Copy(file.ItemSpec, destFile);
|
||||||
|
expectedPackages.Remove(identity.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedPackages.Count != 0)
|
||||||
|
{
|
||||||
|
var error = new StringBuilder();
|
||||||
|
foreach (var key in expectedPackages.Keys)
|
||||||
|
{
|
||||||
|
error.Append(" - ").AppendLine(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.LogError($"Expected the following packages, but they were not found:" + error.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ namespace RepoTasks
|
||||||
var root = new XElement("Project", props, items);
|
var root = new XElement("Project", props, items);
|
||||||
var doc = new XDocument(root);
|
var doc = new XDocument(root);
|
||||||
|
|
||||||
if (RestoreAdditionalSources.Length > 0)
|
if (RestoreAdditionalSources?.Length > 0)
|
||||||
{
|
{
|
||||||
var sources = RestoreAdditionalSources.Aggregate("$(RestoreAdditionalProjectSources)", (sum, piece) => sum + ";" + piece.ItemSpec);
|
var sources = RestoreAdditionalSources.Aggregate("$(RestoreAdditionalProjectSources)", (sum, piece) => sum + ";" + piece.ItemSpec);
|
||||||
props.Add(new XElement("RestoreAdditionalProjectSources", sources));
|
props.Add(new XElement("RestoreAdditionalProjectSources", sources));
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NuGet.Frameworks;
|
using NuGet.Frameworks;
|
||||||
|
using NuGet.Packaging;
|
||||||
using NuGet.Versioning;
|
using NuGet.Versioning;
|
||||||
|
|
||||||
namespace RepoTasks.ProjectModel
|
namespace RepoTasks.ProjectModel
|
||||||
|
|
@ -12,8 +13,8 @@ namespace RepoTasks.ProjectModel
|
||||||
internal class PackageInfo
|
internal class PackageInfo
|
||||||
{
|
{
|
||||||
public PackageInfo(string id,
|
public PackageInfo(string id,
|
||||||
string version,
|
NuGetVersion version,
|
||||||
IReadOnlyList<NuGetFramework> frameworks,
|
IReadOnlyList<PackageDependencyGroup> dependencyGroups,
|
||||||
string source,
|
string source,
|
||||||
string packageType = "Dependency")
|
string packageType = "Dependency")
|
||||||
{
|
{
|
||||||
|
|
@ -22,16 +23,11 @@ namespace RepoTasks.ProjectModel
|
||||||
throw new ArgumentException(nameof(id));
|
throw new ArgumentException(nameof(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(version))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(nameof(version));
|
|
||||||
}
|
|
||||||
|
|
||||||
Id = id;
|
Id = id;
|
||||||
Version = NuGetVersion.Parse(version);
|
Version = version ?? throw new ArgumentNullException(nameof(version));
|
||||||
Frameworks = frameworks;
|
|
||||||
PackageType = packageType;
|
PackageType = packageType;
|
||||||
Source = source;
|
Source = source;
|
||||||
|
DependencyGroups = dependencyGroups ?? Array.Empty<PackageDependencyGroup>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
|
|
@ -41,6 +37,6 @@ namespace RepoTasks.ProjectModel
|
||||||
/// Can be a https feed or a file path. May be null.
|
/// Can be a https feed or a file path. May be null.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Source { get; }
|
public string Source { get; }
|
||||||
public IReadOnlyList<NuGetFramework> Frameworks { get; }
|
public IReadOnlyList<PackageDependencyGroup> DependencyGroups { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<UsingTask TaskName="RepoTasks.AnalyzeBuildGraph" AssemblyFile="$(_RepoTaskAssembly)" />
|
<UsingTask TaskName="RepoTasks.AnalyzeBuildGraph" AssemblyFile="$(_RepoTaskAssembly)" />
|
||||||
|
<UsingTask TaskName="RepoTasks.CopyPackagesToSplitFolders" AssemblyFile="$(_RepoTaskAssembly)" />
|
||||||
<UsingTask TaskName="RepoTasks.GenerateLineup" AssemblyFile="$(_RepoTaskAssembly)" />
|
<UsingTask TaskName="RepoTasks.GenerateLineup" AssemblyFile="$(_RepoTaskAssembly)" />
|
||||||
|
<UsingTask TaskName="RepoTasks.VerifyCoherentVersions" AssemblyFile="$(_RepoTaskAssembly)" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NuGet.Frameworks;
|
using NuGet.Frameworks;
|
||||||
|
using NuGet.Packaging;
|
||||||
|
using NuGet.Packaging.Core;
|
||||||
|
using NuGet.Versioning;
|
||||||
using Microsoft.Build.Framework;
|
using Microsoft.Build.Framework;
|
||||||
using RepoTasks.ProjectModel;
|
using RepoTasks.ProjectModel;
|
||||||
|
|
||||||
|
|
@ -50,10 +53,10 @@ namespace RepoTasks.Utilities
|
||||||
{
|
{
|
||||||
return new PackageInfo(
|
return new PackageInfo(
|
||||||
item.GetMetadata("PackageId"),
|
item.GetMetadata("PackageId"),
|
||||||
item.GetMetadata("Version"),
|
NuGetVersion.Parse(item.GetMetadata("Version")),
|
||||||
string.IsNullOrEmpty(item.GetMetadata("TargetFramework"))
|
string.IsNullOrEmpty(item.GetMetadata("TargetFramework"))
|
||||||
? MSBuildListSplitter.SplitItemList(item.GetMetadata("TargetFramework")).Select(s => NuGetFramework.Parse(s)).ToArray()
|
? MSBuildListSplitter.SplitItemList(item.GetMetadata("TargetFramework")).Select(s => new PackageDependencyGroup(NuGetFramework.Parse(s), Array.Empty<PackageDependency>())).ToArray()
|
||||||
: new [] { NuGetFramework.Parse(item.GetMetadata("TargetFramework")) },
|
: new [] { new PackageDependencyGroup(NuGetFramework.Parse(item.GetMetadata("TargetFramework")), Array.Empty<PackageDependency>()) },
|
||||||
Path.GetDirectoryName(item.ItemSpec),
|
Path.GetDirectoryName(item.ItemSpec),
|
||||||
item.GetMetadata("PackageType"));
|
item.GetMetadata("PackageType"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
namespace RepoTasks.Utilities
|
||||||
|
{
|
||||||
|
public enum PackageCategory
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Shipping,
|
||||||
|
NoShip,
|
||||||
|
ShipOob
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// 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.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
|
||||||
|
namespace RepoTasks.Utilities
|
||||||
|
{
|
||||||
|
public class PackageCollection
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, PackageCategory> _packages = new Dictionary<string, PackageCategory>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
private PackageCollection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetCategory(string packageId, out PackageCategory category) => _packages.TryGetValue(packageId, out category);
|
||||||
|
|
||||||
|
public void Remove(string packageId) => _packages.Remove(packageId);
|
||||||
|
|
||||||
|
public int Count => _packages.Count;
|
||||||
|
|
||||||
|
public IEnumerable<string> Keys => _packages.Keys;
|
||||||
|
|
||||||
|
public static PackageCollection FromItemGroup(ITaskItem[] items)
|
||||||
|
{
|
||||||
|
var list = new PackageCollection();
|
||||||
|
if (items == null)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
PackageCategory category;
|
||||||
|
switch (item.GetMetadata("Category")?.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "ship":
|
||||||
|
category = PackageCategory.Shipping;
|
||||||
|
break;
|
||||||
|
case "noship":
|
||||||
|
category = PackageCategory.NoShip;
|
||||||
|
break;
|
||||||
|
case "shipoob":
|
||||||
|
category = PackageCategory.ShipOob;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
category = PackageCategory.Unknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list._packages.ContainsKey(item.ItemSpec))
|
||||||
|
{
|
||||||
|
throw new InvalidDataException($"Duplicate package id detected: {item.ItemSpec}");
|
||||||
|
}
|
||||||
|
|
||||||
|
list._packages.Add(item.ItemSpec, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
// 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.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
using NuGet.Packaging;
|
||||||
|
using NuGet.Packaging.Core;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
using RepoTasks.ProjectModel;
|
||||||
|
using RepoTasks.Utilities;
|
||||||
|
|
||||||
|
namespace RepoTasks
|
||||||
|
{
|
||||||
|
public class VerifyCoherentVersions : Microsoft.Build.Utilities.Task
|
||||||
|
{
|
||||||
|
public ITaskItem[] PackageFiles { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
var packageLookup = new Dictionary<string, PackageInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var file in PackageFiles)
|
||||||
|
{
|
||||||
|
PackageInfo package;
|
||||||
|
using (var reader = new PackageArchiveReader(file.ItemSpec))
|
||||||
|
{
|
||||||
|
var identity = reader.GetIdentity();
|
||||||
|
var metadata = new PackageBuilder(reader.GetNuspec(), basePath: null);
|
||||||
|
package = new PackageInfo(identity.Id, identity.Version,
|
||||||
|
source: Path.GetDirectoryName(file.ItemSpec),
|
||||||
|
dependencyGroups: metadata.DependencyGroups.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packageLookup.TryGetValue(package.Id, out var existingPackage))
|
||||||
|
{
|
||||||
|
throw new Exception("Multiple copies of the following package were found: " +
|
||||||
|
Environment.NewLine +
|
||||||
|
existingPackage +
|
||||||
|
Environment.NewLine +
|
||||||
|
package);
|
||||||
|
}
|
||||||
|
|
||||||
|
packageLookup[package.Id] = package;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dependencyIssues = new List<DependencyWithIssue>();
|
||||||
|
foreach (var packageInfo in packageLookup.Values)
|
||||||
|
{
|
||||||
|
dependencyIssues.AddRange(Visit(packageLookup, packageInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
var success = true;
|
||||||
|
foreach (var mismatch in dependencyIssues)
|
||||||
|
{
|
||||||
|
var message = $"{mismatch.Info.Id} depends on {mismatch.Dependency.Id} " +
|
||||||
|
$"v{mismatch.Dependency.VersionRange} ({mismatch.TargetFramework}) when the latest build is v{mismatch.Info.Version}.";
|
||||||
|
Log.LogError(message);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.LogMessage(MessageImportance.High, $"Verified {PackageFiles.Length} package(s) have coherent versions");
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DependencyWithIssue
|
||||||
|
{
|
||||||
|
public PackageDependency Dependency { get; set; }
|
||||||
|
public PackageInfo Info { get; set; }
|
||||||
|
public NuGetFramework TargetFramework { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<DependencyWithIssue> Visit(IDictionary<string, PackageInfo> packageLookup, PackageInfo packageInfo)
|
||||||
|
{
|
||||||
|
Log.LogMessage(MessageImportance.Low, $"Processing package {packageInfo.Id}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var issues = new List<DependencyWithIssue>();
|
||||||
|
foreach (var dependencySet in packageInfo.DependencyGroups)
|
||||||
|
{
|
||||||
|
// If the package doens't target any frameworks, just accept it
|
||||||
|
if (dependencySet.TargetFramework == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var dependency in dependencySet.Packages)
|
||||||
|
{
|
||||||
|
if (!packageLookup.TryGetValue(dependency.Id, out var dependencyPackageInfo))
|
||||||
|
{
|
||||||
|
// External dependency
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dependencyPackageInfo.Version != dependency.VersionRange.MinVersion)
|
||||||
|
{
|
||||||
|
// For any dependency in the universe
|
||||||
|
// Add a mismatch if the min version doesn't work out
|
||||||
|
// (we only really care about >= minVersion)
|
||||||
|
issues.Add(new DependencyWithIssue
|
||||||
|
{
|
||||||
|
Dependency = dependency,
|
||||||
|
TargetFramework = dependencySet.TargetFramework,
|
||||||
|
Info = dependencyPackageInfo
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Log.LogError($"Unable to verify package {packageInfo.Id}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue