Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ and project-path inputs its targets need.

Pick by where each artifact *goes*, not by language:

- **Files attached to the GitHub Release** (zips, binaries, packaged libraries): a build-executable
- **Files attached to the GitHub Release** (zips, binaries, packaged libraries): a dotnet-publish
or build-nuget hook per output, each uploading `release-asset-<branch>-<name>`. This is where the
Comment thread
ptr727 marked this conversation as resolved.
Outdated
.NET `dotnet publish` or `dotnet build` and package push lives. The hub default takes an explicit
project path, and a project needing different build behavior replaces the hook. A data-only
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/fleet-skills/.source-digest
Original file line number Diff line number Diff line change
@@ -1 +1 @@
79a65cdb22c0eb39
2ada9ef3366cecec
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ and project-path inputs its targets need.

Pick by where each artifact *goes*, not by language:

- **Files attached to the GitHub Release** (zips, binaries, packaged libraries): a build-executable
- **Files attached to the GitHub Release** (zips, binaries, packaged libraries): a dotnet-publish
or build-nuget hook per output, each uploading `release-asset-<branch>-<name>`. This is where the
Comment thread
ptr727 marked this conversation as resolved.
Outdated
.NET `dotnet publish` or `dotnet build` and package push lives. The hub default takes an explicit
project path, and a project needing different build behavior replaces the hook. A data-only
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/dotnet-publish-default/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ runs:
if: ${{ inputs.smoke != 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-asset-${{ inputs.branch }}-executable
name: release-asset-${{ inputs.branch }}-dotnet-publish
path: ${{ steps.zip.outputs.asset-path }}
# Consumed within the run by the github-release job, so minimize artifact storage.
retention-days: 1
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ and project-path inputs its targets need.

Pick by where each artifact *goes*, not by language:

- **Files attached to the GitHub Release** (zips, binaries, packaged libraries): a build-executable
- **Files attached to the GitHub Release** (zips, binaries, packaged libraries): a dotnet-publish
or build-nuget hook per output, each uploading `release-asset-<branch>-<name>`. This is where the
Comment thread
ptr727 marked this conversation as resolved.
Outdated
.NET `dotnet publish` or `dotnet build` and package push lives. The hub default takes an explicit
project path, and a project needing different build behavior replaces the hook. A data-only
Expand Down
32 changes: 16 additions & 16 deletions .github/workflows/build-release-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ on:
required: false
type: boolean
default: true
enable_executable:
enable_dotnet_publish:
required: false
type: boolean
default: true
Expand All @@ -84,12 +84,12 @@ on:
type: boolean
default: false
# Project paths forwarded to the hub default hooks.
executable_project:
dotnet_publish_project:
required: false
type: string
default: ''
# The release archive's name without .7z, derived from the project file's stem when empty.
executable_asset_name:
dotnet_publish_asset_name:
required: false
type: string
default: ''
Expand Down Expand Up @@ -158,9 +158,9 @@ jobs:
exit 1
fi

build-executable:
name: Build executable job
if: ${{ inputs.enable_executable }}
dotnet-publish:
name: Publish .NET project job
if: ${{ inputs.enable_dotnet_publish }}
needs: [get-version, validate-release]
runs-on: ubuntu-latest
steps:
Expand All @@ -172,20 +172,20 @@ jobs:
ref: ${{ needs.get-version.outputs.GitCommitId }}

# A caller's own hook names its archive itself, so the asset name input reaches only the hub default.
- name: Run caller build-executable hook step
if: ${{ hashFiles('.github/actions/build-executable/action.yml') != '' }}
uses: ./.github/actions/build-executable
- name: Run caller dotnet-publish hook step
if: ${{ hashFiles('.github/actions/dotnet-publish/action.yml') != '' }}
uses: ./.github/actions/dotnet-publish
with:
branch: ${{ inputs.branch }}
smoke: ${{ inputs.smoke }}
semver2: ${{ needs.get-version.outputs.SemVer2 }}
assembly-version: ${{ needs.get-version.outputs.AssemblyVersion }}
assembly-file-version: ${{ needs.get-version.outputs.AssemblyFileVersion }}
assembly-informational-version: ${{ needs.get-version.outputs.AssemblyInformationalVersion }}
project-file: ${{ inputs.executable_project }}
project-file: ${{ inputs.dotnet_publish_project }}

- name: Run hub build-executable default step
if: ${{ hashFiles('.github/actions/build-executable/action.yml') == '' }}
- name: Run hub dotnet-publish default step
if: ${{ hashFiles('.github/actions/dotnet-publish/action.yml') == '' }}
uses: $/.github/actions/dotnet-publish-default
with:
branch: ${{ inputs.branch }}
Expand All @@ -194,8 +194,8 @@ jobs:
assembly-version: ${{ needs.get-version.outputs.AssemblyVersion }}
assembly-file-version: ${{ needs.get-version.outputs.AssemblyFileVersion }}
assembly-informational-version: ${{ needs.get-version.outputs.AssemblyInformationalVersion }}
project-file: ${{ inputs.executable_project }}
asset-name: ${{ inputs.executable_asset_name }}
project-file: ${{ inputs.dotnet_publish_project }}
asset-name: ${{ inputs.dotnet_publish_asset_name }}

build-nuget:
name: Build NuGet library job
Expand Down Expand Up @@ -276,7 +276,7 @@ jobs:

build-docker:
name: Build Docker image job
needs: [get-version, validate-release, build-executable, build-nuget, build-pypi]
needs: [get-version, validate-release, dotnet-publish, build-nuget, build-pypi]
if: ${{ inputs.enable_docker && !failure() && !cancelled() }}
uses: $/.github/workflows/build-docker-task.yml
secrets:
Expand Down Expand Up @@ -304,7 +304,7 @@ jobs:
# The explicit functions replace that implicit success() instead, tolerating a skipped need while still failing closed on a real failure.
if: ${{ inputs.github && !inputs.smoke && !failure() && !cancelled() }}
runs-on: ubuntu-latest
needs: [get-version, validate-release, build-executable, build-nuget, build-pypi, build-docker]
needs: [get-version, validate-release, dotnet-publish, build-nuget, build-pypi, build-docker]
# The release upload and the artifact-delete cleanup both write with GITHUB_TOKEN, and the caller grants contents: write and actions: write when it sets github: true on a non-smoke run.
# A caller publishing only to a registry, or smoke building, leaves this job disabled and grants neither.
# No job-level permissions: block here, for the reason build-nuget gives: a block is validated against the caller's grant before if: runs, and a smoke caller holds a read-only token.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@ jobs:
enable_docker: false
enable_nuget: false
enable_pypi: false
enable_executable: false
enable_dotnet_publish: false
# This repo is source-only, so the release is just the tag + source zip + README + LICENSE.
expect_release_assets: false
6 changes: 3 additions & 3 deletions WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ A target contributes a file to the GitHub release by uploading a workflow artifa

```mermaid
flowchart LR
leafa[leaf: target A] -->|release-asset-branch-A| store[(run artifacts)]
leafb[leaf: target B] -->|release-asset-branch-B| store
dotnet[dotnet-publish] -->|release-asset-branch-dotnet-publish| store[(run artifacts)]
nuget[build-nuget] -->|release-asset-branch-nuget| store
Comment thread
Copilot marked this conversation as resolved.
Outdated
store -->|pattern + merge-multiple| rel["github-release job (D6)"]
reg[registry leaf: nuget / pypi / docker] -->|push, no asset| registries[(registries)]
```
Expand Down Expand Up @@ -281,7 +281,7 @@ The workflow is **operational** iff every *applicable* 5A item passes and every

Each type maps the *applicable* S-scenarios onto its targets. The differences are which leaf tasks exist and what each produces, which 5A addenda apply, and which scenarios are N/A. Walking these is the self-check that the contract holds for each shape.

- **Console / executable application.** Target produces `release-asset-<branch>-executable` (a 7z archive, `Console.7z`) by building a per-runtime `dotnet publish` matrix, then an aggregation job downloads the per-runtime `publish-<branch>-<runtime>` intermediates (`pattern:` + `merge-multiple:`), zips them, and uploads the single asset. Smoke builds a strict subset of runtimes. The per-runtime upload **and** the aggregation job are both gated `!smoke`, so smoke uploads nothing. The per-runtime intermediates rely on `retention-days: 1` (no explicit delete). Test: S1 with a console change smoke-builds the subset and uploads nothing; S7 attaches the 7z, `prerelease=true` on the non-default leg and `prerelease=false` on the default leg (GitHub auto-marks the stable default release "Latest", and the workflow does not set it).
- **Console / .NET publish application.** The target builds a per-runtime `dotnet publish` matrix. Configuration is Release on `main` and Debug otherwise. The target produces `release-asset-<branch>-dotnet-publish`, a 7z archive named `Console.7z`. An aggregation job downloads the `publish-<branch>-<runtime>` intermediates with `pattern:` and `merge-multiple:`. It zips them and uploads the single asset. Smoke builds a strict subset of runtimes. The per-runtime upload and aggregation job are both gated `!smoke`, so smoke uploads nothing. The per-runtime intermediates rely on the `retention-days: 1` backstop. S1 smoke-builds the subset after a console change and uploads nothing. S7 attaches the 7z. The non-default leg sets `prerelease=true`, and the default leg sets `prerelease=false`. GitHub marks the stable default release "Latest" automatically.
Comment thread
ptr727 marked this conversation as resolved.
Outdated
- **NuGet library.** The leaf both pushes (`dotnet nuget push *.nupkg --skip-duplicate`, gated `if: push` only) and uploads `release-asset-<branch>-nugetlibrary`. Configuration is Release on the default branch, Debug otherwise. Where symbols are enabled (`snupkg`), the push auto-carries the paired `.snupkg` to NuGet.org's symbol server and the asset zip also contains it, a triple surface. NuGet.org derives `isPrerelease` from the SemVer2 `-g<sha>` suffix (the workflow sets no such flag). Test: S7 non-default leg publishes a prerelease package + asset, default a stable; S9 re-run is a server-side `--skip-duplicate` no-op. 5C: query NuGet.org for both versions and the symbol package.
- **PyPI library.** The leaf builds + uploads `pypilibrary-build-<branch>`. A **separate** `publish-pypi` job (with `environment: pypi`, `id-token: write`, `actions: write`) does the OIDC Trusted-Publishing upload with `skip-existing: true`, then **consume-then-deletes** the build artifact, **unconditionally on consume**, so on S9 it is deleted even though the `release-asset-*` delete is skipped. The version is `AssemblyFileVersion` with `.dev0` appended on `develop` only, and must stay `--pre`-selectable and sorted above the default release. PyPI contributes no `release-asset-*`. A PyPI-only repo sets `expect_release_assets: false` at the caller. Test: S7 default leg publishes a release, non-default a `.dev0`; S9 is a `skip-existing` no-op; 5C inspects the `dist/*` filenames and the compute-version log.
- **Docker image.** The leaf pushes the default branch multi-arch (amd64+arm64) and any other branch `amd64`-only, with a per-branch registry buildcache (`buildcache-<branch>`; a multi-image repo adds a per-image tag) (`cache-to` only the built branch and only on push, `cache-from` both branches); no `release-asset-*`, so a Docker-only repo's caller passes `expect_release_assets: false`; the readme job (`peter-evans/dockerhub-description`, `DOCKER_HUB_ACCESS_TOKEN`) runs **only** when the default branch publishes, whether called directly or reached through the hub-hosted `publish-docker-readme-task.yml`; the docker-readme task validates `repositories` XOR `manifest`+`manifest-jq` and a multi-image repo derives its publish matrix from the manifest. Docker **always re-pushes** the image, independently of a skipped release-create (S9). A **wrapper** repo tracks an upstream release: the upstream tracker writes a `name -> version` state file and the merge-bot auto-merges the bump PR (S11), and the leaf MUST read that file for the immutable tag instead of `SemVer2` (the tracker ships without this consumer wiring). Test: S7 default leg pushes `latest` + the version tag and updates the readme. Non-default pushes the develop tag (amd64 only). S9 still re-pushes. S11 ships the bumped upstream version next publish. 5C Docker probe needs `DOCKER_HUB_*` secrets and same-repo (not fork) runs.
Expand Down
2 changes: 1 addition & 1 deletion catalog/snippets/workflows/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Workflow snippets

The reusable build/publish workflow tasks a code-shipping repo runs. They are **inert reference here**: this repo is source-only and keeps just the orchestrator set (`test-pull-request`, `publish-release`, `validate-task`, `merge-bot-pull-request`) in `.github/workflows/`, plus the hub-hosted reusable tasks a downstream repo reaches rather than carries (`merge-bot-task`, `get-version-task`, `publish-plan-task`, `build-release-task`, `build-docker-task`, `publish-docker-readme-task`, `check-upstream-version-task`, `deploy-site-task`, `run-codegen-pull-request-task`, per [`docs/reusable-workflows.md`][reusable-workflows]). Each row below names the canonical implementation of one or more `WORKFLOW.md` guarantees, whether the file lives in this directory or is hub-hosted and reached by pin. The audit asserts a downstream repo's own Actions satisfy those guarantees, not that they match these bytes. The table does not yet carry a row for every name in the parenthetical above: `build-release-task.yml`, `build-docker-task.yml`, `publish-docker-readme-task.yml`, `check-upstream-version-task.yml`, `deploy-site-task.yml`, and `run-codegen-pull-request-task.yml` are hub-hosted with no row here, for the reason the next paragraph gives. The release-chain hooks (`build-executable`, `build-nuget`, `build-pypi`, `docker-prepare`, `docker-build-base`) are composite actions rather than snippets here, since a hook is per-repo content and this catalog carries only what a repo copies whole.
The reusable build and publish workflow tasks serve code-shipping repositories. They are **inert reference here** because this repository is source-only. Its `.github/workflows/` directory keeps only `test-pull-request`, `publish-release`, `validate-task`, and `merge-bot-pull-request`. Downstream repositories reach the hub-hosted reusable tasks listed in [`docs/reusable-workflows.md`][reusable-workflows]. Each row below names the canonical implementation of one or more `WORKFLOW.md` guarantees. The implementation can live here or be reached from the hub by pin. The audit checks that downstream Actions satisfy those guarantees, not that they match these bytes. The table does not yet carry every hub-hosted task because the next paragraph explains when caller snippets ship. Release-chain hooks are composite actions because each hook is repository-owned content. They are `dotnet-publish`, `build-nuget`, `build-pypi`, `docker-prepare`, and `docker-build-base`.

A caller stub for a hub-hosted task carries no snippet of its own until the task ships in a release: its `uses:` line would pin a commit no release carries yet, which the pin gate rejects. `test-pull-request.yml`, `publish-release.yml`, and `run-periodic-codegen-pull-request.yml` gained theirs once `2.0.352` released `validate-task.yml`, `build-release-task.yml`, and `run-codegen-pull-request-task.yml`. [`docs/reusable-workflows.md`][reusable-workflows] "Adopting the Gates", "Adopting the Release Chain", and "Adopting the Type-Specific Tasks" carry the remaining stub shapes (the release-with-smoke variant, `deploy-site.yml`, `publish-docker-readme-task.yml`, and `check-upstream-version-task.yml`) as reference until each has a snippet of its own. `get-version-task.yml` and `publish-plan-task.yml` below carry no snippet at all, for a different reason: each is called as a job inside a larger stub rather than reached by its own top-level caller.

Expand Down
2 changes: 1 addition & 1 deletion catalog/snippets/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ jobs:
nuget: true
enable_docker: false
enable_pypi: false
enable_executable: false
enable_dotnet_publish: false
nuget_project: ./Widget/Widget.csproj
Loading