From 0b2c7c12217660d1434235fcec27e0b9fe649484 Mon Sep 17 00:00:00 2001 From: Peter Amiri Date: Fri, 24 Apr 2026 11:57:17 -0700 Subject: [PATCH] fix(config): walk up two levels for monorepo box.json in $readFrameworkVersion (closes #2291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default rootBoxJsonPath resolved "../box.json" from Global.cfc's directory (vendor/wheels/), pointing at vendor/box.json which does not exist. At runtime boot via onapplicationstart.cfc — where the helper is called with no arguments — this silently fell through to "0.0.0-dev" even inside a wheels-dev/wheels checkout. Walking up two levels reaches /box.json so application.wheels.version now resolves to "-dev" as intended. Adds a regression spec that asserts application.wheels.version at boot (rather than invoking the helper directly), because WheelsTest.cfc binds methods into each spec's scope which shifts GetCurrentTemplatePath() and bypasses the code path we need to cover. The existing specs all passed explicit path arguments, leaving the default-args computation uncovered. Co-Authored-By: Claude Opus 4.7 (1M context) --- vendor/wheels/Global.cfc | 2 +- .../specs/events/frameworkVersionSpec.cfc | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/vendor/wheels/Global.cfc b/vendor/wheels/Global.cfc index 1ed67df30d..19fe606fa5 100644 --- a/vendor/wheels/Global.cfc +++ b/vendor/wheels/Global.cfc @@ -2788,7 +2788,7 @@ return local.$wheels; // homepage shows the upcoming version rather than a blank placeholder. local.rootPath = Len(arguments.rootBoxJsonPath) ? arguments.rootBoxJsonPath - : GetDirectoryFromPath(GetCurrentTemplatePath()) & "../box.json"; + : GetDirectoryFromPath(GetCurrentTemplatePath()) & "../../box.json"; try { if (FileExists(local.rootPath)) { local.rootBox = DeserializeJSON(FileRead(local.rootPath)); diff --git a/vendor/wheels/tests/specs/events/frameworkVersionSpec.cfc b/vendor/wheels/tests/specs/events/frameworkVersionSpec.cfc index f17dc8a550..e1634d13b6 100644 --- a/vendor/wheels/tests/specs/events/frameworkVersionSpec.cfc +++ b/vendor/wheels/tests/specs/events/frameworkVersionSpec.cfc @@ -85,6 +85,41 @@ component extends="wheels.WheelsTest" { } }); + it("application.wheels.version resolves to -dev at boot in a monorepo dev checkout (regression for ##2291)", () => { + // Regression for ##2291. Asserts the *runtime boot* result — not a direct + // call — because $readFrameworkVersion is bound into the spec's scope by + // WheelsTest.cfc, which shifts GetCurrentTemplatePath() to this file and + // bypasses the code path we want to cover. application.wheels.version is + // populated by onapplicationstart.cfc calling $readFrameworkVersion() with + // no arguments, so whatever it resolved to is the answer we need to check. + // + // With the bug (one-level "../box.json"): default rootBoxJsonPath points at + // vendor/box.json, which does not exist, so the helper falls through to + // "0.0.0-dev" even in a monorepo checkout. + // With the fix (two-level "../../box.json"): default rootBoxJsonPath points + // at /box.json and yields "-dev". + var wheelsDir = ExpandPath("/wheels/"); + var fwBoxPath = wheelsDir & "box.json"; + var rootBoxPath = wheelsDir & "../../box.json"; + if (!FileExists(fwBoxPath) || !FileExists(rootBoxPath)) { + return; + } + var fwBox = DeserializeJSON(FileRead(fwBoxPath)); + var rootBox = DeserializeJSON(FileRead(rootBoxPath)); + if (!IsStruct(fwBox) || (fwBox.version ?: "") != "@build.version@") { + return; + } + var isWheelsRepo = IsStruct(rootBox) + && ( + ((rootBox.slug ?: "") == "wheels") + || ((rootBox.name ?: "") == "Wheels.fw") + ); + if (!isWheelsRepo || (rootBox.version ?: "") == "" || rootBox.version == "@build.version@") { + return; + } + expect(application.wheels.version).toBe(rootBox.version & "-dev"); + }); + it("$readFrameworkVersion throws Wheels.VersionReadFailed when the file is missing", () => { var missing = getTempDirectory() & "wheels-version-missing-#CreateUUID()#.json"; var threw = false;