Commit 6d27550
authored
ci: automate authoritative desktop release tags (#154)
## Related Issue
No issue — reported directly: the desktop app on Windows was still
offering 0.1.6 after 0.2.0 had landed on main.
## Problem
`apps/desktop` is a private workspace package. Changesets bumps its
version on a release merge, but nothing ships it: `desktop-release.yml`
fires only on a `desktop-v*` tag, and cutting that tag was a manual `git
tag && git push` step outside CI.
On the 1.0.0 release, `apps/desktop/package.json` went `0.1.6 -> 0.2.0`
and no tag followed. The newest release in
`PyModel/pythinker-desktop-releases` stayed `v0.1.6`, so its
`latest.yml` — the electron-updater feed — kept advertising 0.1.6 to
every installed client. Nothing was red; CI on main was fully green the
whole time.
A second problem sat next to it. Both platform jobs ran a "Stamp desktop
version for tag builds" step that rewrote `apps/desktop/package.json` to
whatever the tag said. `git tag desktop-v9.9.9 <any commit>` would
therefore have silently turned that commit into a 9.9.9 release, with
the tag — not the reviewed source — deciding what shipped.
## What changed
**`release.yml` — cut the tag automatically.** After the changesets
step, compare `apps/desktop/package.json` between `${GITHUB_SHA}^` and
`${GITHUB_SHA}`; on a change, create `desktop-v<version>` at that
commit.
Both versions are read **by sha, never by `HEAD`**. This step runs after
the changesets action, and on the run that opens the version PR that
action checks out `changeset-release/main` and commits the bumped
`package.json` files — so `HEAD` there is a bump that is not a release.
Reading `HEAD` would cut, say, `desktop-v0.3.0` pointing at main's tip,
where the package still says 0.2.0. The new `prepare` assertion would
correctly fail *that* build, but the bogus tag would persist, and when
the real 0.3.0 release landed the already-exists check would report
"nothing to do" and desktop 0.3.0 would never ship — the same
silent-no-ship failure this PR exists to close, through a new door.
`$GITHUB_SHA` is the pushed commit whatever the action does to the
checkout, which makes the question moot on both paths.
For the same reason the already-exists check distinguishes a re-run from
an anomaly: a tag on this commit is a `::notice::`, a tag on a
*different* commit is an `::error::` naming both shas, rather than being
waved through as benign.
The tag is created with the release-bot App token, not `GITHUB_TOKEN`:
GitHub does not start workflows from events generated with
`GITHUB_TOKEN`, so a tag pushed with it would sit there without ever
building. (The same token already pushes the `changeset-release/main`
branch, which needs the same `contents: write` — but this specific path
is exercised for the first time on the next desktop bump.)
The step is `continue-on-error: true` and never exits non-zero on a read
it cannot make. It runs inside the `release` job, which gates the npm
publish, the Marketplace publish and the CDN redeploy; a missed desktop
tag costs one manual `git tag`, while a failed step there would block
all three. Every skip emits a `::notice::`, and a failed tag creation
emits an `::error::` carrying the exact recovery command — a silent
no-op is the bug being fixed, so no path here is allowed to be silent.
It is deliberately not gated on `steps.changesets.outputs.published`. A
desktop-only release publishes nothing to npm, so `published` is `false`
on exactly the releases this needs to fire for.
**`desktop-release.yml` — the package version is the source of truth.**
Both "Stamp desktop version" steps are deleted. `prepare` now reads the
version from `apps/desktop/package.json` and fails the build when a
`desktop-v*` tag disagrees with it, instead of rewriting the tree to
match. The tag chooses which commit ships; it can no longer change what
that commit is.
**`desktop-release.yml` — the tagged commit must be on main.** A new
`prepare` step calls the compare API and accepts only `identical` or
`behind`, so a release can no longer be built from a commit that never
landed on main.
Verification of the shell logic against real commits in this repo:
| case | `prev` | `curr` | outcome |
|---|---|---|---|
| `35c89a73b` (the 1.0.0 release commit) | `0.1.6` | `0.2.0` | cuts
`desktop-v0.2.0` — the tag this PR exists because nobody cut |
| `3acb36c66` (an ordinary commit) | `0.1.6` | `0.1.6` | no tag |
| unreadable ref | empty | empty | `::notice::`, exit 0 |
| `desktop-v0.2.0` already at `35c89a73b…` | — | — | `::notice::`
"already points here", exit 0 |
| `desktop-v9.9.9` absent | — | — | `existing` empty, proceeds to create
|
Compare-API statuses were checked against this repository:
`main...35c89a7` → `identical`, `main...3acb36c` → `behind`,
`main...<branch head>` → `ahead`.
`desktop-v0.2.0` was pushed by hand to unblock the current release
before these changes land.
## Checklist
- [x] I have read the
[CONTRIBUTING](https://github.com/PyModel/pythinker-code/blob/main/CONTRIBUTING.md)
document.
- [ ] I have linked a related issue (external PRs: the issue must have a
maintainer's `/approve`).
- [x] I have added tests that prove my feature works. — no test harness
exists for workflow YAML; the shell logic was run against the real
commits in the table above.
- [x] Ran `gen-changesets` skill, or this PR needs no changeset. —
CI-only, nothing users perceive.
- [x] Ran `gen-docs` skill, or this PR needs no doc update.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Release Improvements**
* Desktop releases now consistently use the version defined by the
desktop application.
* Release tags are validated against the application version and
confirmed to exist on the main branch.
* Tag handling now reliably recognizes both annotated and direct release
tags.
* Unchanged desktop versions no longer trigger unnecessary releases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->1 parent 5b6620e commit 6d27550
2 files changed
Lines changed: 86 additions & 24 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
36 | 41 | | |
37 | 42 | | |
38 | 43 | | |
| |||
41 | 46 | | |
42 | 47 | | |
43 | 48 | | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
| 49 | + | |
51 | 50 | | |
52 | 51 | | |
53 | 52 | | |
54 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
55 | 62 | | |
56 | 63 | | |
57 | 64 | | |
58 | 65 | | |
59 | 66 | | |
60 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
61 | 86 | | |
62 | 87 | | |
63 | 88 | | |
| |||
107 | 132 | | |
108 | 133 | | |
109 | 134 | | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | 135 | | |
119 | 136 | | |
120 | 137 | | |
| |||
233 | 250 | | |
234 | 251 | | |
235 | 252 | | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | 253 | | |
246 | 254 | | |
247 | 255 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
129 | 183 | | |
130 | 184 | | |
131 | 185 | | |
| |||
0 commit comments