From ab90d6fd6319997d6b0832088d7f675b6862cde2 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Tue, 15 Sep 2026 12:13:44 -0400 Subject: [PATCH] Make the release tag the source of truth for the version Every release currently needs a package.json bump PR before the tag, and the release workflow fails if the two disagree. The 1.1.1 release broke on exactly this dance, and the bump PR itself introduced a merge accident that took CI down. Stamp the version from the release tag inside the workflow instead. package.json in git holds a 0.0.0-development placeholder, and cutting a release is now just drafting a GitHub Release with a new tag name. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/release.yml | 12 +++++++----- RELEASING.md | 35 ++++++++++++++++------------------- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c6f15aa..2f9ccc8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,8 @@ name: Release # Publishes to npm when a GitHub Release is published. +# The release tag is the single source of truth for the version: it is stamped +# into package.json at publish time, so the version in git never needs bumping. # Authenticates to npm as a trusted publisher via OIDC (no token needed). # See RELEASING.md for the full process. on: @@ -27,15 +29,15 @@ jobs: - run: npm ci - - name: Verify tag matches package.json version + - name: Set version from release tag run: | tag="${GITHUB_REF_NAME#v}" - pkg="$(node -p "require('./package.json').version")" - if [ "$tag" != "$pkg" ]; then - echo "::error::Release tag ($tag) does not match package.json version ($pkg)." + if ! [[ "$tag" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then + echo "::error::Release tag '$GITHUB_REF_NAME' is not a semver version (expected X.Y.Z or vX.Y.Z)." exit 1 fi - echo "Tag matches package.json version: $pkg" + npm version "$tag" --no-git-tag-version + echo "Publishing version $tag" - name: Smoke test run: npm run smoke diff --git a/RELEASING.md b/RELEASING.md index 08d1345..653c6ed 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,7 +2,9 @@ Releases are published to [npm](https://www.npmjs.com/package/altis-cli) automatically by GitHub Actions whenever a **GitHub Release is published**. -`package.json` is the single source of truth for the version number. +The **release tag is the single source of truth** for the version number. It is +stamped into `package.json` by the workflow at publish time, so the version +committed to git is a placeholder (`0.0.0-development`) and never needs bumping. ## Versioning (SemVer) @@ -17,36 +19,31 @@ We follow [Semantic Versioning](https://semver.org/): `MAJOR.MINOR.PATCH`. ## Cutting a release -1. Make sure `main` is green in CI and you have the latest: +1. Make sure `main` is green in CI and contains everything you want to ship. - ```sh - git checkout main && git pull - ``` +2. Go to **Releases → Draft a new release**. -2. Bump the version. This updates `package.json` and creates a matching - `vX.Y.Z` commit and git tag: +3. Under **Choose a tag**, type the new version (for example `1.2.0`) and pick + **Create new tag on publish**. Leave the target as `main`. - ```sh - npm version patch # or: minor | major - ``` +4. Click **Generate release notes**, tidy them up if needed, and **Publish**. -3. Push the commit and tag: - - ```sh - git push --follow-tags - ``` - -4. Create a **GitHub Release** for the new `vX.Y.Z` tag - (Releases → Draft a new release → choose the tag → add notes → Publish). +That is the whole process. There is no version bump commit and no local +tagging; GitHub creates the tag when the release is published. Publishing the release triggers `.github/workflows/release.yml`, which: - installs dependencies (`npm ci`), -- **verifies the release tag matches `package.json`** (fails otherwise), +- **validates the tag is a semver version and writes it into `package.json`** + (a leading `v` is accepted and stripped), - runs the CLI smoke test, - runs `npm audit` (advisory — does not block the release), - publishes to npm with [provenance](https://docs.npmjs.com/generating-provenance-statements). +Because the version is only set inside the workflow, `altis-cli --version` from +a git checkout reports `0.0.0-development`. Installs from npm report the real +version. + ## One-time setup: trusted publishing Publishing authenticates to npm as a diff --git a/package-lock.json b/package-lock.json index 125b667..3ec1632 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "altis-cli", - "version": "1.1.1", + "version": "0.0.0-development", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "altis-cli", - "version": "1.1.1", + "version": "0.0.0-development", "dependencies": { "@automattic/vip-search-replace": "^2.0.0", "@humanmade/ssm": "^0.0.1", diff --git a/package.json b/package.json index d83ee7f..96c6af5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "altis-cli", "type": "module", - "version": "1.1.1", + "version": "0.0.0-development", "description": "Command-line tool for managing Altis Cloud hosting: stacks, backups, deploys, logs, X-Ray and more.", "license": "MIT", "homepage": "https://github.com/humanmade/altis-cli#readme",