From 29858e661dd0217c8e5ef3fe5cc6089e486b69fc Mon Sep 17 00:00:00 2001 From: Peter Amiri Date: Mon, 18 May 2026 14:16:46 -0700 Subject: [PATCH] fix(release): bake .module-version at build time, not from source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real-user Scoop install on 2026-05-18 surfaced: `wheels --version` from a fresh `scoop install wheels` (stable) reports `4.0.0-SNAPSHOT+1442` — a snapshot tag, on a stable channel install of GA v4.0.0. Root cause ---------- `cli/lucli/.module-version` was tracked in git with a hardcoded snapshot string. The release-pipeline `@build.version@` substitution at release.yml:270 targets `*.json`, `*.md`, `*.cfm`, and `*.cfc` — but not `.module-version` (no extension). So every release artifact (stable GA, RC, every snapshot) shipped the same stale source-tracked value regardless of what was actually being released. This file is the source of truth for two runtime behaviors in the brew/scoop/.deb/.rpm wrappers: 1. `wheels --version` reads it and prints the content verbatim. 2. The first-run sync compares staged-module-version against installed-module-version to decide whether to re-sync. When every artifact has the same stale string, the comparison always sees "no change" and silently skips the sync — which means a user running `scoop uninstall wheels; scoop install wheels-be` would keep the OLD stable module on disk under ~/.wheels/modules/wheels/. Channel switching was broken in subtle ways. CFC code at PackagesMainCli.cfc:340 already documents that .module-version "isn't written" in dev checkouts, so the architecture already expected this to be a build-time artifact, not source-tracked. Fix --- - `git rm cli/lucli/.module-version` — drop the stale source file. - `.gitignore` entry so it can't be re-introduced accidentally. - `release.yml`: write `cli/lucli/.module-version` from `MODULE_VERSION` right after the `@build.version@` substitution, before tar/zip pack. snapshot.yml uses release.yml as a reusable workflow, so it inherits. release-candidate.yml doesn't build a wheels-module artifact at all (RCs aren't published to Scoop), so it doesn't need touching. Effect ------ - `wheels --version` on next snapshot/release: reports the actual release tag, not a stale snapshot number. - Channel switching detects the version change correctly and re-syncs. - Dev checkouts (without `.module-version`) fall through to the Tier 2 BuildInfo.cfc lookup at PackagesMainCli.cfc:341, unchanged. No effect on already-shipped 4.0.0 GA install — users with the bad version baked in will see the correct value on their next `scoop update wheels` once 4.0.1 ships through the autoupdate chain. Refs #2758 follow-up Signed-off-by: Peter Amiri --- .github/workflows/release.yml | 13 +++++++++++++ .gitignore | 5 +++++ cli/lucli/.module-version | 1 - 3 files changed, 18 insertions(+), 1 deletion(-) delete mode 100644 cli/lucli/.module-version diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c0ed19c54..011b3fef13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -269,6 +269,19 @@ jobs: # for the wheels-cli ForgeBox artifact. See #2326. find cli/lucli -type f \( -name "*.json" -o -name "*.md" -o -name "*.cfm" -o -name "*.cfc" \) -exec sed -i.bak "s/@build\.version@/${MODULE_VERSION}/g" {} \; find cli/lucli -name "*.bak" -delete + # Generate .module-version at build time with the canonical version. + # This file is read at runtime by the brew/scoop/.deb/.rpm wrappers + # for two purposes: + # (1) `wheels --version` displays its contents verbatim + # (2) The wrappers compare staged-module-version vs installed-version + # to decide whether to re-sync the module on first run + # The substitution above only matches *.json *.md *.cfm *.cfc, so + # `.module-version` (no extension) was previously sourced from a stale + # source-tracked file and embedded into every artifact (snapshot AND + # GA). That made every release look like the same snapshot tag and + # broke channel-switch sync detection. Generating it here ensures + # both behaviors stay correct. See #2758 follow-up. + echo "${MODULE_VERSION}" > cli/lucli/.module-version tar czf "artifacts/wheels/${MODULE_VERSION}/wheels-module-${MODULE_VERSION}.tar.gz" -C cli/lucli . cd cli/lucli && zip -r "../../artifacts/wheels/${MODULE_VERSION}/wheels-module-${MODULE_VERSION}.zip" . && cd ../.. cd artifacts/wheels/${{ env.WHEELS_VERSION }} diff --git a/.gitignore b/.gitignore index 1c5f1e9543..f1c7565382 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,11 @@ META-INF !/vendor/wheels/ /cli/workspace/ /cli/simpletestapp/ +# Generated at release time by .github/workflows/release.yml — see #2758 +# follow-up. Source-tracked stale values cause `wheels --version` to show +# a snapshot tag on GA installs and break channel-switch detection in the +# brew/scoop wrappers (which compare staged vs installed `.module-version`). +/cli/lucli/.module-version # Database files /db/ diff --git a/cli/lucli/.module-version b/cli/lucli/.module-version deleted file mode 100644 index 127a4d9073..0000000000 --- a/cli/lucli/.module-version +++ /dev/null @@ -1 +0,0 @@ -4.0.0-SNAPSHOT+1442 \ No newline at end of file