From ec6399e8e743553b07aaf0904a622448f36ca17d Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:15:22 +0100 Subject: [PATCH 1/6] ci: test the NuGet packages on Windows in their own job With every .NET Framework TFM, the NuGet package tests competed with the engine tests and AOT publish for the Windows runner's CPUs, doubling both. Tag the packaging and package-test modules with categories, skip the package tests in the Windows matrix pipeline (--ignore-categories), and run them in a nuget-package-tests-windows job that only builds and packs the libraries. --- .github/actions/execute-pipeline/action.yml | 6 +- .github/workflows/dotnet.yml | 73 +++++++++++++++++++ .../Modules/AddLocalNuGetRepositoryModule.cs | 4 +- .../Modules/CopyToLocalNuGetModule.cs | 1 + .../Modules/GenerateVersionModule.cs | 2 + .../Modules/GetPackageProjectsModule.cs | 6 +- .../Modules/PackTUnitFilesModule.cs | 3 +- .../Modules/PublishNugetTesterAOTModule.cs | 1 + .../TestAspNetCoreNugetPackageModule.cs | 1 + .../Modules/TestNugetPackageModule.cs | 1 + .../Modules/TestTemplatePackageModule.cs | 1 + tools/TUnit.Pipeline/PipelineCategories.cs | 13 ++++ tools/TUnit.Pipeline/Program.cs | 13 +++- 13 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 tools/TUnit.Pipeline/PipelineCategories.cs diff --git a/.github/actions/execute-pipeline/action.yml b/.github/actions/execute-pipeline/action.yml index 8e1402f5b2e..43ae978fa4f 100644 --- a/.github/actions/execute-pipeline/action.yml +++ b/.github/actions/execute-pipeline/action.yml @@ -5,6 +5,10 @@ inputs: description: Categories to run required: false default: '' + ignore-categories: + description: Categories to skip + required: false + default: '' admin-token: description: 'Admin token' required: true @@ -30,7 +34,7 @@ runs: steps: - name: Run Pipeline shell: bash - run: dotnet run -c Release --no-build --categories ${{ inputs.categories }} + run: dotnet run -c Release --no-build --categories ${{ inputs.categories }} --ignore-categories ${{ inputs.ignore-categories }} working-directory: "tools/TUnit.Pipeline" env: ADMIN_TOKEN: ${{ inputs.admin-token }} diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 3e2819deb17..c8435a31030 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -145,6 +145,9 @@ jobs: environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Development' }} nuget-apikey: ${{ steps.login.outputs.NUGET_API_KEY }} publish-packages: ${{ (github.event.inputs.publish-packages || false) && matrix.os == 'ubuntu-latest' }} + # Windows tests the packages in the nuget-package-tests-windows job instead: with every + # .NET Framework TFM they competed with the engine tests for this runner's CPUs. + ignore-categories: ${{ matrix.os == 'windows-latest' && 'NuGetPackageTests' || '' }} - name: Upload Diagnostic Logs uses: actions/upload-artifact@v7.0.2 @@ -224,6 +227,76 @@ jobs: exit 1 fi + # Tests the packed packages on Windows, including every .NET Framework TFM, on a runner of its + # own. Linux and macOS still test them inside the matrix pipeline. + nuget-package-tests-windows: + runs-on: windows-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@v7.0.1 + with: + fetch-depth: 0 + + - name: Setup Dev Drive + uses: samypr100/setup-dev-drive@v4 + with: + drive-size: 10GB + trusted-dev-drive: true + env-mapping: | + NUGET_PACKAGES,{{ DEV_DRIVE }}/.nuget/packages + TEMP,{{ DEV_DRIVE }}/tmp + TMP,{{ DEV_DRIVE }}/tmp + + - name: Setup .NET Framework + uses: microsoft/setup-msbuild@v3 + + - name: Setup .NET + uses: actions/setup-dotnet@v6.0.0 + + - name: Enable Long Paths + run: | + New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force + shell: pwsh + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v4 + with: + versionSpec: '6.7.x' + + - name: Determine Version + id: gitversion + uses: gittools/actions/gitversion/execute@v4 + + # See the matching step in the modularpipeline job (issue #5622). + - name: Export version env vars + shell: bash + run: | + { + echo "Version=${{ steps.gitversion.outputs.semVer }}" + echo "AssemblyVersion=${{ steps.gitversion.outputs.assemblySemVer }}" + echo "FileVersion=${{ steps.gitversion.outputs.assemblySemFileVer }}" + echo "InformationalVersion=${{ steps.gitversion.outputs.informationalVersion }}" + echo "PackageVersion=${{ steps.gitversion.outputs.fullSemVer }}" + } >> "$GITHUB_ENV" + + # Only what packing needs: every library project (packing reads the Roslyn variants from + # their own bin folders) and the pipeline itself. + - name: Build + shell: bash + run: | + grep -oE 'src/[^"]+\.(cs|fs|vb)proj' TUnit.CI.slnx | grep -v '/content/' \ + | jq -R . | jq -s '{solution: {path: "TUnit.CI.slnx", projects: .}}' > libraries.slnf + dotnet build libraries.slnf -c Release + dotnet build tools/TUnit.Pipeline/TUnit.Pipeline.csproj -c Release + + - name: Run Pipeline + uses: ./.github/actions/execute-pipeline + with: + categories: Packaging NuGetPackageTests + admin-token: ${{ github.token }} + # Compiles the C# fences in the documentation against freshly packed packages, alongside the # test matrix rather than after the Ubuntu pipeline. doc-snippets: diff --git a/tools/TUnit.Pipeline/Modules/AddLocalNuGetRepositoryModule.cs b/tools/TUnit.Pipeline/Modules/AddLocalNuGetRepositoryModule.cs index 33cf74c7c61..64fa1cce2e5 100644 --- a/tools/TUnit.Pipeline/Modules/AddLocalNuGetRepositoryModule.cs +++ b/tools/TUnit.Pipeline/Modules/AddLocalNuGetRepositoryModule.cs @@ -1,4 +1,5 @@ -using ModularPipelines.Context; +using ModularPipelines.Attributes; +using ModularPipelines.Context; using ModularPipelines.DotNet.Extensions; using ModularPipelines.DotNet.Options; using ModularPipelines.FileSystem; @@ -7,6 +8,7 @@ namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.Packaging)] public class AddLocalNuGetRepositoryModule : Module { protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) diff --git a/tools/TUnit.Pipeline/Modules/CopyToLocalNuGetModule.cs b/tools/TUnit.Pipeline/Modules/CopyToLocalNuGetModule.cs index 7baa2a2db21..e7517bd028e 100644 --- a/tools/TUnit.Pipeline/Modules/CopyToLocalNuGetModule.cs +++ b/tools/TUnit.Pipeline/Modules/CopyToLocalNuGetModule.cs @@ -5,6 +5,7 @@ using File = ModularPipelines.FileSystem.File; namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.Packaging)] [DependsOn] [DependsOn] public class CopyToLocalNuGetModule : Module> diff --git a/tools/TUnit.Pipeline/Modules/GenerateVersionModule.cs b/tools/TUnit.Pipeline/Modules/GenerateVersionModule.cs index 5ffe70d7969..e0833769e14 100644 --- a/tools/TUnit.Pipeline/Modules/GenerateVersionModule.cs +++ b/tools/TUnit.Pipeline/Modules/GenerateVersionModule.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using ModularPipelines.Attributes; using ModularPipelines.Context; using ModularPipelines.Git.Extensions; using ModularPipelines.Git.Models; @@ -6,6 +7,7 @@ namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.Packaging)] public class GenerateVersionModule : Module { protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) diff --git a/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs b/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs index 588210d1686..f3f29417693 100644 --- a/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs +++ b/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs @@ -1,9 +1,11 @@ -using ModularPipelines.Context; +using File = ModularPipelines.FileSystem.File; +using ModularPipelines.Attributes; +using ModularPipelines.Context; using ModularPipelines.Modules; -using File = ModularPipelines.FileSystem.File; namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.Packaging)] public class GetPackageProjectsModule : Module> { protected override async Task?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) diff --git a/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs b/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs index 73810b2316d..9e3129a18be 100644 --- a/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs +++ b/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs @@ -1,4 +1,4 @@ -using ModularPipelines.Attributes; +using ModularPipelines.Attributes; using ModularPipelines.Context; using ModularPipelines.DotNet.Extensions; using ModularPipelines.DotNet.Options; @@ -14,6 +14,7 @@ namespace TUnit.Pipeline.Modules; // Version props come from $GITHUB_ENV (see .github/workflows/dotnet.yml) so recompiles // also stamp the correct AssemblyVersion. See issue #5622. The AOT publishes build into // their own artifacts trees, so they no longer touch those folders. +[ModuleCategory(PipelineCategories.Packaging)] [DependsOn] [DependsOn] public class PackTUnitFilesModule : Module> diff --git a/tools/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs b/tools/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs index 0e3de549de2..40e8ace3df3 100644 --- a/tools/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs +++ b/tools/TUnit.Pipeline/Modules/PublishNugetTesterAOTModule.cs @@ -11,6 +11,7 @@ namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [DependsOn] [DependsOn] [DependsOn] diff --git a/tools/TUnit.Pipeline/Modules/TestAspNetCoreNugetPackageModule.cs b/tools/TUnit.Pipeline/Modules/TestAspNetCoreNugetPackageModule.cs index 1ea45872fb0..fa274b95d42 100644 --- a/tools/TUnit.Pipeline/Modules/TestAspNetCoreNugetPackageModule.cs +++ b/tools/TUnit.Pipeline/Modules/TestAspNetCoreNugetPackageModule.cs @@ -10,6 +10,7 @@ namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [DependsOn] [DependsOn] public class TestAspNetCoreNugetPackageModule : TestBaseModule diff --git a/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs b/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs index 5e91013f878..1eef22de3d9 100644 --- a/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs +++ b/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs @@ -28,6 +28,7 @@ public class TestVBNugetPackageModule : AbstractTestNugetPackageModule public override string ProjectName => "TUnit.NugetTester.VB.vbproj"; } +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [DependsOn] [DependsOn] public abstract class AbstractTestNugetPackageModule : TestBaseModule diff --git a/tools/TUnit.Pipeline/Modules/TestTemplatePackageModule.cs b/tools/TUnit.Pipeline/Modules/TestTemplatePackageModule.cs index 964b5b81aff..31cb8c0153e 100644 --- a/tools/TUnit.Pipeline/Modules/TestTemplatePackageModule.cs +++ b/tools/TUnit.Pipeline/Modules/TestTemplatePackageModule.cs @@ -8,6 +8,7 @@ namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [DependsOn] [DependsOn] public class TestTemplatePackageModule : Module diff --git a/tools/TUnit.Pipeline/PipelineCategories.cs b/tools/TUnit.Pipeline/PipelineCategories.cs new file mode 100644 index 00000000000..6813b8aebf0 --- /dev/null +++ b/tools/TUnit.Pipeline/PipelineCategories.cs @@ -0,0 +1,13 @@ +namespace TUnit.Pipeline; + +/// +/// Module categories, selected with --categories or skipped with --ignore-categories. +/// +public static class PipelineCategories +{ + /// Versions, packs and stages the NuGet packages. + public const string Packaging = "Packaging"; + + /// Consumes the packed packages. Windows runs these in their own job (see dotnet.yml). + public const string NuGetPackageTests = "NuGetPackageTests"; +} diff --git a/tools/TUnit.Pipeline/Program.cs b/tools/TUnit.Pipeline/Program.cs index 88098bebd54..0d5fde8471d 100644 --- a/tools/TUnit.Pipeline/Program.cs +++ b/tools/TUnit.Pipeline/Program.cs @@ -15,11 +15,22 @@ DefaultValueFactory = _ => [] }; +var ignoreCategoryOption = new Option( + name: "--ignore-categories") +{ + Arity = ArgumentArity.ZeroOrMore, + AllowMultipleArgumentsPerToken = true, + Description = "Categories to skip when no --categories are given.", + DefaultValueFactory = _ => [] +}; + var rootCommand = new RootCommand("The pipeline for building, testing and packaging TUnit"); rootCommand.Add(categoryOption); +rootCommand.Add(ignoreCategoryOption); rootCommand.SetAction(async parseResult => { var categories = parseResult.GetValue(categoryOption)!; + var ignoreCategories = parseResult.GetValue(ignoreCategoryOption)!; var builder = Pipeline.CreateBuilder(); builder.Configuration.AddEnvironmentVariables(); @@ -33,7 +44,7 @@ } else { - builder.IgnoreCategories("ReadMe"); + builder.IgnoreCategories(["ReadMe", ..ignoreCategories]); } await builder.Build().RunAsync(); From 172ad7967f38002150a4bbe118a270f7a8bec574 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:25:02 +0100 Subject: [PATCH 2/6] ci: keep the using alias last --- tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs b/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs index f3f29417693..986d57a3919 100644 --- a/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs +++ b/tools/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs @@ -1,7 +1,7 @@ -using File = ModularPipelines.FileSystem.File; -using ModularPipelines.Attributes; +using ModularPipelines.Attributes; using ModularPipelines.Context; using ModularPipelines.Modules; +using File = ModularPipelines.FileSystem.File; namespace TUnit.Pipeline.Modules; From ef47515fb7deb2bf5e1eb9d9ebeb61f5a339ed0c Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:30:12 +0100 Subject: [PATCH 3/6] ci: categorise each NuGet tester module and pass --ignore-categories only when set Put the NuGetPackageTests category on the three concrete tester modules rather than relying on attribute inheritance from the abstract base, and only append --ignore-categories in the pipeline action when the input is non-empty. --- .github/actions/execute-pipeline/action.yml | 7 ++++++- tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/actions/execute-pipeline/action.yml b/.github/actions/execute-pipeline/action.yml index 43ae978fa4f..69b91cbda52 100644 --- a/.github/actions/execute-pipeline/action.yml +++ b/.github/actions/execute-pipeline/action.yml @@ -34,7 +34,12 @@ runs: steps: - name: Run Pipeline shell: bash - run: dotnet run -c Release --no-build --categories ${{ inputs.categories }} --ignore-categories ${{ inputs.ignore-categories }} + run: | + args=(--categories ${{ inputs.categories }}) + if [ -n "${{ inputs.ignore-categories }}" ]; then + args+=(--ignore-categories ${{ inputs.ignore-categories }}) + fi + dotnet run -c Release --no-build "${args[@]}" working-directory: "tools/TUnit.Pipeline" env: ADMIN_TOKEN: ${{ inputs.admin-token }} diff --git a/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs b/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs index 1eef22de3d9..67865b7a876 100644 --- a/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs +++ b/tools/TUnit.Pipeline/Modules/TestNugetPackageModule.cs @@ -10,25 +10,27 @@ namespace TUnit.Pipeline.Modules; +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [NotInParallel("NugetTester")] public class TestNugetPackageModule : AbstractTestNugetPackageModule { public override string ProjectName => "TUnit.NugetTester.csproj"; } +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [NotInParallel("NugetTester")] public class TestFSharpNugetPackageModule : AbstractTestNugetPackageModule { public override string ProjectName => "TUnit.NugetTester.FSharp.fsproj"; } +[ModuleCategory(PipelineCategories.NuGetPackageTests)] [NotInParallel("NugetTester")] public class TestVBNugetPackageModule : AbstractTestNugetPackageModule { public override string ProjectName => "TUnit.NugetTester.VB.vbproj"; } -[ModuleCategory(PipelineCategories.NuGetPackageTests)] [DependsOn] [DependsOn] public abstract class AbstractTestNugetPackageModule : TestBaseModule From b0e058dac24f0c66cb2dc83ce6585fe939723763 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:04:44 +0100 Subject: [PATCH 4/6] ci: upload diagnostic logs and hang dumps from the Windows NuGet package test job The NuGet package tests no longer run in the Windows modularpipeline job, so its log_*.diag and hangdump* uploads no longer cover them. Upload both from nuget-package-tests-windows too, under job-specific artifact names. --- .github/workflows/dotnet.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index c8435a31030..7433801a4ab 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -297,6 +297,20 @@ jobs: categories: Packaging NuGetPackageTests admin-token: ${{ github.token }} + - name: Upload Diagnostic Logs + uses: actions/upload-artifact@v7.0.2 + if: always() + with: + name: TestingPlatformDiagnosticLogs-nuget-package-tests-windows + path: '**/log_*.diag' + + - name: Upload Hang Dumps + uses: actions/upload-artifact@v7.0.2 + if: always() + with: + name: HangDump-nuget-package-tests-windows + path: '**/hangdump*' + # Compiles the C# fences in the documentation against freshly packed packages, alongside the # test matrix rather than after the Ubuntu pipeline. doc-snippets: From 2dcddee66da2f0a288843c56bdb9c30cfe402886 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:52:48 +0100 Subject: [PATCH 5/6] ci: pass pipeline categories through env, reject conflicting category flags, and fail on an empty library filter --- .github/actions/execute-pipeline/action.yml | 10 +++++++--- .github/workflows/dotnet.yml | 4 ++++ tools/TUnit.Pipeline/Program.cs | 9 ++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/actions/execute-pipeline/action.yml b/.github/actions/execute-pipeline/action.yml index 69b91cbda52..9014fb6a5a6 100644 --- a/.github/actions/execute-pipeline/action.yml +++ b/.github/actions/execute-pipeline/action.yml @@ -35,13 +35,17 @@ runs: - name: Run Pipeline shell: bash run: | - args=(--categories ${{ inputs.categories }}) - if [ -n "${{ inputs.ignore-categories }}" ]; then - args+=(--ignore-categories ${{ inputs.ignore-categories }}) + read -ra categories <<< "$PIPELINE_CATEGORIES" + read -ra ignore_categories <<< "$PIPELINE_IGNORE_CATEGORIES" + args=(--categories "${categories[@]}") + if [ ${#ignore_categories[@]} -gt 0 ]; then + args+=(--ignore-categories "${ignore_categories[@]}") fi dotnet run -c Release --no-build "${args[@]}" working-directory: "tools/TUnit.Pipeline" env: + PIPELINE_CATEGORIES: ${{ inputs.categories }} + PIPELINE_IGNORE_CATEGORIES: ${{ inputs.ignore-categories }} ADMIN_TOKEN: ${{ inputs.admin-token }} GITHUB_TOKEN: ${{ github.token }} DOTNET_ENVIRONMENT: ${{ inputs.environment }} diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 7433801a4ab..41a091b2194 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -288,6 +288,10 @@ jobs: run: | grep -oE 'src/[^"]+\.(cs|fs|vb)proj' TUnit.CI.slnx | grep -v '/content/' \ | jq -R . | jq -s '{solution: {path: "TUnit.CI.slnx", projects: .}}' > libraries.slnf + if [ "$(jq '.solution.projects | length' libraries.slnf)" -eq 0 ]; then + echo "::error::No library projects found in TUnit.CI.slnx; update the filter in this step." + exit 1 + fi dotnet build libraries.slnf -c Release dotnet build tools/TUnit.Pipeline/TUnit.Pipeline.csproj -c Release diff --git a/tools/TUnit.Pipeline/Program.cs b/tools/TUnit.Pipeline/Program.cs index 0d5fde8471d..077e9ff0775 100644 --- a/tools/TUnit.Pipeline/Program.cs +++ b/tools/TUnit.Pipeline/Program.cs @@ -20,13 +20,20 @@ { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = true, - Description = "Categories to skip when no --categories are given.", + Description = "Categories to skip. Cannot be combined with --categories.", DefaultValueFactory = _ => [] }; var rootCommand = new RootCommand("The pipeline for building, testing and packaging TUnit"); rootCommand.Add(categoryOption); rootCommand.Add(ignoreCategoryOption); +rootCommand.Validators.Add(result => +{ + if (result.GetValue(categoryOption) is { Length: > 0 } && result.GetValue(ignoreCategoryOption) is { Length: > 0 }) + { + result.AddError("--ignore-categories cannot be combined with --categories."); + } +}); rootCommand.SetAction(async parseResult => { var categories = parseResult.GetValue(categoryOption)!; From 22a0a8bcb752d35c171a11fbeff5b0911269fba1 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:37:42 +0100 Subject: [PATCH 6/6] ci: stop the Windows NuGet package test job persisting checkout credentials Versioning only reads the fetched history and nothing in the job pushes, so the build steps have no need for the token. Also restores the byte order mark the rebase dropped from PackTUnitFilesModule.cs. Co-Authored-By: Claude --- .github/workflows/dotnet.yml | 2 ++ tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 41a091b2194..e515160551c 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -238,6 +238,8 @@ jobs: - uses: actions/checkout@v7.0.1 with: fetch-depth: 0 + # Versioning reads the fetched history only; nothing in this job pushes. + persist-credentials: false - name: Setup Dev Drive uses: samypr100/setup-dev-drive@v4 diff --git a/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs b/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs index 9e3129a18be..7e539efba46 100644 --- a/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs +++ b/tools/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs @@ -1,4 +1,4 @@ -using ModularPipelines.Attributes; +using ModularPipelines.Attributes; using ModularPipelines.Context; using ModularPipelines.DotNet.Extensions; using ModularPipelines.DotNet.Options;