fix(desktop): restrict git describe to semver tags for version derivation (#5057)

Non-semver tags (e.g. release-train tags) could become the nearest match
for `git describe --tags`, producing a version string that is not a valid
semver prefix. Restrict describe to `v[0-9]*` tags across the CLI ldflags,
desktop bundling, and app-version paths so the resolved version always has
a `major.minor.patch` shape.
This commit is contained in:
YYClaw
2026-07-08 16:04:54 +08:00
committed by GitHub
parent fd58e13bec
commit c8cfd0a214
5 changed files with 25 additions and 5 deletions

View File

@@ -309,7 +309,7 @@ cli: ## Run the multica CLI with ARGS or MULTICA_ARGS from source
multica: ## Run the multica CLI entrypoint directly from the Go source tree
cd server && go run ./cmd/multica $(MULTICA_ARGS)
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
VERSION ?= $(shell git describe --tags --match 'v[0-9]*' --always --dirty 2>/dev/null || echo dev)
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
DATE ?= $(shell date -u '+%Y-%m-%dT%H:%M:%SZ')

View File

@@ -101,7 +101,7 @@ async function exists(p) {
}
if (hasGo()) {
const version = sh("git describe --tags --always --dirty") || "dev";
const version = sh("git describe --tags --match 'v[0-9]*' --always --dirty") || "dev";
const commit = sh("git rev-parse --short HEAD") || "unknown";
const date = new Date().toISOString().replace(/\.\d+Z$/, "Z");
const ldflags = `-X main.version=${version} -X main.commit=${commit} -X main.date=${date}`;

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env node
// Wrapper around `electron-builder` that keeps the Desktop version in
// lockstep with the CLI. Both are derived from `git describe --tags
// --always --dirty` — the same source GoReleaser reads for the CLI
// --match 'v[0-9]*' --always --dirty` — the same source GoReleaser reads
// for the CLI
// binary via the `main.version` ldflag — so a single `vX.Y.Z` tag push
// produces matching CLI and Desktop versions.
//
@@ -126,7 +127,9 @@ export function normalizeGitVersion(raw) {
}
function deriveVersion() {
return normalizeGitVersion(sh("git describe --tags --always --dirty"));
return normalizeGitVersion(
sh("git describe --tags --match 'v[0-9]*' --always --dirty"),
);
}
function uniqueOrdered(values) {

View File

@@ -50,6 +50,23 @@ describe("normalizeGitVersion", () => {
expect(normalizeGitVersion("2f24057b")).toBe("0.0.0-g2f24057b");
});
it("degrades a non-semver tag prefix that slips past the --match filter", () => {
// `git describe` is invoked with `--match 'v[0-9]*'` so a release-train
// tag like `release_iteration/…` is never the nearest match; the version
// resolves to the `vX.Y.Z-N-g<hash>` shape instead. If that filter ever
// regresses, the describe output carries the non-semver tag verbatim and
// must NOT be passed through as a version — it has no `major.minor.patch`
// prefix, so it degrades to the `0.0.0-g<hash>` fallback rather than
// producing something electron-updater would choke on.
expect(
normalizeGitVersion("release_iteration/Sprint_0705-3-g9adfcd4d8"),
).toBe("0.0.0-grelease_iteration/Sprint_0705-3-g9adfcd4d8");
// With the filter in place the real input is well-formed and passes through.
expect(normalizeGitVersion("v0.3.35-38-g9adfcd4d8")).toBe(
"0.3.35-38-g9adfcd4d8",
);
});
it("prefixes an all-digit hash so the pre-release is valid semver", () => {
// A short hash that is all decimal digits with a leading zero would
// produce `0.0.0-0123456` — a numeric pre-release identifier must not

View File

@@ -20,7 +20,7 @@ export function getAppVersion(): string {
return app.getVersion();
}
try {
const raw = execSync("git describe --tags --always --dirty", {
const raw = execSync("git describe --tags --match 'v[0-9]*' --always --dirty", {
cwd: app.getAppPath(),
encoding: "utf-8",
stdio: ["ignore", "pipe", "ignore"],