diff --git a/changelog.d/3173-base-template-placeholders.fixed.md b/changelog.d/3173-base-template-placeholders.fixed.md new file mode 100644 index 0000000000..b98ba6182b --- /dev/null +++ b/changelog.d/3173-base-template-placeholders.fixed.md @@ -0,0 +1 @@ +- Base template (`tools/build/base`) now ships working defaults instead of unsubstituted `|appName|` / `|cfmlEngine|` / `|datasourceName|` / `|reloadPassword|` placeholders, so `box install wheels-base-template` → `box server start` boots out of the box instead of failing with "Invalid slug detected". The dead `env.example` reference in the template `box.json` postInstall is also removed (#3173). diff --git a/tools/build/base/box.json b/tools/build/base/box.json index 148a5daf45..bc208f018b 100644 --- a/tools/build/base/box.json +++ b/tools/build/base/box.json @@ -48,7 +48,6 @@ } ], "scripts":{ - "postInstall":"pathExists .env || cp env.example .env && mv env.example .env.example", "format":"cfformat run config/,controllers/,events/,files/,global/,miscellaneous/,models/,tests/,views/,*.cfc --overwrite", "format:check":"cfformat check config/,controllers/,events/,files/,global/,miscellaneous/,models/,tests/,views/,*.cfc", "format:watch":"cfformat watch path='config/,controllers/,events/,files/,global/,miscellaneous/,models/,tests/,views/,*.cfc' settingsPath='.cfformat.json'" diff --git a/tools/build/base/config/app.cfm b/tools/build/base/config/app.cfm index 9856f737a5..2c270dd61d 100644 --- a/tools/build/base/config/app.cfm +++ b/tools/build/base/config/app.cfm @@ -7,6 +7,8 @@ this.sessionTimeout = CreateTimeSpan(0,0,5,0); */ - this.name = "|appName|"; + // Leave this commented to let Wheels derive the application name from the + // folder it lives in. Uncomment and set a literal name to override. + // this.name = "MyAppName"; // CLI-Appends-Here diff --git a/tools/build/base/config/settings.cfm b/tools/build/base/config/settings.cfm index d24f2a310f..121902cff1 100644 --- a/tools/build/base/config/settings.cfm +++ b/tools/build/base/config/settings.cfm @@ -9,8 +9,8 @@ /* If you leave these settings commented out, wheels will set the data source name to the same name as the folder the application resides in. */ - set(coreTestDataSourceName="|datasourceName|"); - set(dataSourceName="|datasourceName|"); + // set(coreTestDataSourceName="myDatasource"); + // set(dataSourceName="myDatasource"); // set(dataSourceUserName=""); // set(dataSourcePassword=""); @@ -22,8 +22,9 @@ */ set(URLRewriting="On"); - // Reload your application with ?reload=true&password=|reloadPassword| - set(reloadPassword="|reloadPassword|"); + // Reload your application with ?reload=true&password= + // The secret is read from .env (git-ignored) so it never lands in version control. + set(reloadPassword=env("WHEELS_RELOAD_PASSWORD", "")); // CLI-Appends-Here diff --git a/tools/build/base/server.json b/tools/build/base/server.json index f789b25ec3..6d954e279e 100644 --- a/tools/build/base/server.json +++ b/tools/build/base/server.json @@ -1,5 +1,4 @@ { - "name":"|appName|", "web":{ "host":"localhost", "webroot": "public", @@ -9,7 +8,7 @@ } }, "app":{ - "cfengine":"|cfmlEngine|", + "cfengine":"lucee@7", "libDirs":"app/lib" } } diff --git a/vendor/wheels/tests/specs/baseTemplatePlaceholdersSpec.cfc b/vendor/wheels/tests/specs/baseTemplatePlaceholdersSpec.cfc new file mode 100644 index 0000000000..fb92990a2a --- /dev/null +++ b/vendor/wheels/tests/specs/baseTemplatePlaceholdersSpec.cfc @@ -0,0 +1,74 @@ +component extends="wheels.WheelsTest" { + + // Regression guard for issue ##3173. + // + // The ForgeBox `wheels-base-template` ships the static files under + // tools/build/base/ verbatim — tools/build/scripts/prepare-base.sh only + // substitutes @build.version@ / @build.number@, nothing else. The legacy + // `|appName|` / `|cfmlEngine|` / `|datasourceName|` / `|reloadPassword|` + // tokens were only ever resolved by the retired CommandBox `cfwheels-cli` + // (`wheels create app`) flow, so on the README's documented direct-install + // path (`box install wheels-base-template` -> `box server start`) they + // reach the user unresolved and `box server start` aborts with + // "Invalid slug detected" while resolving the `|cfmlEngine|` engine slug. + // + // The shipped files must therefore carry inert working defaults, never + // pipe-delimited placeholders. Structural source assertion in the spirit + // of buildArtifactLicenseSpec.cfc / buildInfoSpec.cfc — invoking the + // CommandBox install path inside a test is not feasible. + // + // expandPath("/wheels") resolves to vendor/wheels via the configured + // Lucee mapping; the repo root is two levels above. + + function run() { + + describe("Base template (tools/build/base) ships working defaults, not placeholders (issue ##3173)", () => { + + var repoRoot = expandPath("/wheels/../.."); + + // Pipe-delimited legacy CLI tokens, e.g. |appName|, |cfmlEngine|. + var placeholderRegex = "\|[A-Za-z][A-Za-z0-9_]*\|"; + + var baseFiles = [ + "tools/build/base/server.json", + "tools/build/base/config/app.cfm", + "tools/build/base/config/settings.cfm" + ]; + + for (var rel in baseFiles) { + // Capture the loop variable so each closure binds the current + // value, not the final iteration's value. + (function(relPath) { + it("ships " & relPath & " without unsubstituted |placeholder| tokens", () => { + var content = fileRead(repoRoot & "/" & relPath); + var matches = reMatch(placeholderRegex, content); + expect(arrayLen(matches)).toBe( + 0, + relPath & " still contains legacy |placeholder| token(s): " + & arrayToList(matches, ", ") + & ". These are never substituted on the `box install wheels-base-template` " + & "path and break `box server start`. Ship inert working defaults instead. See issue ##3173." + ); + }); + })(rel); + } + + it("pins server.json cfengine to a concrete engine slug", () => { + var server = deserializeJSON(fileRead(repoRoot & "/tools/build/base/server.json")); + expect(server.app.cfengine).notToInclude("|"); + expect(len(server.app.cfengine)).toBeGT(0); + }); + + it("box.json postInstall does not reference the non-shipped env.example", () => { + var box = deserializeJSON(fileRead(repoRoot & "/tools/build/base/box.json")); + var postInstall = box.keyExists("scripts") && box.scripts.keyExists("postInstall") + ? box.scripts.postInstall + : ""; + expect(postInstall).notToInclude("env.example"); + }); + + }); + + } + +}