diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a3196b..683b1ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,46 @@ on: - "*.*.*" jobs: + # Native AOT can only compile for the OS/arch it runs on, so each leg compiles its own RID and + # packs the per-RID tool package. The coordinating build job below takes only the root package and + # the portable 'any' fallback from a plain `dotnet pack` — see generatePackages in + # build/scripts/Targets.fs. On pull requests only linux-x64 runs, to prove AOT still links; the + # other four RIDs get the same proof on every push. + # On pull requests, only linux-x64 runs, to prove AOT still links without burning the full matrix + # on packages nobody sees. All five run on push, where the packages are actually uploaded. + aot-pack: + runs-on: ${{ matrix.runner }} + name: AOT pack (${{ matrix.rid }}) + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(github.event_name == 'pull_request' + && '[{"rid":"linux-x64","runner":"ubuntu-latest"}]' + || '[{"rid":"linux-x64","runner":"ubuntu-latest"},{"rid":"linux-arm64","runner":"ubuntu-24.04-arm"},{"rid":"win-x64","runner":"windows-latest"},{"rid":"win-arm64","runner":"windows-11-arm"},{"rid":"osx-arm64","runner":"macos-latest"}]') }} + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 1 + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.x + + - run: dotnet pack src/assembly-differ/assembly-differ.csproj -c Release -r ${{ matrix.rid }} -o build/output + name: Pack native-AOT tool for ${{ matrix.rid }} + shell: bash + + - name: Upload per-RID package + if: github.event_name == 'push' + uses: actions/upload-artifact@v4 + with: + name: nupkg-${{ matrix.rid }} + path: build/output/*.nupkg + if-no-files-found: error + build: runs-on: ubuntu-latest + needs: aot-pack steps: - uses: actions/checkout@v5 with: @@ -38,7 +76,15 @@ jobs: - run: ./build.sh generatepackages -s true name: Generate local nuget packages - + + - name: Download per-RID AOT packages + if: github.event_name == 'push' + uses: actions/download-artifact@v4 + with: + pattern: nupkg-* + path: build/output + merge-multiple: true + # - run: ./build.sh validatepackages -s true # name: "validate *.npkg files that were created" diff --git a/README.md b/README.md index 54bad1d..5581a92 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ Distributed as a .NET tool so install using the following dotnet tool install assembly-differ ``` +On Linux, Windows and macOS/arm64, this resolves to a self-contained native-AOT executable — no +shared .NET runtime required, and no first-run JIT warmup. Everywhere else, it falls back to a +framework-dependent build (requires the .NET runtime the tool targets to already be installed). + ## Run ```bat @@ -32,7 +36,7 @@ You can omit `dotnet` if you install this as a global tool to see the supported Assembly Providers and outputs: ```bat -assembly-differ [Options] +assembly-differ diff [Options] Supported Assembly Providers: @@ -43,32 +47,45 @@ Supported Assembly Providers: github|/||| Options: - -t, --target=VALUE the assembly targets. Defaults to *all* assemblies - located by the provider - -f, --format=VALUE the format of the diff output. Supported formats - are xml, markdown, asciidoc. Defaults to xml - -o, --output=VALUE the output directory. Defaults to current directory - -h, -?, --help show this message and exit + -t, --target the assembly targets. Defaults to *all* assemblies + located by the provider. May be given more than once. + -f, --format the format of the diff output. Supported formats + are xml, markdown, asciidoc. Defaults to xml + -o, --output the output directory or file name. If not specified only prints to console + -p, --prevent-change fail if the change detected is higher than specified: + none, patch, minor, or major. Defaults to none + -a, --allow-empty-previous-nuget don't fail when no previous nuget package could be found to diff against + -h, --help show this message and exit ``` +> [!NOTE] +> Starting from `1.0.0`, the tool moved off `Mono.Options` onto [`Nullean.Argh`](https://github.com/nullean/argh) +> for CLI parsing, which introduces an explicit `diff` subcommand alongside the bare invocation. `diff` is +> optional as long as an option comes before the two provider arguments (e.g. +> `assembly-differ --target NEST "nuget|..." "nuget|..."`); providers as the very first arguments +> (`assembly-differ "nuget|..." "nuget|..."`) still need the explicit subcommand +> (`assembly-differ diff "nuget|..." "nuget|..."`), since the CLI parser resolves a bare leading argument +> as a subcommand name first. `--target` also moves from a single comma/pipe-separated value to a +> repeatable flag (`--target a --target b` instead of `--target a,b`). + #### Examples: Diff between two local assemblies: ```bat -dotnet assembly-differ "assembly|C:\6.1.0\Nest.dll" "assembly|C:\6.2.0\Nest.dll" +dotnet assembly-differ diff "assembly|C:\6.1.0\Nest.dll" "assembly|C:\6.2.0\Nest.dll" ``` Diff between all assemblies in directories, matched by name: ```bat -dotnet assembly-differ "directory|C:\6.1.0" "directory|C:\6.2.0" +dotnet assembly-differ diff "directory|C:\6.1.0" "directory|C:\6.2.0" ``` Diff NuGet packages: ```bat -dotnet assembly-differ "nuget|NEST|6.1.0|net46" "nuget|NEST|6.2.0|net46" +dotnet assembly-differ diff "nuget|NEST|6.1.0|net46" "nuget|NEST|6.2.0|net46" ``` Diff Previous NuGet packages: @@ -77,16 +94,16 @@ Imagine you want to release `6.2.0` and want to diff with whatever is the latest `previous-nuget` will do the heavy lifting of finding that previous release ```bat -dotnet assembly-differ "previous-nuget|NEST|6.2.0|net46" "directory|C:\6.2.0" +dotnet assembly-differ diff "previous-nuget|NEST|6.2.0|net46" "directory|C:\6.2.0" ``` Diff GitHub commits: ```bat -dotnet assembly-differ "github|elastic/elasticsearch-net|6.1.0|cmd /C call build.bat skiptests skipdocs|build\output\Nest\net46" "github|elastic/elasticsearch-net|6.2.0|cmd /C call build.bat skiptests skipdocs|build\output\Nest\net46" +dotnet assembly-differ diff "github|elastic/elasticsearch-net|6.1.0|cmd /C call build.bat skiptests skipdocs|build\output\Nest\net46" "github|elastic/elasticsearch-net|6.2.0|cmd /C call build.bat skiptests skipdocs|build\output\Nest\net46" ``` -Any of the above can be mixed. For example, to compare GitHub HEAD against last NuGet package, and output in Markdown +Any of the above can be mixed. For example, to compare GitHub HEAD against last NuGet package, and output in Markdown — note that leading with an option lets you drop the `diff` subcommand: ```bat dotnet assembly-differ --format markdown "nuget|NEST|6.2.0|net46" "github|elastic/elasticsearch-net|HEAD|cmd /C call build.bat skiptests skipdocs|build\output\Nest\net46" @@ -98,7 +115,7 @@ You can run the tool locally against itself using the following during developme ```bat dotnet build -c Release -dotnet run --framework netcoreapp3.1 -- "previous-nuget|assembly-differ|0.9.1|netcoreapp3.1" "directory|bin/Release/netcoreapp3.1" --target=assembly-differ +dotnet run -f net10.0 -- diff "previous-nuget|assembly-differ|0.9.1|net10.0" "directory|bin/Release/net10.0" --target assembly-differ ``` # FUTURE PLANS diff --git a/build/scripts/Paths.fs b/build/scripts/Paths.fs index 457f7be..f348e71 100644 --- a/build/scripts/Paths.fs +++ b/build/scripts/Paths.fs @@ -6,6 +6,14 @@ open System.IO let ToolName = "assembly-differ" let Repository = sprintf "nullean/%s" ToolName +/// The RIDs we ship native-AOT tool packages for. AOT compilation requires a matching +/// OS/arch, so CI packs one RID per runner; this list only documents the set. +let AotRuntimeIdentifiers = ["linux-x64"; "linux-arm64"; "win-x64"; "win-arm64"; "osx-arm64"] + +/// Must mirror assembly-differ.csproj's TargetFrameworks. Used to patch the signed managed dll back +/// into the packed 'any' fallback for every TFM it ships — see fixAnyPackageSigning in Targets.fs. +let ManagedTargetFrameworks = ["net8.0"; "net10.0"] + let Root = let mutable dir = DirectoryInfo(".") while dir.GetFiles("*.slnx").Length = 0 do dir <- dir.Parent diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index aefe64a..1cec9a4 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -3,6 +3,7 @@ module Targets open Argu open System open System.IO +open System.IO.Compression open Bullseye open CommandLine open Fake.Tools.Git @@ -36,13 +37,62 @@ let private pristineCheck (arguments:ParseResults) = () //failwithf "The checkout folder has pending changes, aborting" +let private isPerRidPackage (name: string) = + Paths.AotRuntimeIdentifiers |> List.exists (fun rid -> name.Contains(sprintf ".%s." rid)) + +/// `dotnet pack`'s RID-aware tool-packaging path (used once RuntimeIdentifiers is declared) copies +/// the *unsigned* obj/ build of this project's own assembly into the portable 'any' package, even +/// though the normal bin/ output is correctly strong-name signed — a long-standing obj-vs-bin mixup +/// in `dotnet pack` (see https://github.com/dotnet/sdk/issues/20197) that resurfaces here. Patched in +/// place after packing by swapping in the signed bin/ copies for every TFM the 'any' package ships. +let private fixAnyPackageSigning (anyPackagePath: string) = + use archive = ZipFile.Open(anyPackagePath, ZipArchiveMode.Update) + for tfm in Paths.ManagedTargetFrameworks do + let entryName = sprintf "tools/%s/any/%s.dll" tfm Paths.ToolName + let signedDll = Path.Combine(Paths.ToolProject.FullName, "bin", "Release", tfm, sprintf "%s.dll" Paths.ToolName) + match archive.GetEntry(entryName), File.Exists signedDll with + | null, _ | _, false -> () + | entry, true -> + entry.Delete() + let newEntry = archive.CreateEntry(entryName) + use entryStream = newEntry.Open() + use fileStream = File.OpenRead(signedDll) + fileStream.CopyTo(entryStream) + let private generatePackages (arguments:ParseResults) = let output = Paths.RootRelative Paths.Output.FullName - exec "dotnet" ["pack"; "-c"; "Release"; "-o"; output] |> ignore - + if not Paths.Output.Exists then Paths.Output.Create() + + // A plain `dotnet pack` emits the root package (whose DotnetToolSettings.xml v2 maps each RID to + // its own package) AND a package per RID — but native AOT can only compile for the machine it + // runs on, so those per-RID outputs from a single machine are self-contained MANAGED builds, + // silently missing the AOT compilation. We therefore keep only the root and the portable 'any' + // fallback here, and take the real per-RID packages from the CI matrix, where each is compiled + // on a matching runner (see aot-pack in .github/workflows/ci.yml). + let staging = Paths.RootRelative <| Path.Combine(Paths.Output.FullName, "..", "differ-staging") + if Directory.Exists staging then Directory.Delete(staging, true) + exec "dotnet" ["pack"; sprintf "src/%s/%s.csproj" Paths.ToolName Paths.ToolName; "-c"; "Release"; "-o"; staging] |> ignore + + DirectoryInfo(staging).GetFiles("*.nupkg") + |> Seq.filter (fun f -> not (isPerRidPackage f.Name)) + |> Seq.iter (fun f -> + let destination = Path.Combine(Paths.Output.FullName, f.Name) + printfn "keeping %s" f.Name + f.CopyTo(destination, true) |> ignore + if f.Name.Contains(sprintf "%s.any." Paths.ToolName) then + fixAnyPackageSigning destination) + + Directory.Delete(staging, true) + let private validatePackages (arguments:ParseResults) = let nugetPackage = - let p = Paths.Output.GetFiles "*.nupkg" |> Seq.sortByDescending(fun f -> f.CreationTimeUtc) |> Seq.head + // Only the 'any' package carries a signed managed assembly to check: the root package is + // just a DotnetToolSettings.xml pointer with no dll of its own, and the per-RID AOT packages + // hold a native binary with no managed identity either. + let p = + Paths.Output.GetFiles "*.nupkg" + |> Seq.filter (fun f -> f.Name.Contains(sprintf "%s.any." Paths.ToolName)) + |> Seq.sortByDescending(fun f -> f.CreationTimeUtc) |> Seq.head Paths.RootRelative p.FullName exec "dotnet" ["nupkg-validator"; nugetPackage; "-v"; currentVersionInformational.Value; "-a"; Paths.ToolName; "-k"; "96c599bbe3e70f5d"; "--allow-roll-forward"] |> ignore @@ -53,6 +103,7 @@ let private generateApiChanges (arguments:ParseResults) = let dotnetRun =[ "run"; "-c"; "Release"; "-f"; "net10.0"; "--project"; project] let args = [ + "diff"; sprintf "previous-nuget|%s|%s|net8.0" Paths.ToolName currentVersion; sprintf "directory|src/%s/bin/Release/net10.0" Paths.ToolName; "--target"; Paths.ToolName; "-f"; "github-comment"; "--output"; output diff --git a/src/assembly-differ/DiffCommand.cs b/src/assembly-differ/DiffCommand.cs new file mode 100644 index 0000000..f83f99a --- /dev/null +++ b/src/assembly-differ/DiffCommand.cs @@ -0,0 +1,152 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Differ.Exporters; +using Differ.Providers; +using Differ.Providers.GitHub; +using Differ.Providers.NuGet; +using Differ.Providers.PreviousNuGet; +using JustAssembly.Core; +using Nullean.Argh; + +namespace Differ +{ + internal sealed class DiffCommands + { + /// + /// Compares and diffs assemblies from different sources, outputting differences in XML, + /// Markdown, or AsciiDoc. + /// + /// + /// Old assembly provider: assembly|<path>, directory|<path>, nuget|<id>|<version>|[tfm], + /// previous-nuget|<id>|<version>|[tfm], or github|<owner/repo>|<commit>|<build command>|<relative output path>. + /// + /// New assembly provider, same format as . + /// + /// -t, --target, The assembly targets. Defaults to *all* assemblies located by the provider. May be + /// given more than once. + /// + /// -f, --format, The format of the diff output: xml, markdown, or asciidoc. + /// -o, --output, The output directory or file name. If not specified only prints to console. + /// + /// -p, --prevent-change, Fail if the change detected is higher than specified: none, patch, minor, + /// or major. Defaults to none, which never fails. + /// + /// + /// -a, --allow-empty-previous-nuget, Don't fail when no previous nuget package could be found to diff against. + /// + [DefaultCommand] + [CommandName("diff")] + public int Diff( + [Argument] string first, + [Argument] string second, + List? target = null, + string format = "xml", + string? output = null, + string preventChange = "none", + bool allowEmptyPreviousNuget = false) + { + // Enum-typed parameters with a non-zero default member fail to compile against this + // version of Argh (https://github.com/nullean/argh/issues/75), so `--prevent-change` stays + // a string and is parsed manually here instead. + var preventChangeValue = Enum.Parse(preventChange, true); + var providers = new AssemblyProviderFactoryCollection( + new AssemblyProviderFactory(), + new DirectoryAssemblyProviderFactory(), + new NuGetAssemblyProviderFactory(new Providers.NuGet.NuGet()), + new PreviousNuGetAssemblyProviderFactory(new PreviousNugetLocator()), + new GitHubAssemblyProviderFactory(new Git(Environment.GetEnvironmentVariable("GIT"))) + ); + + var exporters = new ExporterCollection( + new XmlExporter(), + new MarkdownExporter(), + new AsciiDocExporter(), + new GitHubActionCommentExporter() + ); + + var outputWriterFactory = new OutputWriterFactory(output); + var targets = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var t in target ?? []) + foreach (var part in t.Split(',', '|')) + if (!string.IsNullOrEmpty(part)) + targets.Add(part); + + try + { + var firstProvider = providers.GetProvider(first); + var secondProvider = providers.GetProvider(second); + var firstProviderName = providers.GetProviderName(first); + var secondProviderName = providers.GetProviderName(second); + + if (!exporters.Contains(format)) + throw new Exception($"No exporter for format '{format}'"); + + var exporter = exporters[format]; + + var firstAssemblies = firstProvider.GetAssemblies(targets).ToList(); + var secondAssemblies = secondProvider.GetAssemblies(targets).ToList(); + var pairs = CreateAssemblyPairs(firstAssemblies, secondAssemblies).ToList(); + + if (!pairs.Any()) + { + if (allowEmptyPreviousNuget && + (firstProviderName == "previous-nuget" || secondProviderName == "previous-nuget")) + { + Console.WriteLine($"[diff] No previous nuget found for: {firstProviderName}"); + Console.WriteLine($"[diff] {firstProvider.GetType().Name}: {firstAssemblies.Count} assemblies"); + Console.WriteLine($"[diff] {secondProvider.GetType().Name}: {secondAssemblies.Count} assemblies"); + Console.WriteLine($"[diff]"); + Console.WriteLine($"[diff] NOT treated as an error because --allow-empty-previous-nuget was set"); + return 0; + } + + Console.Error.WriteLine($"[diff] Unable to create diff!"); + Console.Error.WriteLine($"[diff] {firstProvider.GetType().Name}: {firstAssemblies.Count} assemblies"); + Console.Error.WriteLine($"[diff] {secondProvider.GetType().Name}: {secondAssemblies.Count} assemblies"); + return 1; + } + + var result = new AllComparisonResults(pairs, preventChangeValue); + foreach (var assemblyPair in pairs) + { + assemblyPair.Diff = + APIDiffHelper.GetAPIDifferences(assemblyPair.First.FullName, assemblyPair.Second.FullName); + + if (assemblyPair.Diff == null) + { + Console.WriteLine($"[diff] No diff between {assemblyPair.First.FullName} and {assemblyPair.Second.FullName}"); + continue; + } + Console.WriteLine($"[diff] Difference found: {firstProvider.GetType().Name}:{assemblyPair.First.Name} and {secondProvider.GetType().Name}:{assemblyPair.Second.Name}"); + + if (exporter is IAssemblyComparisonExporter c) + c.Export(assemblyPair, outputWriterFactory); + } + if (exporter is IAllComparisonResultsExporter allExporter) + allExporter.Export(result, outputWriterFactory); + + if (preventChangeValue > SuggestedVersionChange.None && result.SuggestedVersionChange >= preventChangeValue) + { + Console.Error.WriteLine($"[diff] Needed version change '{result.SuggestedVersionChange}' exceeds or equals configured lock: '{preventChangeValue}"); + return 4; + } + Console.WriteLine($"[diff] Suggested version change: {result.SuggestedVersionChange}"); + } + catch (Exception e) + { + Console.Error.WriteLine(e); + return 1; + } + return 0; + } + + private static IEnumerable CreateAssemblyPairs(IEnumerable first, IEnumerable second) => + first.Join(second, + f => f.Name.ToUpperInvariant(), + f => f.Name.ToUpperInvariant(), + (f1, f2) => new AssemblyComparison(f1, f2)); + } +} diff --git a/src/assembly-differ/Program.cs b/src/assembly-differ/Program.cs index 1593bbf..742ea01 100644 --- a/src/assembly-differ/Program.cs +++ b/src/assembly-differ/Program.cs @@ -1,188 +1,7 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection.Metadata; -using Differ.Exporters; -using Differ.Providers; -using Differ.Providers.GitHub; -using Differ.Providers.NuGet; -using Differ.Providers.PreviousNuGet; -using JustAssembly.Core; -using Mono.Options; +using Differ; +using Nullean.Argh; -namespace Differ -{ - internal static class Program - { - private static string _format = "xml"; - private static bool _help; - private static OutputWriterFactory _output = new OutputWriterFactory(null); - private static SuggestedVersionChange _preventChange = SuggestedVersionChange.None; - private static bool _allowEmptyPreviousNuget = false; +var app = new ArghApp(); +app.MapAndRootAlias(); - private static HashSet Targets { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); - - private static int Main(string[] args) - { - var providers = new AssemblyProviderFactoryCollection( - new AssemblyProviderFactory(), - new DirectoryAssemblyProviderFactory(), - new NuGetAssemblyProviderFactory(new Providers.NuGet.NuGet()), - new PreviousNuGetAssemblyProviderFactory(new PreviousNugetLocator()), - new GitHubAssemblyProviderFactory(new Git(Environment.GetEnvironmentVariable("GIT"))) - ); - - var exporters = new ExporterCollection( - new XmlExporter(), - new MarkdownExporter(), - new AsciiDocExporter(), - new GitHubActionCommentExporter() - ); - - var options = new OptionSet - { - {"t|target=", "the assembly targets. Defaults to *all* assemblies located by the provider", AddTarget }, - {"f|format=", $"the format of the diff output. Supported formats are {exporters.SupportedFormats}. Defaults to {_format}", f => _format = f}, - {"o|output=", "the output directory or file name. If not specified only prints to console", o => _output = new OutputWriterFactory(o)}, - {"p|prevent-change=", "Fail if the change detected is higher then specified: none|patch|minor|major. Defaults to `none` which will never fail.", - c => _preventChange = Enum.Parse(c, true)}, - {"a|allow-empty-previous-nuget=", "", - n => _allowEmptyPreviousNuget = n != null}, - {"h|?|help", "show this message and exit", h => _help = h != null}, - }; - - if (_help) - { - ShowHelp(options, providers); - return 2; - } - - - if (args.Length < 2) - { - ShowHelp(options, providers); - return 2; - } - - List unflaggedArgs; - try - { - unflaggedArgs = options.Parse(args); - } - catch (OptionException e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Try 'Differ.exe --help' for more information."); - Environment.ExitCode = 1; - return 2; - } - - try - { - var firstProvider = providers.GetProvider(unflaggedArgs[0]); - var secondProvider = providers.GetProvider(unflaggedArgs[1]); - var firstProviderName = providers.GetProviderName(unflaggedArgs[0]); - var secondProviderName = providers.GetProviderName(unflaggedArgs[1]); - - if (!exporters.Contains(_format)) - throw new Exception($"No exporter for format '{_format}'"); - - var exporter = exporters[_format]; - - var first = firstProvider.GetAssemblies(Targets).ToList(); - var second = secondProvider.GetAssemblies(Targets).ToList(); - var pairs = CreateAssemblyPairs(first, second).ToList(); - - if (!pairs.Any()) - { - if (_allowEmptyPreviousNuget && - (firstProviderName == "previous-nuget" || secondProviderName == "previous-nuget")) - { - Console.WriteLine($"[diff] No previous nuget found for: {firstProviderName}"); - Console.WriteLine($"[diff] {firstProvider.GetType().Name}: {first.Count()} assemblies"); - Console.WriteLine($"[diff] {secondProvider.GetType().Name}: {second.Count()} assemblies"); - Console.WriteLine($"[diff]"); - Console.WriteLine($"[diff] NOT treated as an error because --allow-empty-previous-nuget was set"); - return 0; - - } - - Console.Error.WriteLine($"[diff] Unable to create diff!"); - Console.Error.WriteLine($"[diff] {firstProvider.GetType().Name}: {first.Count()} assemblies"); - Console.Error.WriteLine($"[diff] {secondProvider.GetType().Name}: {second.Count()} assemblies"); - return 1; - } - - var result = new AllComparisonResults(pairs, _preventChange); - foreach (var assemblyPair in pairs) - { - assemblyPair.Diff = - APIDiffHelper.GetAPIDifferences(assemblyPair.First.FullName, assemblyPair.Second.FullName); - - if (assemblyPair.Diff == null) - { - Console.WriteLine($"[diff] No diff between {assemblyPair.First.FullName} and {assemblyPair.Second.FullName}"); - continue; - } - Console.WriteLine($"[diff] Difference found: {firstProvider.GetType().Name}:{assemblyPair.First.Name} and {secondProvider.GetType().Name}:{assemblyPair.Second.Name}"); - - if (exporter is IAssemblyComparisonExporter c) - c.Export(assemblyPair, _output); - } - if (exporter is IAllComparisonResultsExporter allExporter) - allExporter.Export(result, _output); - - if (_preventChange > SuggestedVersionChange.None && result.SuggestedVersionChange >= _preventChange) - { - Console.Error.WriteLine($"[diff] Needed version change '{result.SuggestedVersionChange}' exceeds or equals configured lock: '{_preventChange}"); - return 4; - } - Console.WriteLine($"[diff] Suggested version change: {result.SuggestedVersionChange}"); - - } - catch (Exception e) - { - Console.Error.WriteLine(e); - return 1; - } - return 0; - } - - private static IEnumerable CreateAssemblyPairs(IEnumerable first, IEnumerable second) => - first.Join(second, - f => f.Name.ToUpperInvariant(), - f => f.Name.ToUpperInvariant(), - (f1, f2) => new AssemblyComparison(f1, f2)); - - private static void AddTarget(string input) - { - if (string.IsNullOrEmpty(input)) - return; - - var parts = input.Split(',', '|'); - foreach (var part in parts) - Targets.Add(part); - } - - private static void ShowHelp(OptionSet options, AssemblyProviderFactoryCollection providerFactoryCollection) - { - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine("Differ"); - Console.WriteLine("------"); - Console.WriteLine("Diffs assemblies from different sources"); - Console.WriteLine(); - Console.WriteLine("Differ.exe [Options]"); - Console.WriteLine(); - Console.WriteLine("Supported Assembly Providers:"); - Console.WriteLine(); - foreach (var providerFactory in providerFactoryCollection) - Console.WriteLine($" {providerFactory.Format}"); - Console.WriteLine(); - Console.WriteLine("Options:"); - options.WriteOptionDescriptions(Console.Out); - Console.WriteLine(); - Console.ResetColor(); - } - } -} +return await app.RunAsync(args); diff --git a/src/assembly-differ/assembly-differ.csproj b/src/assembly-differ/assembly-differ.csproj index 1a4054f..0963c9c 100644 --- a/src/assembly-differ/assembly-differ.csproj +++ b/src/assembly-differ/assembly-differ.csproj @@ -2,6 +2,7 @@ Exe net8.0;net10.0 + latest assembly-differ AssemblyDiffer true @@ -16,8 +17,32 @@ https://github.com/nullean/assembly-differ/releases assembly-differ: a dotnet tool to diff assemblies Diff assemblies and nuget packages + + + linux-x64;linux-arm64;win-x64;win-arm64;osx-arm64;any + + + + + true + true + true + false + + + + + + nuget-icon.png @@ -27,15 +52,14 @@ - - + - - - - - - + + + + + +