refactor(release): one command releases every affected artifact#7
Merged
Conversation
Four near-identical scripts (422 lines) became one. Releasing a single
packages/ui bugfix meant three commands, three pushes and three full CI
cycles — each release commit moved HEAD, and every script re-gated on green
CI for the new HEAD — plus knowing by heart that the dashboard and extension
both bundle the SDK and so had to go too.
`bun run release` now works out what's affected, shows the plan, asks once,
and does the lot in one commit with one CI gate:
→ affected since last tags (patch):
sdk 0.4.1 → 0.4.2 → sdk-v0.4.2 → npm
dashboard 0.6.4 → 0.6.5 → v0.6.5 → Docker Hub
extension 0.1.3 → 0.1.4 → extension-v0.1.4 → Web Store
Affected is derived from what each artifact is BUILT FROM, bundled workspace
packages included. Propagation then needs no special rule: the dashboard bakes
the SDK IIFE into its image and the extension syncs it via sync-sdk.ts, so
listing the SDK as a source is what makes a packages/ui fix reach all three —
and expo, which ships its own React Native UI, correctly stays out of it.
Fixes found while doing this, each having already caused a real failure:
- Tags are annotated. amend_release_commit_and_retag() re-tagged with
`git tag -f` (lightweight), while every script printed `git push
--follow-tags` as the next step — which pushes annotated tags only. The tag
silently never reached the remote and the publish workflow never fired.
extension-v0.1.4 hit exactly this and needed a manual `git push origin
<tag>` to recover.
- Detection ignores release commits. A release bumps its own package.json and
CHANGELOG.md inside its own paths, so a plain `git diff` counts
"chore(release): sdk-v0.4.2" as an SDK change and marks everything that
bundles core affected — every release making the next one look necessary.
- Push happens in one place. "postrelease": "git push --follow-tags" fired
implicitly off `bun run release`, so the dashboard auto-pushed while its own
script printed "Next: push" and the other three genuinely didn't. Both
implicit hooks are gone; the script does its own verification.
- Tags push one at a time: GitHub won't start workflow runs for tags beyond
the third in a single push, and there are four artifacts.
- release:all is deleted. It chained scripts with no push between them, so the
second always died on `no CI run found for <sha>`.
Version lines stay independent, so a dashboard change still can't churn a
republish of @reprojs/core.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
filter_changelog_by_paths ran over the WHOLE CHANGELOG.md, dropping every line
whose [sha] wasn't in the keep-set. The keep-set only covers FROM..HEAD, so
every previously-released entry's bullets referenced SHAs outside the range
and were deleted — each release eroding a bit more of the file.
packages/core/CHANGELOG.md, entry by entry, as of sdk-v0.4.0 vs now:
sdk-v0.4.0 257 bullets → 2
sdk-v0.3.0 107 bullets → 1
sdk-v0.2.1 4 bullets → 1
The headings survived (no [sha] to match), so the file kept looking plausible
while its contents drained away. That gutted file is what ships in the npm
tarball and gets pasted into each GitHub Release.
Only filter the section changelogen just prepended; copy everything from the
second `## ` heading down through untouched. `## ` matches version headings
only — `### Fixes` has no space in the third column.
This is pre-existing and independent of the release-script unification; it
just took releasing from a clone and diffing the result to notice.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tonight's CSP fix took three commands, three pushes and three full CI cycles to ship — and one of them silently failed. This makes it one command, and fixes each thing that actually went wrong along the way.
Before / after
↓
Four near-identical scripts (422 lines) → one script + a registry. One commit, one CI gate, one prompt.
Affected detection
Each artifact declares what it's built from, bundled workspace packages included:
sdk-vpackages/{core,ui,sdk-utils,shared,recorder}vapps/dashboard,packages/integrations+ bundles the SDKextension-vapps/extension+ bundles the SDKexpo-vpackages/expo,packages/{sdk-utils,shared}Propagation then needs no special rule — the dashboard bakes the SDK IIFE into its image and the extension syncs it via
sync-sdk.ts, so listing the SDK as a source is what makes apackages/uifix reach all three. That was the fact I had to derive by hand by reading the service worker. Expo correctly stays out: it ships its own React Native UI and never bundlespackages/ui.Version lines stay independent, so a dashboard change still can't churn a republish of
@reprojs/core.Bugs fixed (each one bit for real tonight)
amend_release_commit_and_retag()re-tagged withgit tag -f— lightweight — while every script printedgit push --follow-tags, which carries annotated tags only.extension-v0.1.4never reached the remote, its publish workflow never fired, and nothing errored. It needed a manualgit push origin <tag>to recover.package.json/CHANGELOG.mdinside its own paths, so a plaingit diffcountschore(release): sdk-v0.4.2as an SDK change and marks everything bundling core as affected — every release making the next one look necessary, forever.FROM..HEAD, so every past entry's bullets were dropped.packages/core/CHANGELOG.md'ssdk-v0.4.0entry went 257 bullets → 2;sdk-v0.3.0107 → 1. Headings survived, so the file looked fine while draining. That gutted file ships in the npm tarball and gets pasted into each GitHub Release."postrelease": "git push --follow-tags"fired implicitly offbun run release, so the dashboard auto-pushed while its own script printed "Next: push". Both implicit hooks are gone; the script runs its own verification.release:alldeleted. It chained scripts with no push between, so the second always died onno CI run found for <sha>.Verification
Tested in a throwaway clone against a throwaway bare origin, so nothing could reach the real remote:
expo— correct,packages/sharedreally has changed sinceexpo-v0.3.0packages/uichangebundles @reprojs/core✅--only/--skip/--minor--minorgives a real0.6.5 → 0.7.0, not silently downgraded on 0.xgit cat-file -t v0.6.6→tag(annotated); tag annotated on the remote too19 insertions, 1 deletionvs490 deletionsbefore the fixA push rejection mid-test also confirmed it fails loudly rather than silently.
Note
expohas genuinely unreleasedpackages/sharedchanges sinceexpo-v0.3.0— the tool surfaced that on its first run. Not addressed here; worth deciding separately whether to cutexpo-v0.3.1.The already-gutted changelogs are recoverable from old tags (e.g.
git show sdk-v0.4.0:packages/core/CHANGELOG.mdstill has all 257 bullets). Not done here — happy to follow up if you want the history restored.🤖 Generated with Claude Code