From 1c38b3efe5098ad1c78eacafe40a44a83e1172a5 Mon Sep 17 00:00:00 2001 From: Peter Krenesky Date: Sat, 27 Jun 2026 08:00:28 -0700 Subject: [PATCH] fix(version): don't mark a stamped release build as -dirty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release pipeline stamps package.json (0.1.3 → tag version) before building, which dirties the working tree, so `git describe --tags --dirty` baked `X.Y.Z-dirty` into a clean published release (e.g. quoin --version printed 0.5.3-dirty). Drop --dirty: HEAD-on-tag now bakes the bare tag, while a build ahead of its tag still shows the commits-ahead `-N-gsha` drift suffix. Update FR-002 accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) --- spec/functional/FR-002-print-package-version.md | 8 +++++--- src/cli.ts | 5 ++--- vite.config.ts | 12 +++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/spec/functional/FR-002-print-package-version.md b/spec/functional/FR-002-print-package-version.md index 2b1936a..c5064ab 100644 --- a/spec/functional/FR-002-print-package-version.md +++ b/spec/functional/FR-002-print-package-version.md @@ -14,7 +14,7 @@ relationships: The CLI SHALL print its own version in response to the `version` command, the `--version` flag, or the `-v` flag. The version SHALL be the value baked at build time from `git describe` — a bare tag for a clean release (e.g. `0.5.2`), a -drift-revealing suffix otherwise (e.g. `0.5.1-3-gabc123-dirty`) — and SHALL fall +commits-ahead suffix otherwise (e.g. `0.5.1-3-gabc123`) — and SHALL fall back to the package's `package.json` `version` field when no build-time value is present (dev, test, or no-git builds), raising an error when that fallback version is missing or not a string. @@ -30,8 +30,10 @@ is missing or not a string. ## Behavior -- The CLI SHALL prefer the build-time baked version (`git describe --tags --dirty`, - leading `v` stripped) when it is a non-empty string. +- The CLI SHALL prefer the build-time baked version (`git describe --tags`, leading + `v` stripped) when it is a non-empty string. It SHALL NOT use `--dirty`, since the + release pipeline stamps `package.json` before building and would otherwise mislabel + a clean release as `-dirty`. - The CLI SHALL otherwise resolve its `package.json` relative to the installed package and read the `version` field. - The CLI SHALL print the resolved version and return before any other dispatch. diff --git a/src/cli.ts b/src/cli.ts index c2f7c86..cb3818f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -247,9 +247,8 @@ export async function main(argv: string[]): Promise { } // Baked at build time from `git describe` (see vite.config.ts). A bare semver -// means a clean tagged release; a `--g` / `-dirty` suffix means the build -// is ahead of / diverges from its tag. Empty for dev/test/no-git builds, which -// fall back to package.json. +// means a clean tagged release; a `--g` suffix means the build is ahead of +// its tag. Empty for dev/test/no-git builds, which fall back to package.json. declare const __QUOIN_VERSION__: string; function readPackageJsonVersion(): string { diff --git a/vite.config.ts b/vite.config.ts index 9854ad9..a75c80f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,13 +6,15 @@ import { defineConfig } from "vite"; import dts from "vite-plugin-dts"; // Truthful version baked into the bundle at build time. `git describe` yields the -// bare tag on a clean release commit (e.g. v0.5.2) and a drift-revealing string -// otherwise (e.g. v0.5.1-3-gabc123-dirty); we strip the leading `v`. Only computed -// for `vite build` — under vitest (serve) it stays "" so packageVersion() exercises -// its package.json fallback. Empty on a no-git build (e.g. tarball) too. +// bare tag when HEAD is exactly a release tag (e.g. v0.5.4) and a commits-ahead +// string otherwise (e.g. v0.5.3-2-gabc123); we strip the leading `v`. We do NOT +// pass `--dirty`: the release pipeline stamps package.json before building, which +// would dirty the tree and mislabel a clean release as `-dirty`. Only computed for +// `vite build` — under vitest (serve) it stays "" so packageVersion() exercises its +// package.json fallback. Empty on a no-git build (e.g. tarball) too. function gitVersion(): string { try { - return execSync("git describe --tags --dirty --always", { + return execSync("git describe --tags --always", { encoding: "utf8", }) .trim()