diff --git a/.github/workflows/release-on-version.yml b/.github/workflows/release-on-version.yml index 1171c17..9b4a360 100644 --- a/.github/workflows/release-on-version.yml +++ b/.github/workflows/release-on-version.yml @@ -89,8 +89,16 @@ jobs: run: | set -euo pipefail ROOT="$(pwd)/staging" - if grep -R -n "{{APP_QVER}}\|{{APP_VER}}" "$ROOT" --include='*.html' --include='*.php' --include='*.css' --include='*.js' 2>/dev/null; then - echo "ERROR: Found unreplaced placeholders above in staging." + if grep -R -n -E "{{APP_QVER}}|{{APP_VER}}" "$ROOT" \ + --include='*.html' --include='*.php' --include='*.css' --include='*.js' 2>/dev/null; then + echo "---- DEBUG (show 10 hits with context) ----" + grep -R -n -E "{{APP_QVER}}|{{APP_VER}}" "$ROOT" \ + --include='*.html' --include='*.php' --include='*.css' --include='*.js' \ + | head -n 10 | while IFS=: read -r file line _; do + echo ">>> $file:$line" + nl -ba "$file" | sed -n "$((line-3)),$((line+3))p" || true + echo "----------------------------------------" + done exit 1 fi echo "OK: No unreplaced placeholders in staging." diff --git a/CHANGELOG.md b/CHANGELOG.md index 1025691..d8101e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Changes 10/29/2025 (v1.7.0 & v1.7.1) +## Changes 10/29/2025 (v1.7.0 & v1.7.1 & v1.7.2) release(v1.7.0): asset cache-busting pipeline, public siteConfig cache, JS core split, and caching/security polish @@ -70,6 +70,18 @@ release(v1.7.0): asset cache-busting pipeline, public siteConfig cache, JS core - normalize line endings (strip CRLF) - stamp-assets.sh don’t rely on the exec; invoke via bash +release(v1.7.2): harden asset stamping & CI verification + +### build(stamper) + +- Rewrite scripts/stamp-assets.sh to be repo-agnostic and macOS/Windows friendly: + - Drop reliance on git ls-files/mapfile; use find + null-delimited loops + - Normalize CRLF to LF for all web assets before stamping + - Stamp ?v= in HTML/CSS/PHP and {{APP_VER}} everywhere + - Normalize any ".mjs|.js?v=..." occurrences inside JS (ESM imports/strings) + - Force-write public/js/version.js from VER (source of truth in stamped output) + - Print touched counts and fail fast if any {{APP_QVER}}|{{APP_VER}} remain + --- ## Changes 10/28/2025 (v1.6.11) diff --git a/scripts/stamp-assets.sh b/scripts/stamp-assets.sh index 97da749..f6d332d 100644 --- a/scripts/stamp-assets.sh +++ b/scripts/stamp-assets.sh @@ -1,37 +1,54 @@ #!/usr/bin/env bash -# usage: scripts/stamp-assets.sh v1.6.12 /path/to/target/dir +# usage: scripts/stamp-assets.sh vX.Y.Z /path/to/target/dir set -euo pipefail + VER="${1:?usage: stamp-assets.sh vX.Y.Z target_dir}" QVER="${VER#v}" TARGET="${2:-.}" +echo "Stamping assets in: $TARGET" +echo "VER=${VER} QVER=${QVER}" + cd "$TARGET" -# Build file lists. Prefer git ls-files if we're in a repo, else use find. -if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - mapfile -t HTML_CSS < <(git ls-files -- 'public/*.html' 'public/**/*.html' 'public/*.php' 'public/**/*.css' || true) - mapfile -t JSFILES < <(git ls-files -- 'public/*.js' 'public/**/*.js' 'js/*.js' 'js/**/*.js' || true) -else - mapfile -t HTML_CSS < <(find public -type f \( -name '*.html' -o -name '*.php' -o -name '*.css' \) -print 2>/dev/null || true) - mapfile -t JSFILES < <(find public js -type f -name '*.js' -print 2>/dev/null || true) -fi +# Normalize CRLF to LF (if any files were edited on Windows) +# We only touch web assets. +find public \( -name '*.html' -o -name '*.php' -o -name '*.css' -o -name '*.js' \) -type f -print0 \ + | xargs -0 -r sed -i 's/\r$//' -# HTML/CSS/PHP: stamp ?v=... and {{APP_VER}} -for f in "${HTML_CSS[@]}"; do +# --- HTML/CSS/PHP: stamp ?v=... and {{APP_VER}} --- +# (?v=...) -> ?v= +HTML_CSS_COUNT=0 +while IFS= read -r -d '' f; do sed -E -i "s/(\?v=)[^\"'&<>\s]*/\1${QVER}/g" "$f" sed -E -i "s/\{\{APP_VER\}\}/${VER}/g" "$f" -done + HTML_CSS_COUNT=$((HTML_CSS_COUNT+1)) +done < <(find public -type f \( -name '*.html' -o -name '*.php' -o -name '*.css' \) -print0) -# JS: stamp placeholders and normalize any pre-existing ?v=... -for f in "${JSFILES[@]}"; do +# --- JS: stamp placeholders and normalize any pre-existing ?v=... --- +JS_COUNT=0 +while IFS= read -r -d '' f; do + # Replace placeholders sed -E -i "s/\{\{APP_VER\}\}/${VER}/g" "$f" sed -E -i "s/\{\{APP_QVER\}\}/${QVER}/g" "$f" + # Normalize any "?v=..." that appear in ESM imports or strings + # This keeps any ".js" or ".mjs" then forces ?v= perl -0777 -i -pe "s@(\.m?js)\?v=[^\"')]+@\1?v=${QVER}@g" "$f" -done + JS_COUNT=$((JS_COUNT+1)) +done < <(find public -type f -name '*.js' -print0) -# Optional: version.js fallback update +# Force-write version.js (source of truth in stamped output) if [[ -f public/js/version.js ]]; then - sed -E -i "s/(APP_VERSION\s*=\s*['\"])v[^'\"]+(['\"])/\1${VER}\2/" public/js/version.js + printf "window.APP_VERSION = '%s';\n" "$VER" > public/js/version.js fi -echo "Stamped assets in ${TARGET} to ${VER} (${QVER})" \ No newline at end of file +echo "Touched files: HTML/CSS/PHP=${HTML_CSS_COUNT}, JS=${JS_COUNT}" + +# Final self-check: fail if anything is left +if grep -R -n -E "{{APP_QVER}}|{{APP_VER}}" public \ + --include='*.html' --include='*.php' --include='*.css' --include='*.js' 2>/dev/null; then + echo "ERROR: Placeholders remain after stamping." >&2 + exit 2 +fi + +echo "✅ Stamped to ${VER} (${QVER})" \ No newline at end of file