Created
March 17, 2026 00:02
-
-
Save tpaksu/004a29734c7db6e297ce57d1d21d48f9 to your computer and use it in GitHub Desktop.
WCC Support: Build comparison script for verifying repo restructuring safety
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # Compares the unminified JS/CSS build output between trunk and the current branch | |
| # to verify that the repo restructuring did not change app behavior. | |
| # | |
| # Usage: bin/compare-builds.sh | |
| # | |
| # Requires: nvm, node (via .nvmrc) | |
| set -euo pipefail | |
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| PROJECT_DIR="$(dirname "$SCRIPT_DIR")" | |
| WORK_DIR=$(mktemp -d /tmp/wcc-build-compare.XXXXXX) | |
| CURRENT_BRANCH=$(git -C "$PROJECT_DIR" rev-parse --abbrev-ref HEAD) | |
| cleanup() { | |
| echo "" | |
| echo "Cleaning up..." | |
| git -C "$PROJECT_DIR" checkout -- package-lock.json 2>/dev/null || true | |
| git -C "$PROJECT_DIR" checkout "$CURRENT_BRANCH" 2>/dev/null || true | |
| rm -rf "$WORK_DIR" | |
| } | |
| trap cleanup EXIT | |
| echo "============================================" | |
| echo " WCC Support Build Comparison" | |
| echo "============================================" | |
| echo "" | |
| echo "Comparing: trunk vs ${CURRENT_BRANCH}" | |
| echo "Work dir: ${WORK_DIR}" | |
| echo "" | |
| # Source nvm | |
| export NVM_DIR="$HOME/.nvm" | |
| # shellcheck disable=SC1091 | |
| [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" | |
| cd "$PROJECT_DIR" | |
| # --- Build from trunk --- | |
| echo "=== Building from trunk ===" | |
| git stash -q 2>/dev/null || true | |
| git checkout trunk -q | |
| nvm use -q | |
| npm install --silent 2>/dev/null | |
| cross-env NODE_ENV=development npx webpack --config webpack.production.config.js 2>&1 | tail -1 | |
| cp svn/mc/tools/woo-connect/wcc-support-app.js "$WORK_DIR/old.js" | |
| cp svn/mc/tools/woo-connect/wcc-support-app.css "$WORK_DIR/old.css" | |
| echo "Saved trunk build to ${WORK_DIR}/old.*" | |
| echo "" | |
| # --- Build from current branch --- | |
| echo "=== Building from ${CURRENT_BRANCH} ===" | |
| git checkout -- package-lock.json | |
| git checkout "$CURRENT_BRANCH" -q | |
| nvm use -q | |
| npm install --silent 2>/dev/null | |
| npm run build:dev 2>&1 | tail -1 | |
| cp dist/wcc-support-app.js "$WORK_DIR/new.js" | |
| cp dist/wcc-support-app.css "$WORK_DIR/new.css" | |
| echo "Saved ${CURRENT_BRANCH} build to ${WORK_DIR}/new.*" | |
| echo "" | |
| # --- Compare --- | |
| echo "============================================" | |
| echo " Results" | |
| echo "============================================" | |
| echo "" | |
| # CSS comparison (strip source maps) | |
| sed '/sourceMappingURL/d' "$WORK_DIR/old.css" > "$WORK_DIR/old.css.stripped" | |
| sed '/sourceMappingURL/d' "$WORK_DIR/new.css" > "$WORK_DIR/new.css.stripped" | |
| if diff -q "$WORK_DIR/old.css.stripped" "$WORK_DIR/new.css.stripped" > /dev/null 2>&1; then | |
| echo "CSS (sans source maps): IDENTICAL" | |
| else | |
| echo "CSS (sans source maps): DIFFERENT" | |
| diff "$WORK_DIR/old.css.stripped" "$WORK_DIR/new.css.stripped" | head -20 | |
| fi | |
| echo "" | |
| # JS comparison | |
| OLD_JS_SIZE=$(wc -c < "$WORK_DIR/old.js") | |
| NEW_JS_SIZE=$(wc -c < "$WORK_DIR/new.js") | |
| echo "JS file sizes: trunk=${OLD_JS_SIZE} bytes, branch=${NEW_JS_SIZE} bytes" | |
| echo "" | |
| # Normalize and extract app code for comparison | |
| python3 - "$WORK_DIR" <<'PYEOF' | |
| import re, sys | |
| work_dir = sys.argv[1] | |
| with open(f'{work_dir}/old.js', 'r') as f: | |
| old = f.read() | |
| with open(f'{work_dir}/new.js', 'r') as f: | |
| new = f.read() | |
| def normalize(text): | |
| # Remove inline source maps | |
| text = re.sub(r'/\*#\s*sourceMappingURL=data:.*?\*/', '', text) | |
| text = re.sub(r'//# sourceMappingURL=data:.*', '', text) | |
| # Normalize paths: client/ -> app/, client/stylesheets/ -> assets/stylesheets/ | |
| text = text.replace('./client/stylesheets/', './assets/stylesheets/') | |
| text = text.replace('./client/', './app/') | |
| text = text.replace('client/stylesheets/', 'assets/stylesheets/') | |
| text = text.replace('client/', 'app/') | |
| # Normalize emotion target hashes | |
| text = re.sub(r'target:\s*"[a-z0-9]+"', 'target: "HASH"', text) | |
| # Remove webpack banner comments | |
| text = re.sub(r'/\*![*!\\\\]+\n', '', text) | |
| text = re.sub(r'\\\\[*!]+/', '', text) | |
| text = re.sub(r'!\*\*+!', '', text) | |
| return text | |
| old_n = normalize(old) | |
| new_n = normalize(new) | |
| # Extract all app/ module code blocks | |
| def extract_all_app_code(text): | |
| chunks = [] | |
| parts = text.split('"./app/') | |
| for part in parts[1:]: | |
| mod_end = part.find('\n/***/ "', 100) | |
| node_end = part.find('"./node_modules/', 100) | |
| end = len(part) | |
| if mod_end != -1: | |
| end = min(end, mod_end) | |
| if node_end != -1: | |
| end = min(end, node_end) | |
| chunks.append(part[:end]) | |
| return '\n'.join(chunks) | |
| old_app = extract_all_app_code(old_n) | |
| new_app = extract_all_app_code(new_n) | |
| print(f'App code size: trunk={len(old_app)} chars, branch={len(new_app)} chars') | |
| print(f'App code lines: trunk={len(old_app.splitlines())}, branch={len(new_app.splitlines())}') | |
| print() | |
| if old_app == new_app: | |
| print('APP CODE (normalized): IDENTICAL') | |
| print() | |
| print('All app module code is byte-for-byte identical after normalizing') | |
| print('path references and emotion CSS hashes.') | |
| else: | |
| old_lines = old_app.splitlines() | |
| new_lines = new_app.splitlines() | |
| diffs = [] | |
| for i in range(min(len(old_lines), len(new_lines))): | |
| if old_lines[i].strip() != new_lines[i].strip(): | |
| diffs.append((i + 1, old_lines[i].strip()[:120], new_lines[i].strip()[:120])) | |
| print(f'APP CODE DIFFERENCES: {len(diffs)} line(s)') | |
| print() | |
| for line_num, old_line, new_line in diffs: | |
| print(f' Line {line_num}:') | |
| print(f' trunk: {old_line}') | |
| print(f' branch: {new_line}') | |
| print() | |
| # Polyfill analysis | |
| has_babel_old = 'babel-polyfill' in old or 'babel_polyfill' in old | |
| has_babel_new = 'babel-polyfill' in new or 'babel_polyfill' in new | |
| print('POLYFILL CHANGES:') | |
| print(f' babel-polyfill in trunk: {has_babel_old}') | |
| print(f' babel-polyfill in branch: {has_babel_new}') | |
| if has_babel_old and not has_babel_new: | |
| print(' -> babel-polyfill replaced with core-js 3 (intentional)') | |
| print() | |
| # Summary | |
| print('============================================') | |
| print(' Summary') | |
| print('============================================') | |
| print() | |
| categories = [] | |
| categories.append(('CSS (sans source maps)', 'IDENTICAL' if open(f'{work_dir}/old.css.stripped').read() == open(f'{work_dir}/new.css.stripped').read() else 'DIFFERENT')) | |
| if old_app == new_app: | |
| categories.append(('JS app code', 'IDENTICAL')) | |
| elif len(diffs) <= 5: | |
| categories.append(('JS app code', f'{len(diffs)} line(s) differ (see above)')) | |
| else: | |
| categories.append(('JS app code', f'{len(diffs)} lines differ (REVIEW NEEDED)')) | |
| if has_babel_old and not has_babel_new: | |
| categories.append(('JS polyfills', 'babel-polyfill -> core-js 3 (intentional)')) | |
| else: | |
| categories.append(('JS polyfills', 'unchanged')) | |
| categories.append(('Source maps', 'path references updated (expected)')) | |
| categories.append(('Emotion hashes', 'changed due to file path rename (no visual impact)')) | |
| categories.append(('Webpack banners', 'width differs due to longer path (cosmetic)')) | |
| for name, result in categories: | |
| print(f' {name}: {result}') | |
| PYEOF | |
| echo "" | |
| echo "============================================" | |
| echo " Done" | |
| echo "============================================" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment