Skip to content

ci(desktop): start the Desktop release when Packages succeeds on main - #1414

Merged
abrichr merged 1 commit into
mainfrom
ci/desktop-release-on-packages
Oct 20, 2026
Merged

abrichr merged 1 commit into
mainfrom
ci/desktop-release-on-packages

Conversation

@abrichr

@abrichr abrichr commented Oct 20, 2026

Copy link
Copy Markdown
Member

Summary

Release run 39368396653 refused Desktop 0.22.0 because the gate polled for the commit's Packages run for 60 minutes, and under CI congestion that run sat queued longer. This change starts the release only after Packages has finished, so queue time can't fail a release.

  • Trigger. desktop-release.yml starts from workflow_run on Packages completed, branch main. The gate runs only when that run concluded success, came from a push, and belongs to this repository's main; a fork's pull request from a branch named main can't release. workflow_dispatch stays for manual runs.
  • Subject (head-SHA binding). The subject is github.event.workflow_run.head_sha, never main's tip. The gate reads that Packages run back through the API. It requires the same workflow, head commit, push event, main branch, repository, and completed/success, plus successful desktop test / and desktop build / jobs.
  • Built commit. GitHub runs a workflow_run workflow at main's tip, and the Fulcio certificate records that tip as the workflow SHA. The release therefore builds and tags github.sha, as a dispatch already did, and requires the tip's packages/desktop tree to equal the subject's. That keeps workflow_commit == source_commit in the provenance and channel, which the verifiers check. Building head_sha instead would produce attestations whose certificate names a different commit.
  • Quiet "no release". The gate ends quietly when the subject doesn't change packages/desktop, when main changed Desktop again after the subject (the newer commit's own Packages run releases it), or when the version is already released. Classification runs before the release-state check, so an unrelated commit never trips the loud partly-published refusal.
  • Queueing. Every Packages run on main now starts a Desktop release run. With default concurrency, each new pending run cancels the one waiting before it, so a no-op run could drop a pending release. The group now sets queue: max (GitHub, May 2026). The local actionlint 1.7.12 doesn't know this key yet; CI doesn't run actionlint.
  • Dispatch. A manual run still waits for its subject's Packages run: up to four hours while queued, then the existing 60 minutes once running. The gate's timeout is now 320 minutes.
  • Provenance. native_release.py and the download verifier now accept the workflow_run event. push stays valid for earlier releases.

These gates are unchanged:

  • Packages succeeded, with its desktop test and build jobs.
  • main hasn't changed Desktop since the subject.
  • Version, changelog and tag order.
  • The openadapt-release App identity for tagging.
  • A partly published version refuses a rebuild.

Caching is unchanged. Note that the release build jobs already use setup-node with cache: npm; this PR doesn't add or remove any cache.

Docs: packages/desktop/RELEASES.md has a new "How a release starts" section. packages/desktop/CLAUDE.md and docs/monorepo/README.md are updated to match.

Tests

  • tests/test_desktop_release_subject.py now asserts the trigger, the gate condition, queue: max, the head-SHA binding, the step order and the quiet exits. It also covers the Packages read-back, the desktop job prefixes, the dispatch bounds, the freshness check and the release App identity.
  • packages/desktop/tests/test_native_release.py and test_public_metadata.py are updated for the new trigger and step order.
  • Locally, these pass: tests/test_desktop_release_subject.py, tests/test_verify_github_release.py, packages/desktop test_native_release.py, test_public_metadata.py, test_native_signing.py and test_release_publication.py. actionlint with shellcheck is clean, apart from the unknown queue key.

No release was dispatched or re-run.

🤖 Generated with Claude Code

The release gate used to start on the push and poll for that commit's
Packages run for 60 minutes. Under CI congestion the 0.22.0 commit's
Packages run sat queued past that bound and release run 39368396653
refused, so releases needed a manual re-dispatch.

desktop-release.yml now starts from workflow_run on Packages completing
with success for a push to main. The Packages head commit
(workflow_run.head_sha) is the subject whose checks decide the release;
the gate reads that run back and requires its desktop test and build jobs.
GitHub runs workflow_run at main's tip and signs attestations for it, so
the release builds the tip, as a dispatch already did, and requires its
packages/desktop tree to equal the subject's. Workflow commit and source
commit therefore stay equal in the provenance.

A commit that doesn't change packages/desktop, one superseded by a newer
Desktop change, or an already released version ends quietly as no release.
The concurrency group queues runs (queue: max) so the many no-op runs
can't cancel a pending release. A dispatch still waits: four hours while
Packages is queued, then 60 minutes once it runs. Provenance and the
download verifier accept the workflow_run event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@abrichr
abrichr merged commit f62a0fa into main Oct 20, 2026
49 checks passed
@abrichr
abrichr deleted the ci/desktop-release-on-packages branch October 20, 2026 06:03
abrichr added a commit that referenced this pull request Oct 20, 2026
#1414 starts Desktop releases from workflow_run. A dispatch is always a
candidate, so it reaches the release-state check and resumes. Any other
run that finds the resumable state (PyPI serves the version, the tag
exists, no published release) builds nothing and leaves a warning to
dispatch, instead of failing every Desktop commit until someone does.
The gate's release output stays with the main-unchanged step, which a
resume skips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant