Host Get-Version and Publish-Plan as Hub Reusable Tasks - #759
Conversation
docs/reusable-workflows.md Rollout tracker only, per the PR being its own evidence.
There was a problem hiding this comment.
Pull request overview
Stages reusable “pure function” GitHub Actions tasks in the hub by moving get-version-task.yml and publish-plan-task.yml into .github/workflows/ for downstream reuse via pinned uses:, and updates the fleet’s retirement ledger and documentation to track/drive adoption.
Changes:
- Add hub-hosted reusable workflow
.github/workflows/get-version-task.yml(including a derivedPrereleaseoutput) and update the existingpublish-plan-task.ymlheader comment. - Retire downstream copies via new
retiregap entries inspec/divergences.jsonand alignscripts/prose_lint.py’sHUB_HOSTEDset with those retirements. - Update rollout/adoption docs and remove the catalog snippet copy of
get-version-task.yml.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| TODO.md | Records settled findings about downstream divergence analysis for the two tasks. |
| spec/divergences.json | Adds retire gap entries for the two newly hub-hosted workflows. |
| scripts/prose_lint.py | Extends HUB_HOSTED exemptions to include the newly hub-hosted workflow paths. |
| docs/reusable-workflows.md | Adds “Adopting the Pure Functions” section and expands Stage 3 adoption tracking. |
| catalog/snippets/workflows/README.md | Updates snippet catalog prose/table to describe hub-hosted tasks (needs a path fix per review comment). |
| catalog/snippets/workflows/get-version-task.yml | Removes the catalog copy now hosted in .github/workflows/. |
| .github/workflows/publish-plan-task.yml | Updates header comment to reflect hub-hosted reuse. |
| .github/workflows/get-version-task.yml | New hub-hosted reusable task with updated action pins and Prerelease derivation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (2)
catalog/snippets/workflows/README.md:10
- This table lists
get-version-task.yml/publish-plan-task.ymlas bare filenames, but those files were moved out ofcatalog/snippets/workflows/and now live under.github/workflows/. Listing them as bare names is likely to be read as “present in this snippets directory” and makes the table misleading. Consider using the full repo-relative paths for these two hub-hosted tasks.
| `get-version-task.yml` | Hub-hosted and reached by pin from a leaf or publisher rather than carried, with no caller-stub snippet since it is called as a job inside a larger stub, per [`docs/reusable-workflows.md`][reusable-workflows] | D3 |
| `publish-plan-task.yml` | Hub-hosted and reached by pin from every publish-release job rather than carried, with no caller-stub snippet since it is called as a job inside a larger stub, per [`docs/reusable-workflows.md`][reusable-workflows] | D4 |
.github/workflows/get-version-task.yml:97
- Prerelease detection checks
SemVer2for any-without stripping SemVer2 build metadata (+...). This can misclassify stable versions that include build metadata containing-(SemVer2 allows hyphens in build metadata), and it diverges from the existingvalidate-releaselogic which strips+...before testing for-. Strip build metadata first and test the core+prerelease segment only.
set -Eeuo pipefail
if [[ "$SEMVER2" == *-* ]]; then
PRERELEASE=true
else
PRERELEASE=false
fi
|
Replies to the two suppressed findings from the round on bce9930:
Accepted. Fixed in a4822cb: both rows now name the full
Accepted. Fixed in a4822cb: the step now strips |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (1)
catalog/snippets/workflows/README.md:3
- The sentence "Each file below" is misleading now that the table includes hub-hosted workflows under
.github/workflows/(not files located incatalog/snippets/workflows/). Reword to describe the table entries/workflows rather than implying everything listed is a snippet file in this directory.
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`, per [`docs/reusable-workflows.md`][reusable-workflows]). Each file below is the canonical implementation of one or more `WORKFLOW.md` guarantees. The audit asserts a downstream repo's own Actions satisfy those guarantees, not that they match these bytes.
|
Reply to the suppressed finding from the round on a4822cb:
Accepted. Fixed in 34c5eb2: the sentence now reads "Each row below names the canonical implementation of one or more |
Move get-version-task.yml and publish-plan-task.yml from catalog/snippets/workflows/ into the hub's .github/workflows/, per docs/reusable-workflows.md stage 3. get-version-task.yml keeps the five canonical outputs and adds Prerelease, a derivation two live callers (aiopurpleair, homeassistant-purpleair) duplicated identically, hosted here rather than as per-repo logic. publish-plan-task.yml carries the canonical unchanged, since every downstream copy is a strict subset missing the -E pipefail flag and the unrecognized-actor warning branch. Neither task nests the other or a future build-release-task.yml, per the no-./-nesting rule; a caller that needs only the version reaches get-version-task.yml directly, documented in the new docs/reusable-workflows.md 'Adopting the Pure Functions' section with placeholder pins. spec/divergences.json gains retire gap dispositions for both paths naming their carriers, and scripts/prose_lint.py's HUB_HOSTED set is kept in sync per its own test. catalog/snippets/workflows/README.md rows now describe both as hub-hosted.
Strip SemVer2 build metadata before testing for a prerelease '-' in get-version-task.yml, matching validate-release's existing CORE_AND_PRE logic, so a stable version whose build metadata happens to contain a hyphen is no longer misclassified as a prerelease. catalog/snippets/workflows/README.md now names the two hub-hosted rows by their full .github/workflows/ path, since a bare filename in this directory's table reads as present in the snippets tree.
34c5eb2 to
0507837
Compare
Fail fast in docker-prepare-default when the image input is empty, note the hub's own outcome-preserving use of build-release-task.yml as a source-only release path in WORKFLOW.md, and track the hub's own missing plan job as an Open item pending #759.
Fail fast in docker-prepare-default when the image input is empty, note the hub's own outcome-preserving use of build-release-task.yml as a source-only release path in WORKFLOW.md, and track the hub's own missing plan job as an Open item pending #759.
…ion-tasks # Conflicts: # docs/reusable-workflows.md
Fail fast in docker-prepare-default when the image input is empty, note the hub's own outcome-preserving use of build-release-task.yml as a source-only release path in WORKFLOW.md, and track the hub's own missing plan job as an Open item pending #759.
Now that publish-plan-task.yml is hosted on develop (#759), the hub's own publish-release.yml gains the plan job the interface contract in spec/files.json always required, resolving the tracked gap this stage had documented instead of carrying it forward.
Copilot review on c1dadd1: the merge with #759 (get-version-task.yml, publish-plan-task.yml) rows added a claim that the table names the canonical implementation whether a file lives here or is hub-hosted, but the four stage-5 type-specific tasks are hub-hosted with no row, since their own caller-stub snippet returns only after each task's release per the paragraph beneath it. Names the four explicitly rather than leaving the coverage claim to read as complete.
… Default (#768) Promote `develop` to `main`, carrying the remaining stages of the hub-hosted reusable-workflow rollout and the changes that landed beside them: - #759 Host Get-Version and Publish-Plan as Hub Reusable Tasks - #760 Host the Validate Task and Reshape the Test Pull Request Stub (settles #729 by design: the hub's validate task runs `uvx <tool>@latest`, since Dependabot tracks the action pins and not a uvx version) - #761 Host the Type-Specific Tasks and Retire the Date Badge - #762 Host the Release Chain and the Docker Core in the Hub - #748 and #752, the staged rollout tracker and the PhotoCleaner merge-bot pilot record - #758 Flip the Fleet Line-Ending Default from CRLF to LF - #753, #755, #756, #764, host-setup and test-collection changes The release that follows this promotion is the first tag carrying every hub task, so it is the pin the stage 2 to 5 adoptions and their catalog snippets use. It is also the first run of the hub's own `publish-release.yml` through `build-release-task.yml` with every target disabled, which is the live proof that `github-release` runs when its build needs are skipped. Closes #729. Refs #521 (hub half shipped, the merge-bot adoption sweep is what remains).
Stage 3 of the hub-hosted reusable-workflow rollout (
docs/reusable-workflows.md"Rollout"). Hosts
get-version-task.ymlandpublish-plan-task.ymlin the hub's.github/workflows/, moved out ofcatalog/snippets/workflows/.What moved
get-version-task.yml: the catalog canonical, with action pins updated to thehub's current
actions/checkout@...v7.0.1andactions/setup-dotnet@...v6.0.0(the catalog copy had fallen behind what the hub's own
publish-release.ymlalready runs). Read against the 8 downstream copies (ESPHome-NonRoot, NxWitness,
PhotoCleaner, PlexCleaner, VSCode-Server-DotNetCore, KiCadLibrary, aiopurpleair,
homeassistant-purpleair): 5 are byte-identical to the canonical, KiCadLibrary only
documents the same design, and aiopurpleair and homeassistant-purpleair each add a
Prereleaseoutput derived fromSemVer2with identical logic (SemVer2containsa
-segment). That derivation is a real, duplicated improvement, so it is hostedas a sixth output on the task rather than left as per-repo logic. Homeassistant's
Tagoutput is not carried forward, since it is a bare copy ofSemVer2with noderivation of its own, and a caller can read
SemVer2directly.publish-plan-task.yml: the catalog canonical, unchanged in behavior. All 3downstream copies (ESPHome-NonRoot, NxWitness, Utilities) are a strict subset of
it, missing the
-Einset -Eeuo pipefailand the::warning::branch for anunrecognized actor pushing to
main(WORKFLOW.md D8.4), so nothing from thecopies is folded in.
Neither task nests the other, and neither is called from a hub
./path in thisPR:
build-release-task.yml(stage 4, a sibling agent's PR) inlines theget-version and validate-release jobs rather than nesting a sibling hub task, per
the design's no-
./-nesting rule. A downstreampublish-release.ymlstub thatreads version outputs directly, without carrying the whole release orchestrator,
calls
get-version-task.ymlby pin instead. Both shapes are documented in the new"Adopting the Pure Functions" section of
docs/reusable-workflows.md, withplaceholder pins (
@<hub-main-commit-sha> # <release-tag>) since no release hascarried these tasks yet.
Manifest and audit
Per the brief, no
interfacecontract is added tospec/files.jsonfor eithertask: they are hub-only files with no caller-stub filename convention of their
own (a caller reaches them as a job inside its own
publish-release.ymlorbuild-release-task.yml, not a standalone top-level workflow), so there is nodownstream stub shape to check today.
spec/audit.py'scheck_interfaceselftest set is unchanged for the same reason.
Confirmed the manifest-gap mechanics will do what is expected once this merges:
spec/audit.py'shub_only_pathsis the hub's owngit ls-filesoutput minusspec/files.json's baseline paths, so.github/workflows/get-version-task.ymland
.github/workflows/publish-plan-task.ymljoin that set the moment they landhere undeclared in the manifest.
spec/fidelity_honesty.py'smanifest_gap_passthen walks every cataloged repo's ground-truth tree and reports one whose tree
still contains either path as a gap naming that repo, which is exactly how a
downstream copy left over after this PR would surface once the fleet-wide report
runs.
spec/divergences.jsongains tworetiregap dispositions, one per path,naming the current carriers so the burn-down report reads as tracked rather than
UNTRIAGED.
python3 spec/validate.pyaccepts them (spec/divergences.schema.jsonhas no
reposfield on a gap entry, so carriers are named in thereasontextinstead, matching the ledger's existing prose style).
scripts/prose_lint.py'sHUB_HOSTEDliteral (which exempts a hub-hosted pathfrom the dead-path check once a downstream repo retires its own copy) gained both
new paths, since
scripts/tests/test_prose_lint.py'stest_the_hub_hosted_set_matches_the_ledgerasserts that set equals everyretiregap path in the ledger.Not run live
Per the brief, the live fleet report
(
python3 spec/fidelity_honesty.py --report) was not run in this PR, since itreads every cataloged repo over the network and is not guaranteed to finish
quickly. The two new ledger entries were checked structurally instead:
spec/ validate.pyaccepts the schema, andspec/audit.py --selftest'shub-only set excludes every declared pathcase (184 hub-hosted paths now, upfrom 182) confirms the two new paths are read into
hub_only_pathsas expected.reports/workflow-reuse.mdis not regenerated here either, per the Rolloutsection's rule that regeneration happens in the PR that ticks a stage's last
adoption, not the hub PR.
Tracker
docs/reusable-workflows.md"Rollout" Stage 3: ticked the hub pull requestitem with this PR, expanded the single adoption line into one checkbox per
carrier (9 repos, with ESPHome-NonRoot and NxWitness carrying both files), and
added a catalog-snippet follow-up item concluding that no snippet is warranted
today since a caller of either task is a job inside a larger stub.
TODO.md"Hub-Hosted Reusable Workflows" pure-functions bullet: added Settledlines recording the fleet reading above.
Gates run
spec/validate.py,unittest discover -s scripts/tests(686 tests),spec/ audit.py --selftest,spec/workflow_reuse.py --selftest,scripts/repo_gate.py,scripts/build_dist.py --check,scripts/prose_lint.pywith the named checks,ruff check/ruff format --check,mypy, and the Dockeractionlint,markdownlint-cli2, andeditorconfig-checkerinvocations (the last flags only.git,.mypy_cache,.ruff_cache). All pass.🤖 Generated with Claude Code