From f98c55336c5fc82f9f8bc7b4bba932d4fba1a8b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Nov 2026 14:34:18 +0000 Subject: [PATCH] ci: Bump actions/setup-dotnet from 6.0.0 to 6.1.0 Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 6.0.0 to 6.1.0. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/a98b56852c35b8e3190ac28c8c2271da59106c68...0f4a354dd5547a28c70b7853dbd95d5b67886e73) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-and-test.yml | 858 +++++++++++++-------------- .github/workflows/pack.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 431 insertions(+), 431 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 1706098..f604489 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,429 +1,429 @@ -name: Build and test - -# `[both-platforms]` (docs/superpowers/plans/2026-08-22-intest-ci.md): FixtureDocument's own -# comment says a Windows CI agent cannot observe the platform list shrinking, and Task 1 found -# three latent Linux-only defects and one shipped [paired] defect that no Windows-only process -# would have surfaced. Both triggers run both platforms rather than one doing double duty. -# -# `pull_request` (not `pull_request_target`) intentionally runs with the PR head's own -# permissions and secrets exposure -- this repo has no need for the elevated-base-branch access -# `pull_request_target` grants, and reaching for it here would widen exactly the supply-chain -# surface `[pin-actions-by-sha]` exists to narrow. -on: - push: - branches: [main] - pull_request: - -# No job below writes to the repository, opens issues, or needs any token scope beyond reading -# the checkout -- least privilege, not a response to a specific incident. Phrased without a count -# on purpose: this said "Neither job" when there were two, and was still saying it at four. -permissions: - contents: read - -# Every run step below is PowerShell so the same command text is exercised on both platforms -# instead of maintaining a bash dialect and a pwsh dialect that could silently drift apart. -# windows-latest ships PowerShell out of the box; the Linux side was validated locally against -# mcr.microsoft.com/dotnet/sdk:10.0, which carries pwsh 7.6.4 (see the commit message / task -# report for exactly what that validation covered and did not). -defaults: - run: - shell: pwsh - -jobs: - # `[fast-first]`: Architecture + Cli + Runtime is the job every pull request should get a fast - # verdict from. Measured (Task 1, cold cache, 3 repeats, both platforms): ~33.5-35.5s end to - # end. Kept separate from Golden below so a contributor is not made to wait on Golden's ~90-107s - # for feedback these three suites can give in a fraction of that time. - fast: - name: Architecture + Cli + Runtime (${{ matrix.os }}) - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - name: Checkout - # actions/checkout, pinned by commit SHA per [pin-actions-by-sha]: an action runs with - # repository secrets in scope, a strictly larger supply-chain surface than a NuGet - # package, and CONTRIBUTING.md's dependency policy is explicit that a tag is mutable and - # can be repointed after review. Resolved 2026-08-22 via - # gh api repos/actions/checkout/releases/latest --jq '.tag_name' # -> v7.0.1 - # gh api repos/actions/checkout/git/refs/tags/v7.0.1 --jq '.object.sha' - # and the resulting commit was fetched and its date/message checked against the release - # before use, not trusted on the ref name alone. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - # [shallow-clone-is-a-defect] (docs/superpowers/plans/2026-08-23-trunk-based-versioning.md): - # actions/checkout defaults to a depth-1 (shallow) clone, under which MinVer sees no tags - # and silently computes a plausible-looking but wrong version for every commit, with no - # warning at all. Full history is required for MinVer to see tag distance correctly. - # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly if this - # setting is ever dropped from a checkout step -- keep both, the target is the backstop - # this one line can silently stop being, not a replacement for it. - fetch-depth: 0 - - - name: Setup .NET SDK - # actions/setup-dotnet, pinned the same way (releases/latest -> v6.0.0 -> refs/tags -> - # commit, commit verified). No dotnet-version input: this repo's global.json (added in - # Task 1, pinned to 10.0.400 with rollForward: latestFeature, and the reason recorded - # there) is the single source of truth for the SDK version. setup-dotnet's own action.yml - # documents dotnet-version as "Optional ... If not provided, will install global.json - # version when available" -- confirmed by reading action.yml at this pinned commit, not - # assumed from the action's name. A second version string here would be exactly the kind - # of duplicated-by-accident value CLAUDE.md's package-version rule warns about, just for - # the SDK instead of a package. - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - - - name: Cache NuGet packages - # actions/cache, pinned the same way (releases/latest -> v6.1.0 -> refs/tags -> commit, - # commit verified). Deliberate, not absent: restore is a real fraction of the measured - # per-job time. Keyed on Directory.Packages.props -- required, this repo's single source - # of package versions per CLAUDE.md, and "bitten twice by stale-resolution defects" is - # CLAUDE.md's own wording for why a key that can go stale is worse than no cache -- plus - # every .csproj (a new PackageReference changes what gets restored without touching - # Directory.Packages.props) and Directory.Build.props (TFM and other props that feed - # resolution). setup-dotnet has a built-in `cache` input, but it hashes - # packages.lock.json, and this repo has none (checked: no packages.lock.json anywhere - # under tests/, src/, or samples/) -- it would silently cache nothing useful. Using - # actions/cache directly with an explicit key is the only way to satisfy "the key must - # include Directory.Packages.props" precisely. - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} - restore-keys: | - ${{ runner.os }}-nuget- - - # Each suite is invoked against its own .csproj, not the .sln, so this job only ever - # builds Architecture.Tests/Cli.Tests/Runtime.Tests and the two src/ projects they - # reference -- never Golden.Tests or the four samples/ projects, which is what keeps this - # job fast rather than incidentally rebuilding everything the other job also builds. - # --logger's LogFileName is set explicitly so scripts/ci/assert-trx-results.ps1 can find - # each result by a name it chose, rather than parsing dotnet test's timestamp-based default - # naming (which does not encode which project produced which file -- confirmed by direct - # experiment building this workflow: running the whole solution's tests through the default - # logger produced two files differing only by a trailing "[1]"). - - name: Test InTest.Architecture.Tests - run: dotnet test tests/InTest.Architecture.Tests/InTest.Architecture.Tests.csproj --logger "trx;LogFileName=InTest.Architecture.Tests.trx" --results-directory ${{ github.workspace }}/TestResults - - - name: Test InTest.Cli.Tests - run: dotnet test tests/InTest.Cli.Tests/InTest.Cli.Tests.csproj --logger "trx;LogFileName=InTest.Cli.Tests.trx" --results-directory ${{ github.workspace }}/TestResults - - - name: Test InTest.Runtime.Tests - run: dotnet test tests/InTest.Runtime.Tests/InTest.Runtime.Tests.csproj --logger "trx;LogFileName=InTest.Runtime.Tests.trx" --results-directory ${{ github.workspace }}/TestResults - - # InTest.Runtime.XUnit.Tests cannot join the three `dotnet test` steps above. Both InTest.Runtime.MSTest - # and InTest.Runtime.xUnit declare ApiTestBase/TestHost in the same namespace (deliberately -- see - # CLAUDE.md's Runtime section), so the two adapters cannot coexist in one compilation, and this - # suite exists precisely because it tests the xUnit adapter's own internals in isolation - # (tests/InTest.Runtime.XUnit.Tests/XunitDiagnosticsTests.cs). It also cannot run via `dotnet test` - # at all: xunit.v3's VSTest integration is what fails there, the same reason a solution-level - # `dotnet test InTest.sln` now exits 1 even though the MSTest suites inside it still print - # "Passed!" (measured). The project builds as an executable (OutputType=Exe, required by - # xunit.v3), so it is built once and then invoked as `dotnet ` -- never the platform apphost, - # which does not exist on this job's ubuntu-latest leg (no .exe is produced there). This is the - # same defect already found and fixed in the Golden harness's GeneratedSuiteCommand (commit - # a2b96cd) for the identical reason. - - name: Build InTest.Runtime.XUnit.Tests - run: dotnet build tests/InTest.Runtime.XUnit.Tests/InTest.Runtime.XUnit.Tests.csproj - - # `-result-trx` so this suite joins assert-trx-results.ps1's check below instead of being the - # one suite exempt from it. It was exempt because it produces no .trx through `dotnet test`, - # and that exemption was load-bearing in the wrong direction: measured, the runner exits 0 and - # prints "Total: 0" when it discovers nothing, so a regression that stopped discovering - # XunitDiagnosticsTests — the only test in here — left CI green with zero coverage of the - # xUnit adapter's internals. xunit.v3's own runner writes a VSTest .trx that the existing - # script reads unchanged (verified: it carries and a - # naming this assembly, and a zero-test run fails the check). - - name: Test InTest.Runtime.XUnit.Tests - run: dotnet tests/InTest.Runtime.XUnit.Tests/bin/Debug/net10.0/InTest.Runtime.XUnit.Tests.dll -result-trx ${{ github.workspace }}/TestResults/InTest.Runtime.XUnit.Tests.trx - - # InTest.Runtime.NUnit.Tests exists for the identical CS0433 reason as the xUnit suite above - # (InTest.Runtime.MSTest, InTest.Runtime.xUnit and InTest.Runtime.NUnit all declare - # ApiTestBase/TestHost in the same namespace, so no two adapters can share a compilation) -- - # but unlike that suite, this one is a plain `dotnet test ` step: NUnit runs under - # classic VSTest, like MSTest, with no xunit.v3-style "must be executable" requirement and no - # refusal of `dotnet test` on the .NET 10 SDK ([nunit-is-vstest], the NUnit framework pack's - # plan). No direct-dll invocation and no separate build step are needed here. - - name: Test InTest.Runtime.NUnit.Tests - run: dotnet test tests/InTest.Runtime.NUnit.Tests/InTest.Runtime.NUnit.Tests.csproj --logger "trx;LogFileName=InTest.Runtime.NUnit.Tests.trx" --results-directory ${{ github.workspace }}/TestResults - - - name: Assert the suites actually ran - # Step 3 of the plan's Task 2: a green `dotnet test` step does not prove anything ran -- - # see the script's own header for the two source comments and the reasoning this points - # at. Deliberately its own step, after every suite above, so one missing or empty result - # cannot be masked by the others succeeding. Every suite this job runs is named here -- - # phrased without a count on purpose, the way this workflow's own permissions comment is: - # the previous wording said "the three above" while there were five. - run: ./scripts/ci/assert-trx-results.ps1 -ResultsDirectory "${{ github.workspace }}/TestResults" -ExpectedAssembly InTest.Architecture.Tests, InTest.Cli.Tests, InTest.Runtime.Tests, InTest.Runtime.NUnit.Tests, InTest.Runtime.XUnit.Tests - - # `[fast-first]`: Golden is CLAUDE.md's "only suite that proves generated code both compiles - # and runs" -- kept in its own parallel job, not folded into `fast` above, specifically so it - # cannot slow down the fast job's verdict while still running on every push and pull request - # (provisional per the plan: revisit if it ever exceeds 12 minutes wall clock on the slower - # platform -- measured Task 1 worst case was 107.0s on Windows, a 6.7x margin, so the fallback - # to a merge-queue-only run is not triggered today). - golden: - name: Golden (${{ matrix.os }}) - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - # Identical pins and identical reasoning to the `fast` job above -- see those comments for - # how each SHA was resolved. Not factored into a reusable workflow: two jobs is not enough - # duplication to justify the indirection, and CONTRIBUTING.md's "one canonical explanation" - # rule is about reasoning, not about avoiding all repeated YAML. - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - # [shallow-clone-is-a-defect] (docs/superpowers/plans/2026-08-23-trunk-based-versioning.md): - # actions/checkout defaults to a depth-1 (shallow) clone, under which MinVer sees no tags - # and silently computes a plausible-looking but wrong version for every commit, with no - # warning at all. Full history is required for MinVer to see tag distance correctly. - # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly if this - # setting is ever dropped from a checkout step -- keep both, the target is the backstop - # this one line can silently stop being, not a replacement for it. - fetch-depth: 0 - - - name: Setup .NET SDK - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - - - name: Cache NuGet packages - # Same key shape as the `fast` job. Deliberately identical, not job-scoped: both jobs - # restoring the same package set on the same OS should hit the same cache entry rather - # than each maintaining a redundant copy. - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} - restore-keys: | - ${{ runner.os }}-nuget- - - - name: Test InTest.Golden.Tests - # InTest.Golden.Tests shells out to `dotnet build`/`dotnet test` on scaffolded temp - # projects and runs generated suites against an in-process HTTP stub (CLAUDE.md) -- this - # is the ~88-89% of this job's wall clock (GeneratedSuiteExecutionTests, per the plan's - # §18 remeasurement), not restore/build of this repo itself. - run: dotnet test tests/InTest.Golden.Tests/InTest.Golden.Tests.csproj --logger "trx;LogFileName=InTest.Golden.Tests.trx" --results-directory ${{ github.workspace }}/TestResults - - - name: Assert the suite actually ran - run: ./scripts/ci/assert-trx-results.ps1 -ResultsDirectory "${{ github.workspace }}/TestResults" -ExpectedAssembly InTest.Golden.Tests - - # `[dogfood]` (docs/superpowers/plans/2026-08-22-intest-ci.md, Task 3): the three sample specs - # under samples/ (Catalog.Api.json, Inventory.Api.json, Orders.Api.json) are the only - # real-world-shaped, hand-authored, multi-producer OpenAPI documents in this repository, and no - # automated test in this repo's suites runs the generator against any of them -- - # InTest.Golden.Tests uses Specs/orders.json, Specs/hostile-text.json and inline string specs, - # and touches samples/ nowhere. CliExitCodeTests.CheckFlagIsWiredThroughToGenerate already - # ------------------------------------------------------------------------------------------- - # Compile the sample APIs. Nothing else in this workflow does. - # - # Added after a dependency bump reached main with every check green and then failed a local - # `dotnet build InTest.sln`: Dependabot raised Microsoft.Extensions.ApiDescription.Server to - # 10.0.12, whose build-time document generator requires Microsoft.OpenApi 2.12.0, while - # Swashbuckle.AspNetCore 10.2.3 resolves 2.7.5 into samples/Orders.Api. Every job above targets - # a specific tests/*.csproj or src/InTest.Cli, and `dogfood` reads the *committed* - # samples/**/*.json rather than building the APIs that produce them — so all four samples - # could stop compiling without a single check going red. - # - # Deliberately its own job rather than a solution build folded into `fast`: that job's own - # comment records skipping Golden.Tests and the samples as what keeps it fast, and that reasoning - # is still right. This runs in parallel instead of slowing the job that gates every PR. - # - # These are fixtures, not products, but they are the fixtures the committed OpenAPI documents are - # generated *from* — if they cannot build, the corpus every other job reads can no longer be - # regenerated, and it rots silently. - samples: - name: Build the sample APIs (${{ matrix.os }}) - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - # Identical pins and identical reasoning to the `fast` job above -- see those comments for - # how each SHA was resolved. - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - # [shallow-clone-is-a-defect]: MinVer needs full history, and - # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly - # without it. See the `fast` job's copy of this comment for the full reasoning. - fetch-depth: 0 - - - name: Setup .NET SDK - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - - - name: Cache NuGet packages - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} - restore-keys: | - ${{ runner.os }}-nuget- - - # Named individually rather than `dotnet build InTest.sln`, so a failure names the sample - # that broke instead of one line buried in a whole-solution log. Identity.Server is included: - # it has no OpenAPI document, so `dogfood` skips it, which makes this the only place it is - # compiled at all. - - name: Build samples/Catalog.Api - run: dotnet build samples/Catalog.Api/Catalog.Api.csproj - - - name: Build samples/Orders.Api - run: dotnet build samples/Orders.Api/Orders.Api.csproj - - - name: Build samples/Inventory.Api - run: dotnet build samples/Inventory.Api/Inventory.Api.csproj - - - name: Build samples/Identity.Server - run: dotnet build samples/Identity.Server/Identity.Server.csproj - - # exercises init -> generate -> --check -> mutate -> --check through the real CLI, but on a - # trivial inline spec -- what this job adds is coverage of the documents, not the flow. Rev 1 of - # the plan justified this job differently ("catches a template change that leaves the committed - # output of a real project stale"); that was invented -- this repo commits no generated output - # anywhere -- and is withdrawn. samples/Identity.Server is a Duende provider with no spec, so - # three sample directories are dogfooded here, not four. - # - # Scope limit, decided in the plan: no running API, and no `dotnet build` of the scaffolded - # projects. `generate` and `--check` are static, reading only the spec and the committed - # Generated/ output; starting the samples over real HTTP needs the port/issuer/environment - # pairing samples/README.md documents, where getting it wrong produces 500s and silent 404s - # rather than an obvious failure -- exactly the kind of flake the most-run job in this - # repository should not carry. Proving a scaffold actually *compiles* against InTest.Runtime is - # `golden`'s job above, not this one's. - dogfood: - name: Dogfood the sample specs (${{ matrix.os }}) - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - # Identical pins and identical reasoning to the `fast` job above -- see those comments for - # how each SHA was resolved. - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - # [shallow-clone-is-a-defect] (docs/superpowers/plans/2026-08-23-trunk-based-versioning.md): - # actions/checkout defaults to a depth-1 (shallow) clone, under which MinVer sees no tags - # and silently computes a plausible-looking but wrong version for every commit, with no - # warning at all. Full history is required for MinVer to see tag distance correctly. - # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly if this - # setting is ever dropped from a checkout step -- keep both, the target is the backstop - # this one line can silently stop being, not a replacement for it. - fetch-depth: 0 - - - name: Setup .NET SDK - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - - - name: Cache NuGet packages - # Same key shape as the other two jobs, and deliberately identical rather than job-scoped - # -- see the `golden` job's comment above for why a shared cache entry is preferred to a - # redundant per-job one. This job only restores InTest.Cli's own dependencies (it never - # builds a scaffolded project), a strict subset of what `fast` and `golden` already - # restore, so it always hits an entry one of the other two jobs populates rather than - # needing its own. - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} - restore-keys: | - ${{ runner.os }}-nuget- - - # Built once, at Release, so scripts/ci/dogfood.ps1 can invoke the same binary directly - # (`dotnet `) for all five commands x three specs -- 15 separate `dotnet run` builds of - # the identical binary would just be repeated MSBuild evaluation for no new information. - - name: Build InTest.Cli - run: dotnet build src/InTest.Cli/InTest.Cli.csproj -c Release - - # Scaffolds under runner.temp, which GitHub Actions guarantees exists and sits outside - # github.workspace (the checkout) on every runner -- so nothing this step does can dirty the - # working tree, the same isolation every v1-e acceptance run and scripts/local-e2e-test.ps1 - # already use. See scripts/ci/dogfood.ps1's own header for the full sequence and exit-code - # reasoning per spec. - - name: Dogfood the three sample specs - run: >- - ./scripts/ci/dogfood.ps1 - -RepoRoot ${{ github.workspace }} - -ScaffoldRoot ${{ runner.temp }}/intest-dogfood - -CliDll ${{ github.workspace }}/src/InTest.Cli/bin/Release/net10.0/InTest.Cli.dll - - - name: Confirm the working tree is still clean - # Task 3 Step 3. Belt-and-suspenders on top of scaffolding outside the checkout: this is - # what would actually catch a regression if some future change made init/generate write - # somewhere inside the checkout by mistake, rather than trusting that isolation silently. - # Verified during implementation to actually go non-empty and fail this step on a real - # dirty tree, not just written to look like it would (see the task's own commit message). - run: | - $status = git status --porcelain - if ($status) { - Write-Host "::error::Working tree is not clean after the dogfood run:" - Write-Host $status - exit 1 - } - Write-Host "Working tree clean." - - # `[examples-ci]` (docs/superpowers/plans/2026-08-31-intest-cross-framework-examples.md, Task 5 - # Step 2): six committed example projects now live under examples/ -- Catalog and Orders, each - # under MSTest, xUnit and NUnit -- and until this job existed, nothing in CI touched any of them. - # `dogfood` above is the closest existing job in shape, but it deliberately runs against - # samples/, not examples/, and deliberately never builds what it scaffolds (see that job's own - # header comment). InTest.Golden.Tests proves the templates render correctly, but every Golden - # project substitutes a `ProjectReference` for the adapter's `PackageReference` (CLAUDE.md, - # scripts/ci/examples.ps1's own header), so it cannot prove the *published* - # InTest.Runtime.MSTest / InTest.Runtime.xUnit / InTest.Runtime.NUnit packages on nuget.org still - # produce the committed output. This job is what actually restores each example's own local tool - # manifest and PackageReferences from nuget.org and builds the result -- the adopter path, not - # the local build. Deliberate limitation, stated once here rather than left implicit: because - # every example pins a *published* CLI version, this job cannot catch drift introduced by an - # unreleased CLI change -- that is `golden`'s job above, not this one's. See - # scripts/ci/examples.ps1's own header for the full division of labour and the anti-vacuity - # reasoning behind discovering example directories rather than listing them. - examples: - name: Examples (${{ matrix.os }}) - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - # Identical pins and identical reasoning to the `fast` job above -- see those comments for - # how each SHA was resolved. - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - # Every example project inherits the repo-root Directory.Build.props (examples/ has no - # Directory.Build.props of its own -- only a Directory.Packages.props that opts out of - # central package management, see that file's own comment), so `dotnet build` below runs - # InTestEnsureNotShallowClone for each one exactly as it does for src/ and tests/. A - # shallow clone here would fail loudly with that target's own error text, not silently -- - # but fetch-depth: 0 is what avoids hitting that path at all, same as every other job. - fetch-depth: 0 - - - name: Setup .NET SDK - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - - - name: Cache NuGet packages - # Same key shape as the other jobs. examples/Directory.Packages.props and every example - # .csproj are already covered by the existing `**/Directory.Packages.props` and - # `**/*.csproj` globs, so this job's restore (the published InTest.Runtime.MSTest / - # InTest.Runtime.xUnit / InTest.Runtime.NUnit and their own transitive dependencies, all - # resolved from nuget.org rather than src/) needs no key change of its own. - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} - restore-keys: | - ${{ runner.os }}-nuget- - - - name: Restore, check and build every example project - # For every directory under examples/ that carries its own intest.json (discovered, not - # listed -- scripts/ci/examples.ps1's own header has the anti-vacuity reasoning, the same - # ExampleProjectVersionMarkerTests already applies): dotnet tool restore, then - # `dotnet intest generate --check` (must exit 0 -- a non-zero exit means the committed - # Generated/ output disagrees with what the published CLI renders today), then - # `dotnet build`. Fails loudly, by name, if zero directories are discovered at all. - run: ./scripts/ci/examples.ps1 -RepoRoot ${{ github.workspace }} +name: Build and test + +# `[both-platforms]` (docs/superpowers/plans/2026-08-22-intest-ci.md): FixtureDocument's own +# comment says a Windows CI agent cannot observe the platform list shrinking, and Task 1 found +# three latent Linux-only defects and one shipped [paired] defect that no Windows-only process +# would have surfaced. Both triggers run both platforms rather than one doing double duty. +# +# `pull_request` (not `pull_request_target`) intentionally runs with the PR head's own +# permissions and secrets exposure -- this repo has no need for the elevated-base-branch access +# `pull_request_target` grants, and reaching for it here would widen exactly the supply-chain +# surface `[pin-actions-by-sha]` exists to narrow. +on: + push: + branches: [main] + pull_request: + +# No job below writes to the repository, opens issues, or needs any token scope beyond reading +# the checkout -- least privilege, not a response to a specific incident. Phrased without a count +# on purpose: this said "Neither job" when there were two, and was still saying it at four. +permissions: + contents: read + +# Every run step below is PowerShell so the same command text is exercised on both platforms +# instead of maintaining a bash dialect and a pwsh dialect that could silently drift apart. +# windows-latest ships PowerShell out of the box; the Linux side was validated locally against +# mcr.microsoft.com/dotnet/sdk:10.0, which carries pwsh 7.6.4 (see the commit message / task +# report for exactly what that validation covered and did not). +defaults: + run: + shell: pwsh + +jobs: + # `[fast-first]`: Architecture + Cli + Runtime is the job every pull request should get a fast + # verdict from. Measured (Task 1, cold cache, 3 repeats, both platforms): ~33.5-35.5s end to + # end. Kept separate from Golden below so a contributor is not made to wait on Golden's ~90-107s + # for feedback these three suites can give in a fraction of that time. + fast: + name: Architecture + Cli + Runtime (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + # actions/checkout, pinned by commit SHA per [pin-actions-by-sha]: an action runs with + # repository secrets in scope, a strictly larger supply-chain surface than a NuGet + # package, and CONTRIBUTING.md's dependency policy is explicit that a tag is mutable and + # can be repointed after review. Resolved 2026-08-22 via + # gh api repos/actions/checkout/releases/latest --jq '.tag_name' # -> v7.0.1 + # gh api repos/actions/checkout/git/refs/tags/v7.0.1 --jq '.object.sha' + # and the resulting commit was fetched and its date/message checked against the release + # before use, not trusted on the ref name alone. + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # [shallow-clone-is-a-defect] (docs/superpowers/plans/2026-08-23-trunk-based-versioning.md): + # actions/checkout defaults to a depth-1 (shallow) clone, under which MinVer sees no tags + # and silently computes a plausible-looking but wrong version for every commit, with no + # warning at all. Full history is required for MinVer to see tag distance correctly. + # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly if this + # setting is ever dropped from a checkout step -- keep both, the target is the backstop + # this one line can silently stop being, not a replacement for it. + fetch-depth: 0 + + - name: Setup .NET SDK + # actions/setup-dotnet, pinned the same way (releases/latest -> v6.0.0 -> refs/tags -> + # commit, commit verified). No dotnet-version input: this repo's global.json (added in + # Task 1, pinned to 10.0.400 with rollForward: latestFeature, and the reason recorded + # there) is the single source of truth for the SDK version. setup-dotnet's own action.yml + # documents dotnet-version as "Optional ... If not provided, will install global.json + # version when available" -- confirmed by reading action.yml at this pinned commit, not + # assumed from the action's name. A second version string here would be exactly the kind + # of duplicated-by-accident value CLAUDE.md's package-version rule warns about, just for + # the SDK instead of a package. + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 + + - name: Cache NuGet packages + # actions/cache, pinned the same way (releases/latest -> v6.1.0 -> refs/tags -> commit, + # commit verified). Deliberate, not absent: restore is a real fraction of the measured + # per-job time. Keyed on Directory.Packages.props -- required, this repo's single source + # of package versions per CLAUDE.md, and "bitten twice by stale-resolution defects" is + # CLAUDE.md's own wording for why a key that can go stale is worse than no cache -- plus + # every .csproj (a new PackageReference changes what gets restored without touching + # Directory.Packages.props) and Directory.Build.props (TFM and other props that feed + # resolution). setup-dotnet has a built-in `cache` input, but it hashes + # packages.lock.json, and this repo has none (checked: no packages.lock.json anywhere + # under tests/, src/, or samples/) -- it would silently cache nothing useful. Using + # actions/cache directly with an explicit key is the only way to satisfy "the key must + # include Directory.Packages.props" precisely. + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + # Each suite is invoked against its own .csproj, not the .sln, so this job only ever + # builds Architecture.Tests/Cli.Tests/Runtime.Tests and the two src/ projects they + # reference -- never Golden.Tests or the four samples/ projects, which is what keeps this + # job fast rather than incidentally rebuilding everything the other job also builds. + # --logger's LogFileName is set explicitly so scripts/ci/assert-trx-results.ps1 can find + # each result by a name it chose, rather than parsing dotnet test's timestamp-based default + # naming (which does not encode which project produced which file -- confirmed by direct + # experiment building this workflow: running the whole solution's tests through the default + # logger produced two files differing only by a trailing "[1]"). + - name: Test InTest.Architecture.Tests + run: dotnet test tests/InTest.Architecture.Tests/InTest.Architecture.Tests.csproj --logger "trx;LogFileName=InTest.Architecture.Tests.trx" --results-directory ${{ github.workspace }}/TestResults + + - name: Test InTest.Cli.Tests + run: dotnet test tests/InTest.Cli.Tests/InTest.Cli.Tests.csproj --logger "trx;LogFileName=InTest.Cli.Tests.trx" --results-directory ${{ github.workspace }}/TestResults + + - name: Test InTest.Runtime.Tests + run: dotnet test tests/InTest.Runtime.Tests/InTest.Runtime.Tests.csproj --logger "trx;LogFileName=InTest.Runtime.Tests.trx" --results-directory ${{ github.workspace }}/TestResults + + # InTest.Runtime.XUnit.Tests cannot join the three `dotnet test` steps above. Both InTest.Runtime.MSTest + # and InTest.Runtime.xUnit declare ApiTestBase/TestHost in the same namespace (deliberately -- see + # CLAUDE.md's Runtime section), so the two adapters cannot coexist in one compilation, and this + # suite exists precisely because it tests the xUnit adapter's own internals in isolation + # (tests/InTest.Runtime.XUnit.Tests/XunitDiagnosticsTests.cs). It also cannot run via `dotnet test` + # at all: xunit.v3's VSTest integration is what fails there, the same reason a solution-level + # `dotnet test InTest.sln` now exits 1 even though the MSTest suites inside it still print + # "Passed!" (measured). The project builds as an executable (OutputType=Exe, required by + # xunit.v3), so it is built once and then invoked as `dotnet ` -- never the platform apphost, + # which does not exist on this job's ubuntu-latest leg (no .exe is produced there). This is the + # same defect already found and fixed in the Golden harness's GeneratedSuiteCommand (commit + # a2b96cd) for the identical reason. + - name: Build InTest.Runtime.XUnit.Tests + run: dotnet build tests/InTest.Runtime.XUnit.Tests/InTest.Runtime.XUnit.Tests.csproj + + # `-result-trx` so this suite joins assert-trx-results.ps1's check below instead of being the + # one suite exempt from it. It was exempt because it produces no .trx through `dotnet test`, + # and that exemption was load-bearing in the wrong direction: measured, the runner exits 0 and + # prints "Total: 0" when it discovers nothing, so a regression that stopped discovering + # XunitDiagnosticsTests — the only test in here — left CI green with zero coverage of the + # xUnit adapter's internals. xunit.v3's own runner writes a VSTest .trx that the existing + # script reads unchanged (verified: it carries and a + # naming this assembly, and a zero-test run fails the check). + - name: Test InTest.Runtime.XUnit.Tests + run: dotnet tests/InTest.Runtime.XUnit.Tests/bin/Debug/net10.0/InTest.Runtime.XUnit.Tests.dll -result-trx ${{ github.workspace }}/TestResults/InTest.Runtime.XUnit.Tests.trx + + # InTest.Runtime.NUnit.Tests exists for the identical CS0433 reason as the xUnit suite above + # (InTest.Runtime.MSTest, InTest.Runtime.xUnit and InTest.Runtime.NUnit all declare + # ApiTestBase/TestHost in the same namespace, so no two adapters can share a compilation) -- + # but unlike that suite, this one is a plain `dotnet test ` step: NUnit runs under + # classic VSTest, like MSTest, with no xunit.v3-style "must be executable" requirement and no + # refusal of `dotnet test` on the .NET 10 SDK ([nunit-is-vstest], the NUnit framework pack's + # plan). No direct-dll invocation and no separate build step are needed here. + - name: Test InTest.Runtime.NUnit.Tests + run: dotnet test tests/InTest.Runtime.NUnit.Tests/InTest.Runtime.NUnit.Tests.csproj --logger "trx;LogFileName=InTest.Runtime.NUnit.Tests.trx" --results-directory ${{ github.workspace }}/TestResults + + - name: Assert the suites actually ran + # Step 3 of the plan's Task 2: a green `dotnet test` step does not prove anything ran -- + # see the script's own header for the two source comments and the reasoning this points + # at. Deliberately its own step, after every suite above, so one missing or empty result + # cannot be masked by the others succeeding. Every suite this job runs is named here -- + # phrased without a count on purpose, the way this workflow's own permissions comment is: + # the previous wording said "the three above" while there were five. + run: ./scripts/ci/assert-trx-results.ps1 -ResultsDirectory "${{ github.workspace }}/TestResults" -ExpectedAssembly InTest.Architecture.Tests, InTest.Cli.Tests, InTest.Runtime.Tests, InTest.Runtime.NUnit.Tests, InTest.Runtime.XUnit.Tests + + # `[fast-first]`: Golden is CLAUDE.md's "only suite that proves generated code both compiles + # and runs" -- kept in its own parallel job, not folded into `fast` above, specifically so it + # cannot slow down the fast job's verdict while still running on every push and pull request + # (provisional per the plan: revisit if it ever exceeds 12 minutes wall clock on the slower + # platform -- measured Task 1 worst case was 107.0s on Windows, a 6.7x margin, so the fallback + # to a merge-queue-only run is not triggered today). + golden: + name: Golden (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + # Identical pins and identical reasoning to the `fast` job above -- see those comments for + # how each SHA was resolved. Not factored into a reusable workflow: two jobs is not enough + # duplication to justify the indirection, and CONTRIBUTING.md's "one canonical explanation" + # rule is about reasoning, not about avoiding all repeated YAML. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # [shallow-clone-is-a-defect] (docs/superpowers/plans/2026-08-23-trunk-based-versioning.md): + # actions/checkout defaults to a depth-1 (shallow) clone, under which MinVer sees no tags + # and silently computes a plausible-looking but wrong version for every commit, with no + # warning at all. Full history is required for MinVer to see tag distance correctly. + # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly if this + # setting is ever dropped from a checkout step -- keep both, the target is the backstop + # this one line can silently stop being, not a replacement for it. + fetch-depth: 0 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 + + - name: Cache NuGet packages + # Same key shape as the `fast` job. Deliberately identical, not job-scoped: both jobs + # restoring the same package set on the same OS should hit the same cache entry rather + # than each maintaining a redundant copy. + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Test InTest.Golden.Tests + # InTest.Golden.Tests shells out to `dotnet build`/`dotnet test` on scaffolded temp + # projects and runs generated suites against an in-process HTTP stub (CLAUDE.md) -- this + # is the ~88-89% of this job's wall clock (GeneratedSuiteExecutionTests, per the plan's + # §18 remeasurement), not restore/build of this repo itself. + run: dotnet test tests/InTest.Golden.Tests/InTest.Golden.Tests.csproj --logger "trx;LogFileName=InTest.Golden.Tests.trx" --results-directory ${{ github.workspace }}/TestResults + + - name: Assert the suite actually ran + run: ./scripts/ci/assert-trx-results.ps1 -ResultsDirectory "${{ github.workspace }}/TestResults" -ExpectedAssembly InTest.Golden.Tests + + # `[dogfood]` (docs/superpowers/plans/2026-08-22-intest-ci.md, Task 3): the three sample specs + # under samples/ (Catalog.Api.json, Inventory.Api.json, Orders.Api.json) are the only + # real-world-shaped, hand-authored, multi-producer OpenAPI documents in this repository, and no + # automated test in this repo's suites runs the generator against any of them -- + # InTest.Golden.Tests uses Specs/orders.json, Specs/hostile-text.json and inline string specs, + # and touches samples/ nowhere. CliExitCodeTests.CheckFlagIsWiredThroughToGenerate already + # ------------------------------------------------------------------------------------------- + # Compile the sample APIs. Nothing else in this workflow does. + # + # Added after a dependency bump reached main with every check green and then failed a local + # `dotnet build InTest.sln`: Dependabot raised Microsoft.Extensions.ApiDescription.Server to + # 10.0.12, whose build-time document generator requires Microsoft.OpenApi 2.12.0, while + # Swashbuckle.AspNetCore 10.2.3 resolves 2.7.5 into samples/Orders.Api. Every job above targets + # a specific tests/*.csproj or src/InTest.Cli, and `dogfood` reads the *committed* + # samples/**/*.json rather than building the APIs that produce them — so all four samples + # could stop compiling without a single check going red. + # + # Deliberately its own job rather than a solution build folded into `fast`: that job's own + # comment records skipping Golden.Tests and the samples as what keeps it fast, and that reasoning + # is still right. This runs in parallel instead of slowing the job that gates every PR. + # + # These are fixtures, not products, but they are the fixtures the committed OpenAPI documents are + # generated *from* — if they cannot build, the corpus every other job reads can no longer be + # regenerated, and it rots silently. + samples: + name: Build the sample APIs (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + # Identical pins and identical reasoning to the `fast` job above -- see those comments for + # how each SHA was resolved. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # [shallow-clone-is-a-defect]: MinVer needs full history, and + # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly + # without it. See the `fast` job's copy of this comment for the full reasoning. + fetch-depth: 0 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 + + - name: Cache NuGet packages + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + # Named individually rather than `dotnet build InTest.sln`, so a failure names the sample + # that broke instead of one line buried in a whole-solution log. Identity.Server is included: + # it has no OpenAPI document, so `dogfood` skips it, which makes this the only place it is + # compiled at all. + - name: Build samples/Catalog.Api + run: dotnet build samples/Catalog.Api/Catalog.Api.csproj + + - name: Build samples/Orders.Api + run: dotnet build samples/Orders.Api/Orders.Api.csproj + + - name: Build samples/Inventory.Api + run: dotnet build samples/Inventory.Api/Inventory.Api.csproj + + - name: Build samples/Identity.Server + run: dotnet build samples/Identity.Server/Identity.Server.csproj + + # exercises init -> generate -> --check -> mutate -> --check through the real CLI, but on a + # trivial inline spec -- what this job adds is coverage of the documents, not the flow. Rev 1 of + # the plan justified this job differently ("catches a template change that leaves the committed + # output of a real project stale"); that was invented -- this repo commits no generated output + # anywhere -- and is withdrawn. samples/Identity.Server is a Duende provider with no spec, so + # three sample directories are dogfooded here, not four. + # + # Scope limit, decided in the plan: no running API, and no `dotnet build` of the scaffolded + # projects. `generate` and `--check` are static, reading only the spec and the committed + # Generated/ output; starting the samples over real HTTP needs the port/issuer/environment + # pairing samples/README.md documents, where getting it wrong produces 500s and silent 404s + # rather than an obvious failure -- exactly the kind of flake the most-run job in this + # repository should not carry. Proving a scaffold actually *compiles* against InTest.Runtime is + # `golden`'s job above, not this one's. + dogfood: + name: Dogfood the sample specs (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + # Identical pins and identical reasoning to the `fast` job above -- see those comments for + # how each SHA was resolved. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # [shallow-clone-is-a-defect] (docs/superpowers/plans/2026-08-23-trunk-based-versioning.md): + # actions/checkout defaults to a depth-1 (shallow) clone, under which MinVer sees no tags + # and silently computes a plausible-looking but wrong version for every commit, with no + # warning at all. Full history is required for MinVer to see tag distance correctly. + # Directory.Build.props' InTestEnsureNotShallowClone target fails the build loudly if this + # setting is ever dropped from a checkout step -- keep both, the target is the backstop + # this one line can silently stop being, not a replacement for it. + fetch-depth: 0 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 + + - name: Cache NuGet packages + # Same key shape as the other two jobs, and deliberately identical rather than job-scoped + # -- see the `golden` job's comment above for why a shared cache entry is preferred to a + # redundant per-job one. This job only restores InTest.Cli's own dependencies (it never + # builds a scaffolded project), a strict subset of what `fast` and `golden` already + # restore, so it always hits an entry one of the other two jobs populates rather than + # needing its own. + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + # Built once, at Release, so scripts/ci/dogfood.ps1 can invoke the same binary directly + # (`dotnet `) for all five commands x three specs -- 15 separate `dotnet run` builds of + # the identical binary would just be repeated MSBuild evaluation for no new information. + - name: Build InTest.Cli + run: dotnet build src/InTest.Cli/InTest.Cli.csproj -c Release + + # Scaffolds under runner.temp, which GitHub Actions guarantees exists and sits outside + # github.workspace (the checkout) on every runner -- so nothing this step does can dirty the + # working tree, the same isolation every v1-e acceptance run and scripts/local-e2e-test.ps1 + # already use. See scripts/ci/dogfood.ps1's own header for the full sequence and exit-code + # reasoning per spec. + - name: Dogfood the three sample specs + run: >- + ./scripts/ci/dogfood.ps1 + -RepoRoot ${{ github.workspace }} + -ScaffoldRoot ${{ runner.temp }}/intest-dogfood + -CliDll ${{ github.workspace }}/src/InTest.Cli/bin/Release/net10.0/InTest.Cli.dll + + - name: Confirm the working tree is still clean + # Task 3 Step 3. Belt-and-suspenders on top of scaffolding outside the checkout: this is + # what would actually catch a regression if some future change made init/generate write + # somewhere inside the checkout by mistake, rather than trusting that isolation silently. + # Verified during implementation to actually go non-empty and fail this step on a real + # dirty tree, not just written to look like it would (see the task's own commit message). + run: | + $status = git status --porcelain + if ($status) { + Write-Host "::error::Working tree is not clean after the dogfood run:" + Write-Host $status + exit 1 + } + Write-Host "Working tree clean." + + # `[examples-ci]` (docs/superpowers/plans/2026-08-31-intest-cross-framework-examples.md, Task 5 + # Step 2): six committed example projects now live under examples/ -- Catalog and Orders, each + # under MSTest, xUnit and NUnit -- and until this job existed, nothing in CI touched any of them. + # `dogfood` above is the closest existing job in shape, but it deliberately runs against + # samples/, not examples/, and deliberately never builds what it scaffolds (see that job's own + # header comment). InTest.Golden.Tests proves the templates render correctly, but every Golden + # project substitutes a `ProjectReference` for the adapter's `PackageReference` (CLAUDE.md, + # scripts/ci/examples.ps1's own header), so it cannot prove the *published* + # InTest.Runtime.MSTest / InTest.Runtime.xUnit / InTest.Runtime.NUnit packages on nuget.org still + # produce the committed output. This job is what actually restores each example's own local tool + # manifest and PackageReferences from nuget.org and builds the result -- the adopter path, not + # the local build. Deliberate limitation, stated once here rather than left implicit: because + # every example pins a *published* CLI version, this job cannot catch drift introduced by an + # unreleased CLI change -- that is `golden`'s job above, not this one's. See + # scripts/ci/examples.ps1's own header for the full division of labour and the anti-vacuity + # reasoning behind discovering example directories rather than listing them. + examples: + name: Examples (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + # Identical pins and identical reasoning to the `fast` job above -- see those comments for + # how each SHA was resolved. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Every example project inherits the repo-root Directory.Build.props (examples/ has no + # Directory.Build.props of its own -- only a Directory.Packages.props that opts out of + # central package management, see that file's own comment), so `dotnet build` below runs + # InTestEnsureNotShallowClone for each one exactly as it does for src/ and tests/. A + # shallow clone here would fail loudly with that target's own error text, not silently -- + # but fetch-depth: 0 is what avoids hitting that path at all, same as every other job. + fetch-depth: 0 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 + + - name: Cache NuGet packages + # Same key shape as the other jobs. examples/Directory.Packages.props and every example + # .csproj are already covered by the existing `**/Directory.Packages.props` and + # `**/*.csproj` globs, so this job's restore (the published InTest.Runtime.MSTest / + # InTest.Runtime.xUnit / InTest.Runtime.NUnit and their own transitive dependencies, all + # resolved from nuget.org rather than src/) needs no key change of its own. + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj', 'Directory.Build.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Restore, check and build every example project + # For every directory under examples/ that carries its own intest.json (discovered, not + # listed -- scripts/ci/examples.ps1's own header has the anti-vacuity reasoning, the same + # ExampleProjectVersionMarkerTests already applies): dotnet tool restore, then + # `dotnet intest generate --check` (must exit 0 -- a non-zero exit means the committed + # Generated/ output disagrees with what the published CLI renders today), then + # `dotnet build`. Fails loudly, by name, if zero directories are discovered at all. + run: ./scripts/ci/examples.ps1 -RepoRoot ${{ github.workspace }} diff --git a/.github/workflows/pack.yml b/.github/workflows/pack.yml index a04bd9c..379a1e2 100644 --- a/.github/workflows/pack.yml +++ b/.github/workflows/pack.yml @@ -55,7 +55,7 @@ jobs: fetch-depth: 0 - name: Setup .NET SDK - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 - name: Cache NuGet packages # Same key shape as build-and-test.yml's three jobs, and deliberately identical rather diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ded97f0..7ea8129 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -185,7 +185,7 @@ jobs: fetch-depth: 0 - name: Setup .NET SDK - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + uses: actions/setup-dotnet@0f4a354dd5547a28c70b7853dbd95d5b67886e73 # v6.1.0 - name: Cache NuGet packages # Identical key shape to pack.yml/build-and-test.yml -- see those files' comments for why