Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ The required behaviors, organized by domain. Each is a **MUST**, stated as input
- **D4.2 Tag the built commit.** Output: the release `target_commitish` is the built commit's SHA (NBGV's `GitCommitId`), never a branch name or a separately re-resolved ref. *Prevents: the tag landing on the default branch instead of the built tree.*
- **D4.3 Release contents.** Output: every release is a tag on the built commit plus the auto source zip, README, and LICENSE; file-producing targets attach `release-asset-*`; `prerelease` equals `branch != default`. A no-file-target repo that uses the release task (Docker-only, PyPI-only) reaches the tag-only shape **only** with `expect_release_assets: false` set by the caller (which relaxes `fail_on_unmatched_files` and skips the asset download). With the default `true` and no assets the release-create step fails. A source-only repo reaches the same shape through its inlined `action-gh-release` instead, with no release task or `expect_release_assets`.
- **D4.4 No-op republish.** Input: a re-run whose version is unchanged. Output: nothing is re-pushed - the release-create step is skipped when the tag exists (refreshed only on `workflow_dispatch`), and the paired asset-delete is skipped with it. Registry pushes are no-ops. The NuGet/PyPI publish steps are **not** statically gated on existence - they run and the **server** dedupes (`dotnet nuget push --skip-duplicate` turns a 409 into success; PyPI `skip-existing: true`). **Docker always re-pushes** the image (base-image refresh), independently of the release-create skip, within the same run. *Prevents: duplicate releases and wasted pushes.*
- **D4.5 A build failure blocks every publish target.** Input: a real publish where one enabled build fails. Output: nothing publishes - `github-release` needs every build, so a failed build skips it (no tag, no release), and the terminal registry pusher (Docker) needs every other build and guards its `if` with `!failure() && !cancelled()`, so a failed build skips docker too (no image push) while a disabled or unchanged target - skipped, not failed - still lets docker build on smoke. *Prevents: a partial publish, e.g. a Docker image pushed while the executable build failed and no release was cut.* A repo pushing two registry targets at once would need a build/publish split behind an all-builds gate, which none does today.

### D5 - Resource Cleanup

Expand Down
10 changes: 8 additions & 2 deletions catalog/snippets/workflows/build-release-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,16 @@ jobs:
branch: ${{ inputs.branch }}
smoke: ${{ inputs.smoke }}

# Docker is the terminal registry push, so it must never push on a partial run. It needs every other build and
# guards with `!failure() && !cancelled()`: a *failed* build skips docker (no build, no push), while a *skipped*
# build - a target disabled on a smoke PR, or one this repo does not vendor - does not, so docker still builds
# the changed target on smoke. Plain `needs` cannot express this (a skipped need skips the dependent). The
# github-release job reaches the same intent more simply because it only runs on a publish (`!inputs.smoke`),
# where nothing is disabled. (A repo pushing a package alongside docker would need a build/publish split.)
build-docker:
name: Build Docker job
if: ${{ inputs.enable_docker }}
needs: [get-version, validate-release]
if: ${{ inputs.enable_docker && !failure() && !cancelled() }}
needs: [get-version, validate-release, build-nugetlibrary, build-pypilibrary, build-executable]
uses: ./.github/workflows/build-docker-task.yml
secrets: inherit
with:
Expand Down
2 changes: 1 addition & 1 deletion spec/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
{ "path": "spec/secrets.json", "fidelity": "intent", "intentRef": "docs/repo-config-carry.md", "appliesTo": "*" },
{ "path": ".github/dependabot.yml", "appliesTo": "*" },
{ "path": ".github/workflows/test-pull-request.yml", "fidelity": "interface", "contract": { "requiredJobKeys": ["check-workflow-status"], "requiredCheckName": "Check pull request workflow status job" }, "intentRef": "AGENTS.md#workflow-yaml-conventions", "appliesTo": "*" },
{ "path": ".github/workflows/build-release-task.yml", "fidelity": "interface", "contract": { "requiredJobKeys": ["get-version", "github-release"], "artifactNameToken": "release-asset-", "requireTokensInJob": { "github-release": ["pattern:", "merge-multiple:"] }, "forbidTokensInJob": { "github-release": ["artifact-ids:"] }, "verbatimJobs": ["github-release"] }, "reference": "catalog/snippets/workflows/build-release-task.yml", "intentRef": "AGENTS.md#release-model", "appliesTo": ["csharp", "console", "docker", "nuget", "pypi", "eda"] },
{ "path": ".github/workflows/build-release-task.yml", "fidelity": "interface", "contract": { "requiredJobKeys": ["get-version", "validate-release", "github-release"], "artifactNameToken": "release-asset-", "requireTokensInJob": { "github-release": ["pattern:", "merge-multiple:"] }, "forbidTokensInJob": { "github-release": ["artifact-ids:"] }, "verbatimJobs": ["github-release"] }, "reference": "catalog/snippets/workflows/build-release-task.yml", "intentRef": "AGENTS.md#release-model", "appliesTo": ["csharp", "console", "docker", "nuget", "pypi", "eda"] },
{ "path": ".vscode/tasks.json", "sections": ["clean-compile task group"], "reference": "catalog/snippets/configs/vscode-tasks.json", "appliesTo": ["csharp"] },
{ "path": ".vscode/tasks.json", "sections": ["clean-compile task group"], "reference": "catalog/snippets/configs/vscode-tasks-python.json", "appliesTo": ["python"] },
{ "path": "codecov.yml", "fidelity": "intent", "reference": "catalog/snippets/configs/codecov.yml", "intentRef": "WORKFLOW.md", "appliesTo": ["csharp", "python"] },
Expand Down