From 36033a626f7762d4449373dd0c3358d2ad398aa3 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sun, 9 Aug 2026 21:14:08 -0700 Subject: [PATCH] docs(release): correct the runbook's two broken commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both documented commands fail as written: - `nx release patch` is rejected outright — nx.json configures git options under release.changelog.git, and Nx refuses the top-level command when granular git config is present. Replaced with the version/changelog subcommands. - `nx release changelog v0.0.2` double-prefixes the tag. releaseTagPattern is `v{version}`, so passing `vX.Y.Z` yields a malformed `vvX.Y.Z` tag and GitHub Release. Pass the bare version. Also adds a lockfile check before pushing (the version step regenerates package-lock.json, which on macOS can drop Linux swc bindings) and a drift check, since version bumps on main don't publish and the version on disk can match npm while the code differs. Co-Authored-By: Claude Opus 5 --- docs/RELEASE.md | 85 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 81f04ba8e..4202c5604 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -2,49 +2,66 @@ The seven publishable libraries (`@threadplane/chat`, `@threadplane/langgraph`, `@threadplane/ag-ui`, `@threadplane/render`, `@threadplane/a2ui`, `@threadplane/licensing`, `@threadplane/telemetry`) ship together at a synchronized version via Nx Release. During the `0.0.x` exploratory phase, only patch bumps are used. -## One-shot release (recommended; second release onward) +## Standard release (second release onward) > First release? See **[First `@threadplane` release](#first-threadplane-release)** below — the flow is different because there's no prior package under the new npm org yet. +> [!WARNING] +> **Do not use `nx release patch`.** The one-shot `nx release` command does not +> work in this repo. `nx.json` configures git options under +> `release.changelog.git`, and Nx rejects the top-level command whenever +> granular git config is present: +> +> `NX The "release" top level command cannot be used with granular git configuration.` +> +> Use the subcommands below instead. + From a clean main branch: ```bash git checkout main && git pull -npx nx release patch -``` -This runs Nx Release in interactive mode, which: - -1. Builds all seven publishable projects and patches install telemetry into the publishable package manifests (preVersionCommand). -2. Bumps every package.json version (e.g., `0.0.1` → `0.0.2`). -3. Generates `CHANGELOG.md` from commits since the last tag. -4. Creates a git commit `chore(release): publish v0.0.2`. -5. Tags the commit `v0.0.2`. -6. **Prompts for confirmation, then publishes to npm with provenance.** +# 1. Version bump. Runs preVersionCommand (builds all seven projects and +# patches install telemetry into the dist manifests), rewrites every +# package.json, updates package-lock.json, and stages the result. +npx nx release version --specifier=patch -After the prompt, push the commit and tag: +# 2. Changelog + commit + tag + GitHub Release. +# Pass the BARE version — see the warning below. +npx nx release changelog 0.0.57 -```bash +# 3. Push. The Publish workflow fires on the tag and publishes to npm +# with provenance via OIDC trusted publishing. git push origin main --tags ``` -The `Publish` GitHub Actions workflow fires on tag push and re-publishes (idempotent — npm rejects duplicate versions). - -## Step-by-step (for debugging) +> [!WARNING] +> **Pass the bare version to `changelog`, not `vX.Y.Z`.** `releaseTagPattern` is +> `v{version}`, so Nx prepends the `v` itself. Passing `v0.0.57` produces a +> malformed **`vv0.0.57`** tag and a GitHub Release at +> `/releases/tag/vv0.0.57`. Pass `0.0.57`. +> +> Always `--dry-run` step 2 first and check the printed tag URL before +> committing to it. -If something goes wrong, run the steps individually: +Step 3 is what actually ships. You can also publish from your machine with +`npx nx release publish --groups=publishable`, but preferring the tag-driven +workflow means no local npm credentials are needed and provenance is attested +by CI. -```bash -# 1. Version bump (writes new versions to package.json files) -npx nx release version --specifier=patch +### Check the lockfile before pushing -# 2. Generate changelog (creates CHANGELOG.md, commits, tags) -npx nx release changelog v0.0.2 # use the version produced by step 1 +Step 1 regenerates `package-lock.json`. On macOS that can drop the Linux +`@next/swc-*` bindings and break CI. The diff should be **only** the version +lines for the seven libs: -# 3. Publish to npm -npx nx release publish --groups=publishable +```bash +git diff --cached package-lock.json | grep -E '^-' | grep -icE 'linux|darwin|musl|gnu' +# must print 0 ``` +If it prints anything else, revert the lockfile and re-apply the version lines by hand. + ## First `@threadplane` release The first publish under the `@threadplane` npm org is manual. The packages must exist on npm before trusted publishing can be configured package-by-package. Run this from a clean, merged `main` branch. @@ -87,13 +104,27 @@ After the first `@threadplane` release, configure npm trusted publishing for all ## Dry run -Always sanity-check before a real release: +Always sanity-check before a real release. Dry-run each subcommand — the +one-shot `nx release patch --dry-run` fails the same way the real command does: + +```bash +npx nx release version --specifier=patch --dry-run +npx nx release changelog 0.0.57 --dry-run # bare version; check the printed tag URL +``` + +These print what would happen without modifying anything. + +## Is a release actually needed? + +Version bumps on `main` do **not** publish — only a pushed `vX.Y.Z` tag does. Main +routinely drifts ahead of npm, and the version on disk can match the version on +npm while the code differs. Check before assuming: ```bash -npx nx release patch --dry-run +git rev-list --count "v$(npm view @threadplane/chat version)"..origin/main ``` -This prints what would happen without modifying anything. +Anything above `0` means main has unpublished commits. ## Manual workflow trigger