From eec2497cedc89cc2376c15b7e6d7fa4b69b08cfc Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Thu, 20 Aug 2026 14:38:21 -0700 Subject: [PATCH 1/3] fix(packaging): align dependencies by target framework Multi-target the Accordant runtime libraries for netstandard2.0, net8.0, and net10.0, and package matching dependency trains for each native target. Add isolated package-consumer validation for net8 and net10 which fails on MSB3277 and verifies the selected assets and dependency groups. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 4 + Accordant.Choose/Accordant.Choose.csproj | 2 +- .../Accordant.Invariant.csproj | 2 +- .../Accordant.Operations.Http.csproj | 2 +- .../Accordant.Operations.csproj | 2 +- Accordant/Accordant.csproj | 2 +- Directory.Packages.props | 9 +- .../Net10Consumer/Library/AccordantTypes.cs | 8 + .../Library/ConsumerLibrary.csproj | 12 + .../Net10Consumer/Net10Consumer.csproj | 19 ++ .../Consumers/Net10Consumer/Program.cs | 4 + .../SharedFrameworkLibrary/JsonTypes.cs | 8 + .../SharedFrameworkLibrary.csproj | 8 + .../Net8Consumer/Library/AccordantTypes.cs | 8 + .../Library/ConsumerLibrary.csproj | 12 + .../Net8Consumer/Net8Consumer.csproj | 19 ++ .../Consumers/Net8Consumer/Program.cs | 4 + .../SharedFrameworkLibrary/JsonTypes.cs | 8 + .../SharedFrameworkLibrary.csproj | 8 + .../Validate-Packages.ps1 | 217 ++++++++++++++++++ nuget/Microsoft.Accordant.Package.csproj | 11 + nuget/Microsoft.Accordant.nuspec | 34 ++- 22 files changed, 393 insertions(+), 10 deletions(-) create mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs create mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj create mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj create mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs create mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs create mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj create mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs create mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj create mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj create mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs create mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs create mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj create mode 100644 Tests/PackageCompatibility/Validate-Packages.ps1 create mode 100644 nuget/Microsoft.Accordant.Package.csproj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4b01c2..f8b75f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,5 +32,9 @@ jobs: - name: Build run: dotnet build --no-restore --configuration Release + - name: Validate package compatibility + shell: pwsh + run: ./Tests/PackageCompatibility/Validate-Packages.ps1 + - name: Test run: dotnet test --no-build --configuration Release --verbosity normal diff --git a/Accordant.Choose/Accordant.Choose.csproj b/Accordant.Choose/Accordant.Choose.csproj index b5ba547..2f0244d 100644 --- a/Accordant.Choose/Accordant.Choose.csproj +++ b/Accordant.Choose/Accordant.Choose.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;net8.0;net10.0 latest Library ../bin diff --git a/Accordant.Invariant/Accordant.Invariant.csproj b/Accordant.Invariant/Accordant.Invariant.csproj index ab79541..234f7ec 100644 --- a/Accordant.Invariant/Accordant.Invariant.csproj +++ b/Accordant.Invariant/Accordant.Invariant.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;net8.0;net10.0 latest Library ../bin diff --git a/Accordant.Operations.Http/Accordant.Operations.Http.csproj b/Accordant.Operations.Http/Accordant.Operations.Http.csproj index f75d481..bbcc3c4 100644 --- a/Accordant.Operations.Http/Accordant.Operations.Http.csproj +++ b/Accordant.Operations.Http/Accordant.Operations.Http.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;net8.0;net10.0 latest Library ../bin diff --git a/Accordant.Operations/Accordant.Operations.csproj b/Accordant.Operations/Accordant.Operations.csproj index 24a2bfd..3759c04 100644 --- a/Accordant.Operations/Accordant.Operations.csproj +++ b/Accordant.Operations/Accordant.Operations.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;net8.0;net10.0 latest Library ../bin diff --git a/Accordant/Accordant.csproj b/Accordant/Accordant.csproj index 327bc13..fa71f82 100644 --- a/Accordant/Accordant.csproj +++ b/Accordant/Accordant.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;net8.0;net10.0 latest Library ../bin diff --git a/Directory.Packages.props b/Directory.Packages.props index e86106c..81fbd1f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,9 +12,12 @@ - + + - - + + + + \ No newline at end of file diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs b/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs new file mode 100644 index 0000000..50acbe0 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs @@ -0,0 +1,8 @@ +namespace PackageCompatibility.ConsumerLibrary; + +using Microsoft.Accordant; + +public static class AccordantTypes +{ + public static string Description => $"{typeof(StateAttribute).FullName};{typeof(Spec).FullName}"; +} diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj new file mode 100644 index 0000000..47ca187 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj @@ -0,0 +1,12 @@ + + + + net10.0 + enable + + + + + + + diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj b/Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj new file mode 100644 index 0000000..2968201 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj @@ -0,0 +1,19 @@ + + + + Exe + net10.0 + enable + + + + + + + + + + + + + diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs b/Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs new file mode 100644 index 0000000..37d843b --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs @@ -0,0 +1,4 @@ +using PackageCompatibility.ConsumerLibrary; +using PackageCompatibility.SharedFrameworkLibrary; + +Console.WriteLine($"{AccordantTypes.Description};{JsonTypes.Description}"); diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs b/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs new file mode 100644 index 0000000..1e62482 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs @@ -0,0 +1,8 @@ +namespace PackageCompatibility.SharedFrameworkLibrary; + +using System.Text.Json; + +public static class JsonTypes +{ + public static string Description => typeof(JsonSerializer).Assembly.FullName!; +} diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj new file mode 100644 index 0000000..07f055d --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj @@ -0,0 +1,8 @@ + + + + net10.0 + enable + + + diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs b/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs new file mode 100644 index 0000000..50acbe0 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs @@ -0,0 +1,8 @@ +namespace PackageCompatibility.ConsumerLibrary; + +using Microsoft.Accordant; + +public static class AccordantTypes +{ + public static string Description => $"{typeof(StateAttribute).FullName};{typeof(Spec).FullName}"; +} diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj new file mode 100644 index 0000000..4826ee5 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + enable + + + + + + + diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj b/Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj new file mode 100644 index 0000000..e0e1a77 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + + + + + + + + + + + + + diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs b/Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs new file mode 100644 index 0000000..37d843b --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs @@ -0,0 +1,4 @@ +using PackageCompatibility.ConsumerLibrary; +using PackageCompatibility.SharedFrameworkLibrary; + +Console.WriteLine($"{AccordantTypes.Description};{JsonTypes.Description}"); diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs b/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs new file mode 100644 index 0000000..1e62482 --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs @@ -0,0 +1,8 @@ +namespace PackageCompatibility.SharedFrameworkLibrary; + +using System.Text.Json; + +public static class JsonTypes +{ + public static string Description => typeof(JsonSerializer).Assembly.FullName!; +} diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj new file mode 100644 index 0000000..bab0ebf --- /dev/null +++ b/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj @@ -0,0 +1,8 @@ + + + + net8.0 + enable + + + diff --git a/Tests/PackageCompatibility/Validate-Packages.ps1 b/Tests/PackageCompatibility/Validate-Packages.ps1 new file mode 100644 index 0000000..035dbff --- /dev/null +++ b/Tests/PackageCompatibility/Validate-Packages.ps1 @@ -0,0 +1,217 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +[CmdletBinding()] +param( + [string] $NuGetSource = "https://api.nuget.org/v3/index.json" +) + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +$repositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path +$nuspecPath = Join-Path $repositoryRoot "nuget\Microsoft.Accordant.nuspec" +$packageProject = Join-Path $repositoryRoot "nuget\Microsoft.Accordant.Package.csproj" +$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "accordant-package-compatibility-$([Guid]::NewGuid().ToString('N'))" +$packageDirectory = Join-Path $tempRoot "packages" +$globalPackagesDirectory = Join-Path $tempRoot "global-packages" +$nugetConfigPath = Join-Path $tempRoot "NuGet.config" + +function Invoke-DotNet { + param( + [Parameter(Mandatory)] + [string[]] $Arguments + ) + + $output = & dotnet @Arguments 2>&1 | Out-String + if ($LASTEXITCODE -ne 0) { + throw "dotnet $($Arguments -join ' ') failed:`n$output" + } + + return $output +} + +function Assert-PackageDependencies { + param( + [Parameter(Mandatory)] + [string] $PackagePath, + + [Parameter(Mandatory)] + [string] $TargetFramework, + + [Parameter(Mandatory)] + [hashtable] $ExpectedPackages + ) + + $archive = [System.IO.Compression.ZipFile]::OpenRead($PackagePath) + try { + $nuspecEntry = $archive.Entries | + Where-Object { $_.FullName.EndsWith(".nuspec", [StringComparison]::OrdinalIgnoreCase) } | + Select-Object -First 1 + $reader = [System.IO.StreamReader]::new($nuspecEntry.Open()) + try { + [xml] $packageNuspec = $reader.ReadToEnd() + } + finally { + $reader.Dispose() + } + } + finally { + $archive.Dispose() + } + + $group = $packageNuspec.SelectNodes("//*[local-name()='group']") | + Where-Object { $_.targetFramework -eq $TargetFramework } | + Select-Object -First 1 + + if ($null -eq $group) { + throw "Package dependency group $TargetFramework was not found in $PackagePath." + } + + foreach ($package in $ExpectedPackages.GetEnumerator()) { + $dependency = $group.SelectNodes("*[local-name()='dependency']") | + Where-Object { $_.id -eq $package.Key } | + Select-Object -First 1 + + if ($null -eq $dependency -or $dependency.version -ne $package.Value) { + throw "Expected $($package.Key) $($package.Value) in the $TargetFramework dependency group." + } + } +} + +function Assert-AccordantAsset { + param( + [Parameter(Mandatory)] + [string] $AssetsPath, + + [Parameter(Mandatory)] + [string] $PackageVersion, + + [Parameter(Mandatory)] + [string] $TargetFramework + ) + + $assets = Get-Content $AssetsPath -Raw | ConvertFrom-Json + $target = $assets.targets.PSObject.Properties | Select-Object -First 1 -ExpandProperty Value + $accordant = $target.PSObject.Properties | + Where-Object { $_.Name -eq "Microsoft.Accordant/$PackageVersion" } | + Select-Object -First 1 -ExpandProperty Value + $compileAssets = @($accordant.compile.PSObject.Properties.Name) + + if ($compileAssets.Count -eq 0 -or + $compileAssets.Where({ -not $_.StartsWith("lib/$TargetFramework/", [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0) { + throw "Expected Microsoft.Accordant $PackageVersion to select only $TargetFramework compile assets." + } +} + +try { + New-Item -ItemType Directory -Path $packageDirectory -Force | Out-Null + $escapedPackageDirectory = [System.Security.SecurityElement]::Escape($packageDirectory) + $escapedNuGetSource = [System.Security.SecurityElement]::Escape($NuGetSource) + @" + + + + + + + + + + + + + + + + +"@ | Set-Content $nugetConfigPath -Encoding utf8 + + [xml] $nuspec = Get-Content $nuspecPath + $packageVersion = [string] $nuspec.package.metadata.version + + Invoke-DotNet @( + "pack", + $packageProject, + "--configuration", "Release", + "--output", $packageDirectory, + "--nologo", + "--verbosity", "minimal" + ) | Out-Host + $packagePath = Join-Path $packageDirectory "Microsoft.Accordant.$packageVersion.nupkg" + + $consumerCases = @( + @{ + Name = "Net8Consumer" + TargetFramework = "net8.0" + Packages = @{ + "System.Collections.Immutable" = "8.0.0" + "System.IO.Hashing" = "8.0.0" + "System.Text.Json" = "8.0.5" + } + }, + @{ + Name = "Net10Consumer" + TargetFramework = "net10.0" + Packages = @{ + "System.Collections.Immutable" = "10.0.0" + "System.IO.Hashing" = "10.0.3" + "System.Text.Json" = "10.0.3" + } + } + ) + + foreach ($case in $consumerCases) { + Assert-PackageDependencies ` + -PackagePath $packagePath ` + -TargetFramework $case.TargetFramework ` + -ExpectedPackages $case.Packages + + $sourceDirectory = Join-Path $PSScriptRoot "Consumers\$($case.Name)" + $consumerDirectory = Join-Path $tempRoot $case.Name + New-Item -ItemType Directory -Path $consumerDirectory -Force | Out-Null + Copy-Item -Path (Join-Path $sourceDirectory "*") -Destination $consumerDirectory -Recurse + + $consumerProject = Get-ChildItem $consumerDirectory -Filter "*.csproj" | Select-Object -First 1 -ExpandProperty FullName + Invoke-DotNet @( + "restore", + $consumerProject, + "--packages", $globalPackagesDirectory, + "--configfile", $nugetConfigPath, + "--force", + "--no-cache", + "--ignore-failed-sources", + "--nologo", + "--verbosity", "minimal", + "-p:AccordantPackageVersion=$packageVersion" + ) | Out-Host + + $buildOutput = Invoke-DotNet @( + "build", + $consumerProject, + "--configuration", "Release", + "--no-restore", + "--nologo", + "--verbosity", "minimal", + "-warnaserror:MSB3277", + "-p:AccordantPackageVersion=$packageVersion" + ) + + if ($buildOutput -match "\bMSB3277\b") { + throw "$($case.Name) emitted an MSB3277 assembly conflict:`n$buildOutput" + } + + $assetsPath = Join-Path $consumerDirectory "obj\project.assets.json" + Assert-AccordantAsset ` + -AssetsPath $assetsPath ` + -PackageVersion $packageVersion ` + -TargetFramework $case.TargetFramework + + Write-Host "$($case.Name) resolved the expected package train without MSB3277." + } +} +finally { + if (Test-Path $tempRoot) { + Remove-Item $tempRoot -Recurse -Force + } +} diff --git a/nuget/Microsoft.Accordant.Package.csproj b/nuget/Microsoft.Accordant.Package.csproj new file mode 100644 index 0000000..5c201d9 --- /dev/null +++ b/nuget/Microsoft.Accordant.Package.csproj @@ -0,0 +1,11 @@ + + + + net10.0 + true + false + Microsoft.Accordant.nuspec + true + + + diff --git a/nuget/Microsoft.Accordant.nuspec b/nuget/Microsoft.Accordant.nuspec index 268ba71..81267aa 100644 --- a/nuget/Microsoft.Accordant.nuspec +++ b/nuget/Microsoft.Accordant.nuspec @@ -15,8 +15,18 @@ accordant model-based testing state specifications fuzzing automated-testing - - + + + + + + + + + + + + @@ -32,6 +42,26 @@ + + + + + + + + + + + + + + + + + + + + From cb7ead88a7c331e80977a16341a2a5d3823ca2cb Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Thu, 20 Aug 2026 14:48:27 -0700 Subject: [PATCH 2/3] test(packaging): simplify consumer validation Generate the net8 and net10 package consumers at runtime instead of committing a multi-project fixture graph, while retaining isolated restore, MSB3277 enforcement, and TFM asset checks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Net10Consumer/Library/AccordantTypes.cs | 8 - .../Library/ConsumerLibrary.csproj | 12 -- .../Net10Consumer/Net10Consumer.csproj | 19 -- .../Consumers/Net10Consumer/Program.cs | 4 - .../SharedFrameworkLibrary/JsonTypes.cs | 8 - .../SharedFrameworkLibrary.csproj | 8 - .../Net8Consumer/Library/AccordantTypes.cs | 8 - .../Library/ConsumerLibrary.csproj | 12 -- .../Net8Consumer/Net8Consumer.csproj | 19 -- .../Consumers/Net8Consumer/Program.cs | 4 - .../SharedFrameworkLibrary/JsonTypes.cs | 8 - .../SharedFrameworkLibrary.csproj | 8 - .../Validate-Packages.ps1 | 179 +++++------------- 13 files changed, 45 insertions(+), 252 deletions(-) delete mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs delete mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj delete mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj delete mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs delete mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs delete mode 100644 Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj delete mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs delete mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj delete mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj delete mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs delete mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs delete mode 100644 Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs b/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs deleted file mode 100644 index 50acbe0..0000000 --- a/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/AccordantTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PackageCompatibility.ConsumerLibrary; - -using Microsoft.Accordant; - -public static class AccordantTypes -{ - public static string Description => $"{typeof(StateAttribute).FullName};{typeof(Spec).FullName}"; -} diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj deleted file mode 100644 index 47ca187..0000000 --- a/Tests/PackageCompatibility/Consumers/Net10Consumer/Library/ConsumerLibrary.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - net10.0 - enable - - - - - - - diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj b/Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj deleted file mode 100644 index 2968201..0000000 --- a/Tests/PackageCompatibility/Consumers/Net10Consumer/Net10Consumer.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - net10.0 - enable - - - - - - - - - - - - - diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs b/Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs deleted file mode 100644 index 37d843b..0000000 --- a/Tests/PackageCompatibility/Consumers/Net10Consumer/Program.cs +++ /dev/null @@ -1,4 +0,0 @@ -using PackageCompatibility.ConsumerLibrary; -using PackageCompatibility.SharedFrameworkLibrary; - -Console.WriteLine($"{AccordantTypes.Description};{JsonTypes.Description}"); diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs b/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs deleted file mode 100644 index 1e62482..0000000 --- a/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/JsonTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PackageCompatibility.SharedFrameworkLibrary; - -using System.Text.Json; - -public static class JsonTypes -{ - public static string Description => typeof(JsonSerializer).Assembly.FullName!; -} diff --git a/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj deleted file mode 100644 index 07f055d..0000000 --- a/Tests/PackageCompatibility/Consumers/Net10Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - net10.0 - enable - - - diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs b/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs deleted file mode 100644 index 50acbe0..0000000 --- a/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/AccordantTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PackageCompatibility.ConsumerLibrary; - -using Microsoft.Accordant; - -public static class AccordantTypes -{ - public static string Description => $"{typeof(StateAttribute).FullName};{typeof(Spec).FullName}"; -} diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj deleted file mode 100644 index 4826ee5..0000000 --- a/Tests/PackageCompatibility/Consumers/Net8Consumer/Library/ConsumerLibrary.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - net8.0 - enable - - - - - - - diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj b/Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj deleted file mode 100644 index e0e1a77..0000000 --- a/Tests/PackageCompatibility/Consumers/Net8Consumer/Net8Consumer.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - net8.0 - enable - - - - - - - - - - - - - diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs b/Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs deleted file mode 100644 index 37d843b..0000000 --- a/Tests/PackageCompatibility/Consumers/Net8Consumer/Program.cs +++ /dev/null @@ -1,4 +0,0 @@ -using PackageCompatibility.ConsumerLibrary; -using PackageCompatibility.SharedFrameworkLibrary; - -Console.WriteLine($"{AccordantTypes.Description};{JsonTypes.Description}"); diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs b/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs deleted file mode 100644 index 1e62482..0000000 --- a/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/JsonTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PackageCompatibility.SharedFrameworkLibrary; - -using System.Text.Json; - -public static class JsonTypes -{ - public static string Description => typeof(JsonSerializer).Assembly.FullName!; -} diff --git a/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj b/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj deleted file mode 100644 index bab0ebf..0000000 --- a/Tests/PackageCompatibility/Consumers/Net8Consumer/SharedFrameworkLibrary/SharedFrameworkLibrary.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - net8.0 - enable - - - diff --git a/Tests/PackageCompatibility/Validate-Packages.ps1 b/Tests/PackageCompatibility/Validate-Packages.ps1 index 035dbff..28e6f83 100644 --- a/Tests/PackageCompatibility/Validate-Packages.ps1 +++ b/Tests/PackageCompatibility/Validate-Packages.ps1 @@ -18,10 +18,7 @@ $globalPackagesDirectory = Join-Path $tempRoot "global-packages" $nugetConfigPath = Join-Path $tempRoot "NuGet.config" function Invoke-DotNet { - param( - [Parameter(Mandatory)] - [string[]] $Arguments - ) + param([Parameter(Mandatory)][string[]] $Arguments) $output = & dotnet @Arguments 2>&1 | Out-String if ($LASTEXITCODE -ne 0) { @@ -31,81 +28,20 @@ function Invoke-DotNet { return $output } -function Assert-PackageDependencies { - param( - [Parameter(Mandatory)] - [string] $PackagePath, - - [Parameter(Mandatory)] - [string] $TargetFramework, - - [Parameter(Mandatory)] - [hashtable] $ExpectedPackages - ) - - $archive = [System.IO.Compression.ZipFile]::OpenRead($PackagePath) - try { - $nuspecEntry = $archive.Entries | - Where-Object { $_.FullName.EndsWith(".nuspec", [StringComparison]::OrdinalIgnoreCase) } | - Select-Object -First 1 - $reader = [System.IO.StreamReader]::new($nuspecEntry.Open()) - try { - [xml] $packageNuspec = $reader.ReadToEnd() - } - finally { - $reader.Dispose() - } - } - finally { - $archive.Dispose() - } - - $group = $packageNuspec.SelectNodes("//*[local-name()='group']") | - Where-Object { $_.targetFramework -eq $TargetFramework } | - Select-Object -First 1 - - if ($null -eq $group) { - throw "Package dependency group $TargetFramework was not found in $PackagePath." - } - - foreach ($package in $ExpectedPackages.GetEnumerator()) { - $dependency = $group.SelectNodes("*[local-name()='dependency']") | - Where-Object { $_.id -eq $package.Key } | - Select-Object -First 1 - - if ($null -eq $dependency -or $dependency.version -ne $package.Value) { - throw "Expected $($package.Key) $($package.Value) in the $TargetFramework dependency group." - } - } -} - -function Assert-AccordantAsset { - param( - [Parameter(Mandatory)] - [string] $AssetsPath, - - [Parameter(Mandatory)] - [string] $PackageVersion, - - [Parameter(Mandatory)] - [string] $TargetFramework - ) +try { + New-Item -ItemType Directory -Path $packageDirectory -Force | Out-Null - $assets = Get-Content $AssetsPath -Raw | ConvertFrom-Json - $target = $assets.targets.PSObject.Properties | Select-Object -First 1 -ExpandProperty Value - $accordant = $target.PSObject.Properties | - Where-Object { $_.Name -eq "Microsoft.Accordant/$PackageVersion" } | - Select-Object -First 1 -ExpandProperty Value - $compileAssets = @($accordant.compile.PSObject.Properties.Name) + [xml] $nuspec = Get-Content $nuspecPath + $packageVersion = [string] $nuspec.package.metadata.version - if ($compileAssets.Count -eq 0 -or - $compileAssets.Where({ -not $_.StartsWith("lib/$TargetFramework/", [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0) { - throw "Expected Microsoft.Accordant $PackageVersion to select only $TargetFramework compile assets." - } -} + Invoke-DotNet @( + "pack", $packageProject, + "--configuration", "Release", + "--output", $packageDirectory, + "--nologo", + "--verbosity", "minimal" + ) | Out-Host -try { - New-Item -ItemType Directory -Path $packageDirectory -Force | Out-Null $escapedPackageDirectory = [System.Security.SecurityElement]::Escape($packageDirectory) $escapedNuGetSource = [System.Security.SecurityElement]::Escape($NuGetSource) @" @@ -127,87 +63,62 @@ try { "@ | Set-Content $nugetConfigPath -Encoding utf8 - [xml] $nuspec = Get-Content $nuspecPath - $packageVersion = [string] $nuspec.package.metadata.version - - Invoke-DotNet @( - "pack", - $packageProject, - "--configuration", "Release", - "--output", $packageDirectory, - "--nologo", - "--verbosity", "minimal" - ) | Out-Host - $packagePath = Join-Path $packageDirectory "Microsoft.Accordant.$packageVersion.nupkg" - - $consumerCases = @( - @{ - Name = "Net8Consumer" - TargetFramework = "net8.0" - Packages = @{ - "System.Collections.Immutable" = "8.0.0" - "System.IO.Hashing" = "8.0.0" - "System.Text.Json" = "8.0.5" - } - }, - @{ - Name = "Net10Consumer" - TargetFramework = "net10.0" - Packages = @{ - "System.Collections.Immutable" = "10.0.0" - "System.IO.Hashing" = "10.0.3" - "System.Text.Json" = "10.0.3" - } - } - ) + foreach ($targetFramework in "net8.0", "net10.0") { + $consumerDirectory = Join-Path $tempRoot $targetFramework + $consumerProject = Join-Path $consumerDirectory "Consumer.csproj" + New-Item -ItemType Directory -Path $consumerDirectory -Force | Out-Null - foreach ($case in $consumerCases) { - Assert-PackageDependencies ` - -PackagePath $packagePath ` - -TargetFramework $case.TargetFramework ` - -ExpectedPackages $case.Packages + @" + + + $targetFramework + + + + + +"@ | Set-Content $consumerProject -Encoding utf8 - $sourceDirectory = Join-Path $PSScriptRoot "Consumers\$($case.Name)" - $consumerDirectory = Join-Path $tempRoot $case.Name - New-Item -ItemType Directory -Path $consumerDirectory -Force | Out-Null - Copy-Item -Path (Join-Path $sourceDirectory "*") -Destination $consumerDirectory -Recurse + 'public static class Consumer { public static System.Type AccordantType => typeof(Microsoft.Accordant.StateAttribute); }' | + Set-Content (Join-Path $consumerDirectory "Consumer.cs") -Encoding utf8 - $consumerProject = Get-ChildItem $consumerDirectory -Filter "*.csproj" | Select-Object -First 1 -ExpandProperty FullName Invoke-DotNet @( - "restore", - $consumerProject, + "restore", $consumerProject, "--packages", $globalPackagesDirectory, "--configfile", $nugetConfigPath, "--force", "--no-cache", "--ignore-failed-sources", "--nologo", - "--verbosity", "minimal", - "-p:AccordantPackageVersion=$packageVersion" + "--verbosity", "minimal" ) | Out-Host $buildOutput = Invoke-DotNet @( - "build", - $consumerProject, + "build", $consumerProject, "--configuration", "Release", "--no-restore", "--nologo", "--verbosity", "minimal", - "-warnaserror:MSB3277", - "-p:AccordantPackageVersion=$packageVersion" + "-warnaserror:MSB3277" ) if ($buildOutput -match "\bMSB3277\b") { - throw "$($case.Name) emitted an MSB3277 assembly conflict:`n$buildOutput" + throw "$targetFramework emitted an MSB3277 assembly conflict:`n$buildOutput" } - $assetsPath = Join-Path $consumerDirectory "obj\project.assets.json" - Assert-AccordantAsset ` - -AssetsPath $assetsPath ` - -PackageVersion $packageVersion ` - -TargetFramework $case.TargetFramework + $assets = Get-Content (Join-Path $consumerDirectory "obj\project.assets.json") -Raw | ConvertFrom-Json + $target = $assets.targets.PSObject.Properties | Select-Object -First 1 -ExpandProperty Value + $accordant = $target.PSObject.Properties | + Where-Object Name -eq "Microsoft.Accordant/$packageVersion" | + Select-Object -First 1 -ExpandProperty Value + $compileAssets = @($accordant.compile.PSObject.Properties.Name) + + if ($compileAssets.Count -eq 0 -or + $compileAssets.Where({ -not $_.StartsWith("lib/$targetFramework/", [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0) { + throw "Microsoft.Accordant $packageVersion did not select its $targetFramework assets." + } - Write-Host "$($case.Name) resolved the expected package train without MSB3277." + Write-Host "$targetFramework selected its package assets without MSB3277." } } finally { From 8eff1581740c88362d3bb74b803904b1ca3ea5fd Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Thu, 20 Aug 2026 15:13:33 -0700 Subject: [PATCH 3/3] refactor(packaging): use SDK-native NuGet packs Replace handwritten nuspec files with SDK pack projects, use target-framework package version overrides, and cover net8/net10 through the existing operations tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 7 +- Accordant.slnx | 1 + Directory.Packages.props | 14 +- .../DotnetToolSettings.xml | 6 - .../Microsoft.Accordant.Cli.csproj | 16 ++- Scripts/Install-AccordantCli.ps1 | 20 +-- Scripts/create-nuget-packages.ps1 | 25 +--- .../Accordant.Operations.Tests.csproj | 2 +- .../Validate-Packages.ps1 | 128 ------------------ nuget/Microsoft.Accordant.Cli.nuspec | 33 ----- nuget/Microsoft.Accordant.Package.csproj | 50 ++++++- nuget/Microsoft.Accordant.nuspec | 70 ---------- 12 files changed, 80 insertions(+), 292 deletions(-) delete mode 100644 Microsoft.Accordant.Cli/DotnetToolSettings.xml delete mode 100644 Tests/PackageCompatibility/Validate-Packages.ps1 delete mode 100644 nuget/Microsoft.Accordant.Cli.nuspec delete mode 100644 nuget/Microsoft.Accordant.nuspec diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8b75f6..e2109e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,9 +32,10 @@ jobs: - name: Build run: dotnet build --no-restore --configuration Release - - name: Validate package compatibility - shell: pwsh - run: ./Tests/PackageCompatibility/Validate-Packages.ps1 + - name: Pack + run: | + dotnet pack nuget/Microsoft.Accordant.Package.csproj --no-build --no-restore --configuration Release + dotnet pack Microsoft.Accordant.Cli/Microsoft.Accordant.Cli.csproj --no-build --no-restore --configuration Release - name: Test run: dotnet test --no-build --configuration Release --verbosity normal diff --git a/Accordant.slnx b/Accordant.slnx index 3afd4cf..584fe1d 100644 --- a/Accordant.slnx +++ b/Accordant.slnx @@ -23,4 +23,5 @@ + diff --git a/Directory.Packages.props b/Directory.Packages.props index 81fbd1f..2edd047 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,12 +12,14 @@ - - + - - - - + + + + + + + \ No newline at end of file diff --git a/Microsoft.Accordant.Cli/DotnetToolSettings.xml b/Microsoft.Accordant.Cli/DotnetToolSettings.xml deleted file mode 100644 index 135493c..0000000 --- a/Microsoft.Accordant.Cli/DotnetToolSettings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Microsoft.Accordant.Cli/Microsoft.Accordant.Cli.csproj b/Microsoft.Accordant.Cli/Microsoft.Accordant.Cli.csproj index b48480b..be8d0b6 100644 --- a/Microsoft.Accordant.Cli/Microsoft.Accordant.Cli.csproj +++ b/Microsoft.Accordant.Cli/Microsoft.Accordant.Cli.csproj @@ -7,9 +7,14 @@ enable enable Microsoft.Accordant - - - false + true + true + accordant + Microsoft.Accordant.Cli + docs\readme.md + icon.png + CLI tool for scaffolding Accordant model-based testing projects + accordant cli scaffolding testing model-based @@ -26,9 +31,8 @@ - - Always - + + diff --git a/Scripts/Install-AccordantCli.ps1 b/Scripts/Install-AccordantCli.ps1 index 87555ed..6fcc9a5 100644 --- a/Scripts/Install-AccordantCli.ps1 +++ b/Scripts/Install-AccordantCli.ps1 @@ -1,6 +1,5 @@ # Install-AccordantCli.ps1 # Installs (or reinstalls) the Microsoft.Accordant.Cli tool locally for development -# Uses the nuspec file from nuget/ folder param( [switch]$Global = $true @@ -10,12 +9,9 @@ $ErrorActionPreference = "Stop" $toolName = "Microsoft.Accordant.Cli" $projectPath = (Resolve-Path "$PSScriptRoot\..\Microsoft.Accordant.Cli\Microsoft.Accordant.Cli.csproj").Path -$nuspecPath = (Resolve-Path "$PSScriptRoot\..\nuget\Microsoft.Accordant.Cli.nuspec").Path $nupkgPath = "$PSScriptRoot\..\bin\packages" -# Extract version from nuspec -[xml]$nuspec = Get-Content $nuspecPath -$version = $nuspec.package.metadata.version +$version = dotnet msbuild $projectPath -getProperty:Version -nologo Write-Host "=== Accordant CLI Installer ===" -ForegroundColor Cyan Write-Host "" @@ -48,24 +44,16 @@ if (-not (Test-Path $nupkgPath)) { # Convert to absolute path for dotnet tool install $nupkgPath = (Resolve-Path $nupkgPath).Path -# Pack using nuspec (catches target framework mismatches) Write-Host "" -Write-Host "Packing with nuspec (validates target framework coverage)..." -ForegroundColor Yellow +Write-Host "Packing..." -ForegroundColor Yellow # Remove any existing nupkg to avoid file locking issues Remove-Item "$nupkgPath\$toolName.*.nupkg" -Force -ErrorAction SilentlyContinue -# Use nuget pack with the nuspec file -$nugetExe = Get-Command nuget -ErrorAction SilentlyContinue -if ($nugetExe) { - nuget pack $nuspecPath -OutputDirectory $nupkgPath -} else { - # Fallback: use dotnet pack with nuspec - dotnet pack $projectPath -c Release -o $nupkgPath -p:NuspecFile=$nuspecPath /m:1 -} +dotnet pack $projectPath -c Release -o $nupkgPath --no-build if ($LASTEXITCODE -ne 0) { - Write-Host "Pack failed! Check if nuspec matches csproj TargetFrameworks." -ForegroundColor Red + Write-Host "Pack failed!" -ForegroundColor Red exit 1 } diff --git a/Scripts/create-nuget-packages.ps1 b/Scripts/create-nuget-packages.ps1 index a2e84f7..37bbe0b 100644 --- a/Scripts/create-nuget-packages.ps1 +++ b/Scripts/create-nuget-packages.ps1 @@ -3,35 +3,20 @@ Import-Module $PSScriptRoot/common.psm1 -Force -$nuget = "nuget" - -# Check that NuGet.exe is installed. -if (-not (Get-Command $nuget -errorAction SilentlyContinue)) { - Write-Comment -text "Please install the latest NuGet.exe from https://www.nuget.org/downloads and add it to the PATH environment variable." -color "yellow" - exit 1 -} +$dotnet = "dotnet" Write-Comment -prefix "." -text "Creating the Accordant NuGet packages" -color "yellow" -$version = "0.1.5" - -# Setup the command line options for nuget pack. -$cmd_options = "-OutputDirectory $PSScriptRoot/../bin/packages -Version $version" -$cmd_options = "$cmd_options -Symbols -SymbolPackageFormat snupkg" - Write-Comment -prefix "..." -text "Creating the 'Microsoft.Accordant' package" -$command = "pack $PSScriptRoot/../nuget/Microsoft.Accordant.nuspec $cmd_options" +$command = "pack $PSScriptRoot/../nuget/Microsoft.Accordant.Package.csproj --configuration Release --output $PSScriptRoot/../bin/packages --no-restore" $error_msg = "Failed to create the Microsoft.Accordant NuGet package" -Invoke-ToolCommand -tool $nuget -cmd $command -error_msg $error_msg - -# Tool packages don't need symbols -$tool_cmd_options = "-OutputDirectory $PSScriptRoot/../bin/packages -Version $version" +Invoke-ToolCommand -tool $dotnet -cmd $command -error_msg $error_msg Write-Comment -prefix "..." -text "Creating the 'Microsoft.Accordant.Cli' package (dotnet tool)" -$command = "pack $PSScriptRoot/../nuget/Microsoft.Accordant.Cli.nuspec $tool_cmd_options" +$command = "pack $PSScriptRoot/../Microsoft.Accordant.Cli/Microsoft.Accordant.Cli.csproj --configuration Release --output $PSScriptRoot/../bin/packages --no-restore" $error_msg = "Failed to create the Microsoft.Accordant.Cli NuGet package" -Invoke-ToolCommand -tool $nuget -cmd $command -error_msg $error_msg +Invoke-ToolCommand -tool $dotnet -cmd $command -error_msg $error_msg Write-Comment -prefix "." -text "Successfully created the Accordant NuGet packages" -color "green" diff --git a/Tests/Accordant.Operations.Tests/Accordant.Operations.Tests.csproj b/Tests/Accordant.Operations.Tests/Accordant.Operations.Tests.csproj index 0f81647..5f316aa 100644 --- a/Tests/Accordant.Operations.Tests/Accordant.Operations.Tests.csproj +++ b/Tests/Accordant.Operations.Tests/Accordant.Operations.Tests.csproj @@ -1,7 +1,7 @@ - net9.0 + net8.0;net10.0 latest Library diff --git a/Tests/PackageCompatibility/Validate-Packages.ps1 b/Tests/PackageCompatibility/Validate-Packages.ps1 deleted file mode 100644 index 28e6f83..0000000 --- a/Tests/PackageCompatibility/Validate-Packages.ps1 +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -[CmdletBinding()] -param( - [string] $NuGetSource = "https://api.nuget.org/v3/index.json" -) - -$ErrorActionPreference = "Stop" -Set-StrictMode -Version Latest - -$repositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path -$nuspecPath = Join-Path $repositoryRoot "nuget\Microsoft.Accordant.nuspec" -$packageProject = Join-Path $repositoryRoot "nuget\Microsoft.Accordant.Package.csproj" -$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "accordant-package-compatibility-$([Guid]::NewGuid().ToString('N'))" -$packageDirectory = Join-Path $tempRoot "packages" -$globalPackagesDirectory = Join-Path $tempRoot "global-packages" -$nugetConfigPath = Join-Path $tempRoot "NuGet.config" - -function Invoke-DotNet { - param([Parameter(Mandatory)][string[]] $Arguments) - - $output = & dotnet @Arguments 2>&1 | Out-String - if ($LASTEXITCODE -ne 0) { - throw "dotnet $($Arguments -join ' ') failed:`n$output" - } - - return $output -} - -try { - New-Item -ItemType Directory -Path $packageDirectory -Force | Out-Null - - [xml] $nuspec = Get-Content $nuspecPath - $packageVersion = [string] $nuspec.package.metadata.version - - Invoke-DotNet @( - "pack", $packageProject, - "--configuration", "Release", - "--output", $packageDirectory, - "--nologo", - "--verbosity", "minimal" - ) | Out-Host - - $escapedPackageDirectory = [System.Security.SecurityElement]::Escape($packageDirectory) - $escapedNuGetSource = [System.Security.SecurityElement]::Escape($NuGetSource) - @" - - - - - - - - - - - - - - - - -"@ | Set-Content $nugetConfigPath -Encoding utf8 - - foreach ($targetFramework in "net8.0", "net10.0") { - $consumerDirectory = Join-Path $tempRoot $targetFramework - $consumerProject = Join-Path $consumerDirectory "Consumer.csproj" - New-Item -ItemType Directory -Path $consumerDirectory -Force | Out-Null - - @" - - - $targetFramework - - - - - -"@ | Set-Content $consumerProject -Encoding utf8 - - 'public static class Consumer { public static System.Type AccordantType => typeof(Microsoft.Accordant.StateAttribute); }' | - Set-Content (Join-Path $consumerDirectory "Consumer.cs") -Encoding utf8 - - Invoke-DotNet @( - "restore", $consumerProject, - "--packages", $globalPackagesDirectory, - "--configfile", $nugetConfigPath, - "--force", - "--no-cache", - "--ignore-failed-sources", - "--nologo", - "--verbosity", "minimal" - ) | Out-Host - - $buildOutput = Invoke-DotNet @( - "build", $consumerProject, - "--configuration", "Release", - "--no-restore", - "--nologo", - "--verbosity", "minimal", - "-warnaserror:MSB3277" - ) - - if ($buildOutput -match "\bMSB3277\b") { - throw "$targetFramework emitted an MSB3277 assembly conflict:`n$buildOutput" - } - - $assets = Get-Content (Join-Path $consumerDirectory "obj\project.assets.json") -Raw | ConvertFrom-Json - $target = $assets.targets.PSObject.Properties | Select-Object -First 1 -ExpandProperty Value - $accordant = $target.PSObject.Properties | - Where-Object Name -eq "Microsoft.Accordant/$packageVersion" | - Select-Object -First 1 -ExpandProperty Value - $compileAssets = @($accordant.compile.PSObject.Properties.Name) - - if ($compileAssets.Count -eq 0 -or - $compileAssets.Where({ -not $_.StartsWith("lib/$targetFramework/", [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0) { - throw "Microsoft.Accordant $packageVersion did not select its $targetFramework assets." - } - - Write-Host "$targetFramework selected its package assets without MSB3277." - } -} -finally { - if (Test-Path $tempRoot) { - Remove-Item $tempRoot -Recurse -Force - } -} diff --git a/nuget/Microsoft.Accordant.Cli.nuspec b/nuget/Microsoft.Accordant.Cli.nuspec deleted file mode 100644 index ffb6fe5..0000000 --- a/nuget/Microsoft.Accordant.Cli.nuspec +++ /dev/null @@ -1,33 +0,0 @@ - - - - Microsoft.Accordant.Cli - 0.1.7 - Microsoft - false - MIT - https://github.com/microsoft/accordant - - docs\readme.md - icon.png - CLI tool for scaffolding Accordant model-based testing projects - © Microsoft Corporation. All rights reserved. - accordant cli scaffolding testing model-based - - - - - - - - - - - - - - - - - - diff --git a/nuget/Microsoft.Accordant.Package.csproj b/nuget/Microsoft.Accordant.Package.csproj index 5c201d9..1556fbe 100644 --- a/nuget/Microsoft.Accordant.Package.csproj +++ b/nuget/Microsoft.Accordant.Package.csproj @@ -1,11 +1,55 @@ - net10.0 + netstandard2.0;net8.0;net10.0 + Microsoft.Accordant true false - Microsoft.Accordant.nuspec - true + true + snupkg + docs\readme.md + icon.png + Accordant is a model-based testing framework for .NET. Define state specifications, operations, and expected outcomes, then let Accordant automatically generate and execute comprehensive test cases covering all state transitions. + accordant model-based testing state specifications fuzzing automated-testing + $(TargetsForTfmSpecificContentInPackage);AddAccordantAssembliesToPackage + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nuget/Microsoft.Accordant.nuspec b/nuget/Microsoft.Accordant.nuspec deleted file mode 100644 index 81267aa..0000000 --- a/nuget/Microsoft.Accordant.nuspec +++ /dev/null @@ -1,70 +0,0 @@ - - - - Microsoft.Accordant - 0.1.7 - Microsoft - false - MIT - https://github.com/microsoft/accordant - - docs\readme.md - icon.png - Accordant is a model-based testing framework for .NET. Define state specifications, operations, and expected outcomes, then let Accordant automatically generate and execute comprehensive test cases covering all state transitions. - © Microsoft Corporation. All rights reserved. - accordant model-based testing state specifications fuzzing automated-testing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -