Skip to content

Commit 42e223c

Browse files
ndemiancclaude
andcommitted
fix(build): keep git-describe's suffix so dev builds can't impersonate a release
Addresses the PR #24 review. Both comments were real; the first turned out to sit on top of a latent bug worth more than the wording fix it asked for. 1. Regex vs stated intent. The comment claimed "a plain dotted version" while the regex allowed a -suffix. Rather than tighten the regex as suggested, the suffix is now REQUIRED behaviour and the comment says so — because dropping --abbrev=0 from `git describe` is the actual fix: at the tag (CI release): v0.8.0 -> stamps 0.8.0 off the tag (dev build): v0.8.0-1-g404ef20 -> stamps 0.8.0-1-g404ef20 With --abbrev=0 a dev build five commits past a release stamped a bare "0.8.0" and impersonated it in the UI — the exact class of confusion this PR exists to fix. Tightening to X.Y.Z would have locked that in, or failed dev builds outright once the suffix appeared. Junk ("v0.8", a branch name, an empty describe) still exits 1 and fails the build. 2. %cI documented as "authored". The code was right and the prose was wrong, so the prose changed: "Released" means when the build's commit LANDED, and a cherry-picked commit's author date can predate the release by weeks — the stability %aI offers is stability around the wrong instant. Now stated explicitly in the script header, build-macos.sh, and the product.ts doc comment. (On every release commit to date the two are identical, since they are GitHub merge commits.) Verified: exact-tag input stamps 0.8.0; describe-suffix input keeps the suffix; "v0.8" / a branch name / empty all exit 1; typecheck-client exit 0; the patch is still 14 entries with the original 11 byte-identical, no de-brand contamination, and reverse-applies cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 72383a0 commit 42e223c

3 files changed

Lines changed: 25 additions & 10 deletions

File tree

patches/levelcode-core.patch

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,10 @@ index 1a1f1e1d..56af75ac 100644
291291
-});
292292
+// [LevelCode] Removed the Help ▸ "Editor Playground" menu item (Microsoft VS Code walkthrough content).
293293
diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts
294-
index 5a1a2018..36b7c03a 100644
294+
index 5a1a2018..7d238537 100644
295295
--- a/src/vs/base/common/product.ts
296296
+++ b/src/vs/base/common/product.ts
297-
@@ -89,6 +89,23 @@ export interface IProductConfiguration {
297+
@@ -89,6 +89,25 @@ export interface IProductConfiguration {
298298
readonly quality?: string;
299299
readonly commit?: string;
300300

@@ -309,7 +309,9 @@ index 5a1a2018..36b7c03a 100644
309309
+ readonly levelcodeVersion?: string;
310310
+
311311
+ /**
312-
+ * [LevelCode] When this build's commit was authored (ISO 8601), stamped alongside `levelcodeVersion`.
312+
+ * [LevelCode] When this build's commit was COMMITTED (ISO 8601, git `%cI`), stamped alongside
313+
+ * `levelcodeVersion`. Committer date, not author date: "Released" means when the build's commit
314+
+ * landed, and a cherry-picked or rebased commit's author date can predate the release by weeks.
313315
+ * `date` is the Code-OSS build date and is misleading in release UI — it reflects the upstream base,
314316
+ * not when this LevelCode release shipped.
315317
+ */

scripts/build-macos.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,14 @@ node "$SCRIPT_DIR/strip-unreleased.mjs" "$BUILT_APP/LevelCode.app/Contents/Resou
8989
# `version` deliberately stays the Code-OSS base — it is what extensions' engines.vscode is validated
9090
# against — so the release version rides ALONGSIDE it rather than replacing it. Without this the update
9191
# UI reports "1.126.0", the upstream base, next to a LevelCode commit. See stamp-levelcode-version.mjs.
92-
# Tag-derived, so a CI build at tag vX.Y.Z stamps X.Y.Z; a dev build with no reachable tag skips it and
93-
# the UI falls back to `version`.
94-
if LC_VERSION="$(git -C "$ROOT_DIR" describe --tags --abbrev=0 2>/dev/null)" && [ -n "$LC_VERSION" ]; then
92+
# Tag-derived. NOTE the deliberate absence of --abbrev=0: at the exact tag (what CI checks out for a
93+
# release) `describe` returns a clean "v0.8.0", but OFF the tag it returns "v0.8.0-1-g404ef20". With
94+
# --abbrev=0 a dev build five commits past a release stamps a bare "0.8.0" and impersonates it in the
95+
# UI; the suffix makes such a build self-identifying. A checkout with no reachable tag skips the stamp
96+
# entirely and the UI falls back to `version`.
97+
# %cI is the COMMITTER date on purpose: "Released" means when this build's commit landed, not when the
98+
# work was originally written — a cherry-picked commit's author date can predate the release by weeks.
99+
if LC_VERSION="$(git -C "$ROOT_DIR" describe --tags 2>/dev/null)" && [ -n "$LC_VERSION" ]; then
95100
LC_DATE="$(git -C "$ROOT_DIR" log -1 --format=%cI HEAD 2>/dev/null || true)"
96101
echo "[build] Stamping the LevelCode release version ($LC_VERSION) …"
97102
node "$SCRIPT_DIR/stamp-levelcode-version.mjs" \

scripts/stamp-levelcode-version.mjs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
* So we add SEPARATE, human-facing fields rather than overloading `version`:
1414
* levelcodeVersion "0.8.0" ← from the git tag
15-
* levelcodeReleaseDate "2026-07-20T02:51:22Z" ← when this build's commit was authored
15+
* levelcodeReleaseDate "2026-07-20T02:51:22Z" ← when this build's commit was COMMITTED (%cI)
1616
*
1717
* Compatibility checks keep reading `version`; humans read these. Both are optional in the type,
1818
* so a dev build with neither still renders (it falls back to `version`).
@@ -35,11 +35,19 @@ if (!fs.existsSync(appDir)) {
3535
process.exit(1);
3636
}
3737

38-
// A release version, not a tag: "v0.8.0" would render as "Current Version: v0.8.0". Reject anything
39-
// that isn't a plain dotted version so a bad --describe result can't ship as the product version.
38+
// A release version, not a tag: "v0.8.0" would render as "Current Version: v0.8.0".
39+
//
40+
// Accepted: X.Y.Z, optionally followed by a `-` or `+` suffix. The suffix is REQUIRED, not tolerated —
41+
// build-macos.sh runs `git describe --tags` without --abbrev=0, so an off-tag build passes
42+
// "v0.8.0-1-g404ef20" and must keep that suffix: it is exactly what stops a dev build from
43+
// impersonating the release it happens to sit after. An exact-tag build (what CI does for a release)
44+
// passes a clean "v0.8.0" and gets a clean "0.8.0".
45+
//
46+
// Rejected: anything else — "v0.8", a branch name, an empty describe. Those exit non-zero so the build
47+
// fails rather than shipping a nonsense product version.
4048
const clean = String(version).replace(/^v/, "");
4149
if (!/^\d+\.\d+\.\d+([-+].+)?$/.test(clean)) {
42-
console.error(`[stamp] ERROR: "${version}" is not a version like 0.8.0 — refusing to stamp.`);
50+
console.error(`[stamp] ERROR: "${version}" is not X.Y.Z or X.Y.Z-<suffix> — refusing to stamp.`);
4351
process.exit(1);
4452
}
4553

0 commit comments

Comments
 (0)