Skip to content

Support grouped builds in build-to-draft-release#171

Open
jesserockz wants to merge 2 commits into
mainfrom
jesserockz-2026-486
Open

Support grouped builds in build-to-draft-release#171
jesserockz wants to merge 2 commits into
mainfrom
jesserockz-2026-486

Conversation

@jesserockz

@jesserockz jesserockz commented Jul 17, 2026

Copy link
Copy Markdown
Member

Repositories that publish several combined manifests from one release — esphome/firmware builds both esp-web-tools and esphome-web — could not adopt the thin build-to-draft-release.yml caller. The wrapper never forwarded build.yml's combined-name, so each config would get its own manifest instead of the combined one, breaking the update.source manifest URLs that existing devices poll for OTA.

Grouped builds

Adds a combined-name passthrough for the single-group case, and a groups input (JSON array of {name, files}) that publishes several combined manifests from one call, as a matrix over the inner build.yml. One group may use an empty name to publish its files as one manifest each, for repositories shipping a combined group alongside standalone devices.

Grouping is expressed in a single call rather than one call per group. Removing the draft's ASSETS_PENDING warning is a claim that the whole release is built, and only one job can make it: split across a call per group, whichever finished first would strip the warning while the others were still compiling, inviting a maintainer to publish a release missing a group. A single call also keeps a single upload job — upload-to-gh-release.yml takes every artifact in the run, so two calls in one workflow would upload each other's artifacts and race on identical asset names.

Per-group files is required and is not auto-discovered: discovery globs *.factory.yaml across the whole repository, so one group would sweep up another group's configs. ci-draft-release.yml gains a two-group smoke test asserting each group's manifest combines exactly its own builds.

Draft asset cleanup moves to the drafter

build-to-draft-release.yml no longer cleans the draft's assets; it only adds them. draft-calver-release.yml now empties the draft immediately after release-drafter re-applies the release notes, and with them the ASSETS_PENDING warning.

That is the only point where deleting every asset is unambiguous: no build is in flight — the build workflows trigger on workflow_run of this workflow completing — so anything still attached is from an earlier build of the same draft. A clean running alongside the builds cannot tell a stale asset from one another build has just uploaded, which is what would otherwise force every repository into a single build+upload call per release. It also stops the draft advertising the previous build's assets for the whole compile window while claiming they are pending, and it cleans by the release id release-drafter reports rather than searching for "the first draft".

The clean's previous rationale (renamed files when the version bumps from .1 to .2) does not hold: release assets carry no version (xiao-ir-mate.manifest.json, esp-web-tools-example-esp32.ota.bin), and upload-to-gh-release.yml already replaces any same-named asset. It is a rare-event GC for renamed or removed devices.

This means a repository must use both halves of the pipeline: one whose Release Drafter workflow does not call draft-calver-release.yml never empties its draft.

Backwards compatibility

Callers passing neither input resolve to a single unnamed group and still publish one manifest per file, with cleaning still happening (now via the drafter) and the build job still displaying as Build Firmware, so required status checks are unaffected. The permissions callers must grant are unchanged.

Follow-ups

  • A new release/tag is needed before consumers can pin to this; they currently pin @9f6577fd37b5cf773ab1b9be929714a0dcd15661 # 2026.7.0.
  • Consumers should move their draft-calver-release.yml and build-to-draft-release.yml pins together; skew silently disables cleaning.
  • Adopt ready-made project template CI and release standards firmware#361 can then drop its inline build.yml for a groups caller.

Repositories that publish several combined manifests from one release (e.g.
esphome/firmware's esp-web-tools and esphome-web) could not use the thin
caller: the wrapper never forwarded build.yml's combined-name, so each config
would get its own manifest instead of the combined one, breaking the
update.source URLs existing devices poll for OTA.

Add a combined-name passthrough and a groups input that builds several
combined manifests from one call, as a matrix over the inner build.yml.
Grouping lives in a single call because removing the draft's pending warning
claims the whole release is built, and only one job can make that claim; a
call per group would let whichever finished first strip the warning while the
others were still compiling. One call also keeps one upload job, since
upload-to-gh-release takes every artifact in the run.

Move the asset cleanup to draft-calver-release, where release-drafter re-adds
the ASSETS_PENDING warning. That is the only point where deleting every asset
is unambiguous: no build is in flight, so anything attached is from an earlier
build of the same draft. A clean running alongside the builds cannot tell a
stale asset from one another build just uploaded, which is what would force a
single call per release. It also stops the draft advertising the previous
build's assets while claiming they are pending, and cleans by the id
release-drafter reports rather than searching for the first draft. Consumers
must use both halves of the pipeline for the draft to be emptied.

Callers passing neither input are unaffected: they resolve to a single unnamed
group and still publish one manifest per file.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the reusable draft-release build pipeline to support grouped builds, allowing multiple combined manifests to be produced and uploaded to the same draft release from a single build-to-draft-release.yml call, and shifts “delete stale draft assets” responsibility to the CalVer drafter workflow.

Changes:

  • Add combined-name passthrough + new groups JSON input to build-to-draft-release.yml, fanning out builds via a matrix (one leg per group) while keeping a single upload job.
  • Move draft asset cleanup from build-to-draft-release.yml into draft-calver-release.yml immediately after release-drafter runs.
  • Expand CI smoke coverage to validate grouped builds produce distinct combined manifests and artifacts for each group.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
README.md Documents grouped builds usage and clarifies the new draft asset lifecycle responsibilities.
.github/workflows/draft-calver-release.yml Deletes stale draft assets right after release-drafter updates the draft.
.github/workflows/ci-draft-release.yml Adds a grouped-build smoke test and validates per-group manifest composition.
.github/workflows/build-to-draft-release.yml Introduces groups, forwards combined-name per group, and removes in-workflow asset cleanup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/draft-calver-release.yml
Comment thread .github/workflows/build-to-draft-release.yml Outdated
Refuse to delete assets unless the release release-drafter reported is
actually a draft. The removed in-workflow clean filtered on .draft == true;
deleting by id alone would irreversibly delete a published release's assets if
a caller's release-drafter config ever resolved to one, so fail loudly instead.

Also fix the groups validation error message grammar.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants