diff --git a/.github/workflows/build-docker-task.yml b/.github/workflows/build-docker-task.yml index 25fc27bb..d2e22676 100644 --- a/.github/workflows/build-docker-task.yml +++ b/.github/workflows/build-docker-task.yml @@ -42,7 +42,7 @@ jobs: steps: - name: Checkout step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/build-executable-task.yml b/.github/workflows/build-executable-task.yml index a4a821c5..ab5add7e 100644 --- a/.github/workflows/build-executable-task.yml +++ b/.github/workflows/build-executable-task.yml @@ -42,12 +42,12 @@ jobs: # No NuGet restore caching: restore is cheap here, and setup-dotnet's cache needs a packages.lock.json that # Central Package Management doesn't produce by default. - name: Setup .NET SDK step - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: dotnet-version: 10.x - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ inputs.ref }} @@ -68,7 +68,7 @@ jobs: # job is `!smoke`, so the per-runtime output would have no consumer. - name: Upload matrix build artifacts step if: ${{ !inputs.smoke }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: publish-${{ inputs.branch }}-${{ matrix.runtime }} path: ${{ runner.temp }}/publish @@ -86,7 +86,7 @@ jobs: steps: - name: Download matrix build artifacts step - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: publish-${{ inputs.branch }}-* merge-multiple: true @@ -98,7 +98,7 @@ jobs: # GitHub-release asset, uploaded under the `release-asset--*` pattern that the `github-release` job # collects. Branch-suffixed so the publisher can build both branches in one run without colliding on the name. - name: Upload build artifacts step - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: release-asset-${{ inputs.branch }}-executable path: ${{ runner.temp }}/Console.7z diff --git a/.github/workflows/build-nugetlibrary-task.yml b/.github/workflows/build-nugetlibrary-task.yml index 7933c121..a0311beb 100644 --- a/.github/workflows/build-nugetlibrary-task.yml +++ b/.github/workflows/build-nugetlibrary-task.yml @@ -41,12 +41,12 @@ jobs: steps: - name: Setup .NET SDK step - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: dotnet-version: 10.x - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ inputs.ref }} @@ -81,7 +81,7 @@ jobs: # Skipped on smoke: the github-release job is `!smoke`, so nothing would consume it. - name: Upload build artifacts step if: ${{ !inputs.smoke }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: release-asset-${{ inputs.branch }}-nugetlibrary path: ${{ runner.temp }}/NuGetLibrary.7z diff --git a/.github/workflows/build-pypilibrary-task.yml b/.github/workflows/build-pypilibrary-task.yml index faebbce2..61885a54 100644 --- a/.github/workflows/build-pypilibrary-task.yml +++ b/.github/workflows/build-pypilibrary-task.yml @@ -51,7 +51,7 @@ jobs: steps: - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ inputs.ref }} @@ -113,7 +113,7 @@ jobs: - name: Upload build artifacts step id: artifact-upload-step if: ${{ !inputs.smoke }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: pypilibrary-build-${{ inputs.branch }} path: PyPiLibrary/dist/* diff --git a/.github/workflows/build-release-task.yml b/.github/workflows/build-release-task.yml index bfb10f99..f2a63b22 100644 --- a/.github/workflows/build-release-task.yml +++ b/.github/workflows/build-release-task.yml @@ -130,7 +130,7 @@ jobs: # Check out the exact built commit so the uploaded release files match the tag even if the branch advances mid-run. - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ needs.get-version.outputs.GitCommitId }} @@ -153,7 +153,7 @@ jobs: # yields a valid file-less release. Subset releases by deleting the target, not `enable_*: false` (a skipped # `needs` job would skip this release job too). - name: Download release asset artifacts step - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: release-asset-${{ inputs.branch }}-* merge-multiple: true diff --git a/.github/workflows/check-upstream-version-task.yml b/.github/workflows/check-upstream-version-task.yml index 6dcbc94a..72fab1e6 100644 --- a/.github/workflows/check-upstream-version-task.yml +++ b/.github/workflows/check-upstream-version-task.yml @@ -56,7 +56,7 @@ jobs: private-key: ${{ secrets.CODEGEN_APP_PRIVATE_KEY }} - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ matrix.branch }} token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/get-version-task.yml b/.github/workflows/get-version-task.yml index 38cf4535..900e0630 100644 --- a/.github/workflows/get-version-task.yml +++ b/.github/workflows/get-version-task.yml @@ -37,12 +37,12 @@ jobs: steps: - name: Setup .NET SDK step - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: dotnet-version: 10.x - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ inputs.ref }} fetch-depth: 0 diff --git a/.github/workflows/publish-docker-readme-task.yml b/.github/workflows/publish-docker-readme-task.yml index 4b04ad64..f7ac5f97 100644 --- a/.github/workflows/publish-docker-readme-task.yml +++ b/.github/workflows/publish-docker-readme-task.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Check out the branch being published so the main leg pushes main's readme regardless of the triggering ref. ref: ${{ inputs.branch }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index b1656674..93d83ea9 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -110,7 +110,7 @@ jobs: steps: - name: Download PyPI library build artifacts step - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: # Branch-suffixed name so both branch legs in this run stay distinct. name: pypilibrary-build-${{ matrix.branch }} diff --git a/.github/workflows/run-codegen-pull-request-task.yml b/.github/workflows/run-codegen-pull-request-task.yml index 3d802810..34a56640 100644 --- a/.github/workflows/run-codegen-pull-request-task.yml +++ b/.github/workflows/run-codegen-pull-request-task.yml @@ -42,12 +42,12 @@ jobs: private-key: ${{ secrets.CODEGEN_APP_PRIVATE_KEY }} - name: Setup .NET SDK step - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: dotnet-version: 10.x - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ matrix.target.ref }} token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/test-pull-request.yml b/.github/workflows/test-pull-request.yml index 45774261..838f90bc 100644 --- a/.github/workflows/test-pull-request.yml +++ b/.github/workflows/test-pull-request.yml @@ -63,12 +63,12 @@ jobs: steps: - name: Setup .NET SDK step - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: dotnet-version: 10.x - name: Checkout code step - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Restore .NET local tools step run: dotnet tool restore diff --git a/AGENTS.md b/AGENTS.md index 689e1c3a..b359b296 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ The template uses a **two-phase model by default**: PRs build fast, publishing i - **Required check.** The `changes` job is in the `Check pull request workflow status` aggregator's `needs` and **must succeed** (not just "not fail") - a paths-filter error must never let a target-changing PR merge with its smoke build silently skipped. Skipped smoke jobs (no matching change) pass; `failure`/`cancelled` blocks. - **Reusable-task parameter contract.** Every `build-*-task.yml` and `build-release-task.yml` takes `ref` (git ref to check out/version), `branch` (logical branch driving config/tags/prerelease - `main` => Release/`latest`/non-prerelease, else Debug/`develop`/prerelease), and where relevant `smoke`. **Branch-derived config keys off `inputs.branch`, never `github.ref_name`** - the publisher's matrix builds `develop` from a run whose `github.ref_name` is `main`, so `ref_name` would be wrong. Artifact names are branch-suffixed so both matrix legs coexist in one run. `get-version-task.yml` takes a `ref` so NBGV versions the right branch. - **Per-target subsetting (derived projects).** `build-release-task.yml` has per-target `enable_*` gates and self-contained leaf tasks, so a project that drops a target deletes: its `build--task.yml`, the matching job + `github-release` `needs` entry in `build-release-task.yml`, its path-filter entry in `test-pull-request.yml`, and (for PyPI) the `publish-pypi` job in `publish-release.yml`. CodeGen, versioning, badge, merge-bot, and Dependabot are target-agnostic. -- **Orchestration vs. build - the override seam.** The pipeline splits into two layers. The **orchestration** layer is generic and meant to be synced verbatim from upstream: [`publish-release.yml`](./.github/workflows/publish-release.yml) (publish plan + branch matrix), the `get-version` + `github-release` jobs inside [`build-release-task.yml`](./.github/workflows/build-release-task.yml), [`get-version-task.yml`](./.github/workflows/get-version-task.yml), [`build-datebadge-task.yml`](./.github/workflows/build-datebadge-task.yml), and the aggregator shape of [`test-pull-request.yml`](./.github/workflows/test-pull-request.yml). Within `test-pull-request.yml`, only the `changes -> smoke-build -> check-workflow-status` aggregator wiring and the ruleset-bound job name are verbatim orchestration; the `unit-test` job and the `dorny/paths-filter` entries are owned/per-target. The **build** layer - the `build--task.yml` leaf tasks - is what a derived project owns and replaces. The contract that keeps the seam clean: **a target contributes files to the GitHub release by uploading a workflow artifact named `release-asset--`.** The `github-release` job collects every `release-asset--*` artifact by pattern and **never names a build job**, so it (the tag-the-commit + create-the-release + attach-the-assets logic) is reusable **verbatim** - that is the part a downstream previously had to fork and rewrite, and no longer does. +- **Orchestration vs. build - the override seam.** The pipeline splits into two layers. The **orchestration** layer is generic and meant to be synced verbatim from upstream: [`publish-release.yml`](./.github/workflows/publish-release.yml) (publish plan + branch matrix), the `get-version` + `github-release` jobs inside [`build-release-task.yml`](./.github/workflows/build-release-task.yml), [`get-version-task.yml`](./.github/workflows/get-version-task.yml), [`build-datebadge-task.yml`](./.github/workflows/build-datebadge-task.yml), and the aggregator shape of [`test-pull-request.yml`](./.github/workflows/test-pull-request.yml). Within `test-pull-request.yml`, only the `changes -> smoke-build -> check-workflow-status` aggregator wiring and the ruleset-bound job name are verbatim orchestration; the `unit-test` job and the `dorny/paths-filter` entries are owned/per-target. The **build** layer - the `build--task.yml` leaf tasks - is what a derived project owns and replaces. The contract that keeps the seam clean: **a target contributes files to the GitHub release by uploading a workflow artifact named `release-asset--`.** The `github-release` job collects every `release-asset--*` artifact by pattern and **never names a build job**, so it (the tag-the-commit + create-the-release + attach-the-assets logic) is reusable **verbatim** - that is the part a downstream previously had to fork and rewrite, and no longer does. **This name-pattern handoff is canonical for every repo, single-target included** - name your one asset `release-asset--` and the verbatim `github-release` globs it; do not switch a single-target repo to an `artifact-id` output plus `download-artifact` `artifact-ids:`, which looks tidier for 1:1 but forks the `github-release` download (`pattern:`/`merge-multiple:`) and breaks its verbatim carry. - **What a downstream still curates** (this is by design, not a leak): the *list* of leaf jobs in `build-release-task.yml`. Per **Per-target subsetting** above, you delete the target jobs you don't ship and add the one(s) you do - `build-release-task.yml`'s `github-release` job is untouched, but the file is not byte-identical because its `needs`/job list reflects your targets. Making that list itself target-agnostic is a larger "factor build from orchestration" refactor that is intentionally **not** done. - **Map your outputs to the right seam** - pick by where each artifact *goes*, not by language: - *Files attached to the GitHub Release* (zips, binaries, packaged libraries): one leaf task per output, each uploading `release-asset--`. A data-only repo (e.g. a symbol library) has exactly one such task: validate -> `zip` -> upload `release-asset--library`; it deletes the nuget/pypi/executable/docker jobs and the `publish-pypi` job, keeps `github-release` as-is. This is also where the .NET `build-executable-task` lives - it is *not* a generic file step, it is specifically `dotnet publish` of the console app; replace it wholesale, don't adapt it.