Your Wheels application is running. Edit this file at app/views/main/index.cfm
\n' \ + "${APP_NAME}" > "${BUILD_DIR}/app/views/main/index.cfm" + +# Materialize directory-keeper markers so empty scaffold dirs survive packaging. +# CommandBox `package publish` keeps .keep / .gitkeep files, so no rename is +# needed — but normalize .gitkeep -> .keep is intentionally NOT done; both ship. +echo "Ensuring db/ ships with a keeper marker..." +touch "${BUILD_DIR}/db/.keep" + +# Translate the LuCLI underscore-prefixed dotfile templates into the CommandBox +# equivalents. _env becomes env.example (box.json's postInstall copies it to +# .env on first install). _gitignore is superseded by the CommandBox-specific +# tools/build/base/.gitignore copied below. +if [ -f "${TEMPLATE_DIR}/_env" ]; then + cp "${TEMPLATE_DIR}/_env" "${BUILD_DIR}/env.example" +fi + mkdir -p "${BUILD_DIR}/vendor" -cp vendor/wheels/.keep "${BUILD_DIR}/vendor/.keep" 2>/dev/null || touch "${BUILD_DIR}/vendor/.keep" +touch "${BUILD_DIR}/vendor/.keep" -# Copy AI documentation files +# Copy AI documentation files from the repo root. echo "Copying AI documentation..." -cp -r .ai "${BUILD_DIR}/" -cp CLAUDE.md "${BUILD_DIR}/" -cp -r .claude "${BUILD_DIR}/" -cp -r .opencode "${BUILD_DIR}/" 2>/dev/null || true +cp -r "${REPO_ROOT}/.ai" "${BUILD_DIR}/" +cp "${REPO_ROOT}/CLAUDE.md" "${BUILD_DIR}/" +cp -r "${REPO_ROOT}/.claude" "${BUILD_DIR}/" +cp -r "${REPO_ROOT}/.opencode" "${BUILD_DIR}/" 2>/dev/null || true # Apache 2.0 §4(d) requires NOTICE to propagate to derivatives. -cp LICENSE "${BUILD_DIR}/" -cp NOTICE "${BUILD_DIR}/" +cp "${REPO_ROOT}/LICENSE" "${BUILD_DIR}/" +cp "${REPO_ROOT}/NOTICE" "${BUILD_DIR}/" # Copy VS Code snippets echo "Copying VS Code snippets..." mkdir -p "${BUILD_DIR}/.vscode" -cp .vscode/wheels.code-snippets "${BUILD_DIR}/.vscode/" -cp .vscode/wheels-test.code-snippets "${BUILD_DIR}/.vscode/" - -# Copy template files, overwriting defaults -cp tools/build/base/.gitignore "${BUILD_DIR}/.gitignore" -cp tools/build/base/box.json "${BUILD_DIR}/box.json" -cp tools/build/base/README.md "${BUILD_DIR}/README.md" -cp tools/build/base/server.json "${BUILD_DIR}/server.json" -cp tools/build/base/config/app.cfm "${BUILD_DIR}/config/app.cfm" -cp tools/build/base/config/settings.cfm "${BUILD_DIR}/config/settings.cfm" - -# Copy .env file -cp .env "${BUILD_DIR}/.env" +cp "${REPO_ROOT}/.vscode/wheels.code-snippets" "${BUILD_DIR}/.vscode/" +cp "${REPO_ROOT}/.vscode/wheels-test.code-snippets" "${BUILD_DIR}/.vscode/" + +# Layer the CommandBox-specific build overrides on top. These are the CommandBox +# counterparts of the LuCLI server config (lucee.json/rewrite.config): a +# CommandBox server.json (webroot/cfengine/rewrites pointing at the template's +# public/urlrewrite.xml), the ForgeBox box.json (dependency + installPaths), the +# package README, the base .gitignore (must NOT exclude db/), and editor/MCP +# config. +echo "Applying CommandBox build overrides..." +cp "${REPO_ROOT}/tools/build/base/.gitignore" "${BUILD_DIR}/.gitignore" +cp "${REPO_ROOT}/tools/build/base/box.json" "${BUILD_DIR}/box.json" +cp "${REPO_ROOT}/tools/build/base/README.md" "${BUILD_DIR}/README.md" +cp "${REPO_ROOT}/tools/build/base/server.json" "${BUILD_DIR}/server.json" +cp "${REPO_ROOT}/tools/build/base/.mcp.json" "${BUILD_DIR}/.mcp.json" +cp "${REPO_ROOT}/tools/build/base/.opencode.json" "${BUILD_DIR}/.opencode.json" + +# Substitute template placeholders to working defaults so the published artifact +# has NO |tokens| / {{tokens}}. `box install` has no substitution step, so this +# is what makes `box server start` boot with zero manual edits. +# +# The app-level tokens ({{appName}}, {{datasourceName}}, {{reloadPassword}}, +# {{luceeAdminPassword}}) appear only in config/app.cfm, config/settings.cfm, +# app/views/layout.cfm and env.example — NOT in app/snippets/*.txt (those carry +# code-gen tokens like {{belongsToRelationships}} that must ship verbatim), so +# substituting these four specific tokens is safe across the whole tree. +# +# The legacy |token| forms come only from the CommandBox overrides (server.json, +# and any historical config copies); substitute them too. +echo "Substituting template placeholders to build defaults..." +substitute_placeholders() { + local file="$1" + sed -i.bak \ + -e "s/{{appName}}/${APP_NAME}/g" \ + -e "s/{{datasourceName}}/${DATASOURCE_NAME}/g" \ + -e "s/{{reloadPassword}}/${RELOAD_PASSWORD}/g" \ + -e "s/{{luceeAdminPassword}}/${LUCEE_ADMIN_PASSWORD}/g" \ + -e "s/|appName|/${APP_NAME}/g" \ + -e "s/|cfmlEngine|/${CFML_ENGINE}/g" \ + -e "s/|datasourceName|/${DATASOURCE_NAME}/g" \ + -e "s/|reloadPassword|/${RELOAD_PASSWORD}/g" \ + "$file" && rm "${file}.bak" +} +# Restrict substitution to config + server + env + the layout view; never touch +# app/snippets/*.txt code-gen templates. +for f in \ + "${BUILD_DIR}/config/app.cfm" \ + "${BUILD_DIR}/config/settings.cfm" \ + "${BUILD_DIR}/config/routes.cfm" \ + "${BUILD_DIR}/config/environment.cfm" \ + "${BUILD_DIR}/app/views/layout.cfm" \ + "${BUILD_DIR}/server.json" \ + "${BUILD_DIR}/env.example"; do + if [ -f "$f" ]; then + substitute_placeholders "$f" + fi +done # Replace version placeholders echo "Replacing version placeholders..." diff --git a/vendor/wheels/tests/specs/buildArtifactLicenseSpec.cfc b/vendor/wheels/tests/specs/buildArtifactLicenseSpec.cfc index 530e64e7f1..d916834eb2 100644 --- a/vendor/wheels/tests/specs/buildArtifactLicenseSpec.cfc +++ b/vendor/wheels/tests/specs/buildArtifactLicenseSpec.cfc @@ -12,6 +12,15 @@ component extends="wheels.WheelsTest" { // asserting the canonical `cp LICENSE` / `cp NOTICE` lines mirrors the // regression-guard pattern used by buildInfoSpec.cfc and // routesViewBrowserFixturesSpec.cfc. + // + // Two source-operand forms are accepted: the bare `cp LICENSE "${BUILD_DIR}/"` + // (core/cli/starterApp run from the repo root, so a relative LICENSE + // resolves) and the CWD-independent `cp "${REPO_ROOT}/LICENSE" "${BUILD_DIR}/"` + // that prepare-base.sh uses (#3196 — the LuCLI-source rebuild derives + // REPO_ROOT from BASH_SOURCE and reads every source file by absolute path, + // so a bare LICENSE would be a lone CWD-dependent outlier). Both forms still + // land LICENSE/NOTICE in BUILD_DIR; the regex remains tight enough that + // deleting the copy line fails the guard. function run() { @@ -36,7 +45,7 @@ component extends="wheels.WheelsTest" { it("copies LICENSE into its BUILD_DIR", () => { var src = fileRead(repoRoot & "/" & relPath); var hasLicense = reFindNoCase( - "cp[[:space:]]+LICENSE[[:space:]]+""\$\{BUILD_DIR\}", + "cp[[:space:]]+(""?\$\{REPO_ROOT\}/)?LICENSE""?[[:space:]]+""\$\{BUILD_DIR\}", src ) > 0; expect(hasLicense).toBeTrue( @@ -47,7 +56,7 @@ component extends="wheels.WheelsTest" { it("copies NOTICE into its BUILD_DIR", () => { var src = fileRead(repoRoot & "/" & relPath); var hasNotice = reFindNoCase( - "cp[[:space:]]+NOTICE[[:space:]]+""\$\{BUILD_DIR\}", + "cp[[:space:]]+(""?\$\{REPO_ROOT\}/)?NOTICE""?[[:space:]]+""\$\{BUILD_DIR\}", src ) > 0; expect(hasNotice).toBeTrue(