fix(build): fail --prod builds with test server defaults; sync web assets before Gradle assembles
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
38af28154e
commit
28ee81b9d3
+15
@@ -1176,6 +1176,10 @@ npm run build:ios:prod
|
||||
(.../.pkgx/zlib.net/v1.3.0/lib/libz.1.3.dylib) built for 'macOS'` then run
|
||||
XCode outside that terminal (ie. not with `npx cap open ios`).
|
||||
- Required password entry 26 times.
|
||||
- Before distributing, confirm the archive carries production server
|
||||
defaults. Xcode packages whatever web bundle is in `ios/App/App/public`,
|
||||
even one from a `--test` build:
|
||||
`./scripts/check-prod-bundle.sh ios/App/App/public`
|
||||
- Click Distribute -> App Store Connect
|
||||
- In AppStoreConnect, add the build to the distribution. You may have to remove
|
||||
the current build with the "-" when you hover over it, then "Add Build" with the
|
||||
@@ -1478,6 +1482,13 @@ cd -
|
||||
|
||||
... and find your `aab` file at app/build/outputs/bundle/release
|
||||
|
||||
* Gradle packages whatever web bundle was last synced into
|
||||
`android/app/src/main/assets/public`, even one from a `--test` build. Before
|
||||
uploading, confirm it has production server defaults:
|
||||
`./scripts/check-prod-bundle.sh android/app/build/outputs/bundle/release/app-release.aab`
|
||||
* `build-android.sh` runs `./gradlew clean`, which deletes any earlier `aab`, so
|
||||
run `bundleRelease` after the build script finishes.
|
||||
|
||||
* Note that F-Droid builds should omit `-PfirebaseEnabled`.
|
||||
|
||||
At play.google.com/console:
|
||||
@@ -2222,6 +2233,8 @@ command chaining, following DRY principles.
|
||||
- `7` - Asset generation failed
|
||||
- `8` - Android Studio launch failed
|
||||
- `9` - Resource check failed
|
||||
- `10` - Production bundle has test/dev server defaults (`--prod` only; see
|
||||
`scripts/check-prod-bundle.sh`)
|
||||
|
||||
### A.4 build-ios.sh
|
||||
|
||||
@@ -2282,6 +2295,8 @@ command chaining, following DRY principles.
|
||||
- **Clean Build**: Removes Xcode build artifacts and DerivedData
|
||||
- **Asset Generation**: Creates platform-specific assets
|
||||
- **Simulator Support**: Launches iOS Simulator for testing
|
||||
- **Production Bundle Check**: With `--prod`, exits with code `10` if the synced
|
||||
web bundle has test/dev server defaults (`scripts/check-prod-bundle.sh`)
|
||||
|
||||
### A.5 common.sh
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"test:prerequisites": "node scripts/check-prerequisites.js",
|
||||
"test:unit": "jest",
|
||||
"check:dependencies": "./scripts/check-dependencies.sh",
|
||||
"check:prod-bundle": "./scripts/check-prod-bundle.sh",
|
||||
"deps:update-daily-notification-plugin": "npm install @timesafari/daily-notification-plugin@git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#master",
|
||||
"test:all": "npm run lint && npm run type-check && npm run type-check:vue && npm run test:unit && npm run test:web && npm run test:mobile && echo '\n\n\nGotta add the performance tests'",
|
||||
"test:web": "npx playwright test -c playwright.config-local.ts --trace on",
|
||||
|
||||
+21
-12
@@ -545,7 +545,7 @@ fi
|
||||
# Handle assets-only mode
|
||||
if [ "$ASSETS_ONLY" = true ]; then
|
||||
log_info "Assets-only mode: generating assets"
|
||||
safe_execute "Generating assets" "npx capacitor-assets generate --android" || exit 7
|
||||
safe_execute "Generating assets" "npx capacitor-assets generate --android --assetPath resources" || exit 7
|
||||
log_success "Assets generation completed successfully!"
|
||||
exit 0
|
||||
fi
|
||||
@@ -612,25 +612,31 @@ elif [ "$BUILD_MODE" = "production" ]; then
|
||||
safe_execute "Building Capacitor version (production)" "npm run build:capacitor -- --mode production" || exit 3
|
||||
fi
|
||||
|
||||
# Step 6: Clean Gradle build
|
||||
# Step 6: Sync with Capacitor (before any Gradle assemble, which packages
|
||||
# whatever web bundle and resources are in android/app/src/main at that moment)
|
||||
safe_execute "Syncing with Capacitor" "npx cap sync android" || exit 6
|
||||
|
||||
# Step 6.5: Restore local plugins (capacitor.plugins.json gets overwritten by cap sync)
|
||||
safe_execute "Restoring local plugins" "node scripts/restore-local-plugins.js" || exit 7
|
||||
|
||||
# Step 6.6: Verify the synced web bundle has production server defaults
|
||||
if [ "$BUILD_MODE" = "production" ]; then
|
||||
safe_execute "Checking production bundle" "./scripts/check-prod-bundle.sh android/app/src/main/assets/public" || exit 10
|
||||
fi
|
||||
|
||||
# Step 7: Generate assets
|
||||
safe_execute "Generating assets" "npx capacitor-assets generate --android --assetPath resources" || exit 7
|
||||
|
||||
# Step 8: Clean Gradle build
|
||||
safe_execute "Cleaning Gradle build" "cd android && ./gradlew clean && cd .." || exit 4
|
||||
|
||||
# Step 7: Build based on type
|
||||
# Step 9: Build based on type
|
||||
if [ "$BUILD_TYPE" = "debug" ]; then
|
||||
safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5
|
||||
elif [ "$BUILD_TYPE" = "release" ]; then
|
||||
safe_execute "Assembling release build" "cd android && ./gradlew assembleRelease && cd .." || exit 5
|
||||
fi
|
||||
|
||||
# Step 8: Sync with Capacitor
|
||||
safe_execute "Syncing with Capacitor" "npx cap sync android" || exit 6
|
||||
|
||||
# Step 8.5: Restore local plugins (capacitor.plugins.json gets overwritten by cap sync)
|
||||
safe_execute "Restoring local plugins" "node scripts/restore-local-plugins.js" || exit 7
|
||||
|
||||
# Step 9: Generate assets
|
||||
safe_execute "Generating assets" "npx capacitor-assets generate --android" || exit 7
|
||||
|
||||
# Step 10: Build APK/AAB if requested
|
||||
if [ "$BUILD_APK" = true ]; then
|
||||
if [ "$BUILD_TYPE" = "debug" ]; then
|
||||
@@ -642,6 +648,9 @@ fi
|
||||
|
||||
if [ "$BUILD_AAB" = true ]; then
|
||||
safe_execute "Building AAB" "cd android && ./gradlew bundleRelease && cd .." || exit 5
|
||||
if [ "$BUILD_MODE" = "production" ]; then
|
||||
safe_execute "Checking production AAB" "./scripts/check-prod-bundle.sh android/app/build/outputs/bundle/release/app-release.aab" || exit 10
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 11: Auto-run app if requested
|
||||
|
||||
@@ -680,6 +680,11 @@ safe_execute "Installing CocoaPods dependencies" "run_pod_install_with_workaroun
|
||||
# Step 6.6: Sync with Capacitor (uses run_cap_sync_with_workaround defined above for Xcode 26)
|
||||
safe_execute "Syncing with Capacitor" "run_cap_sync_with_workaround" || exit 6
|
||||
|
||||
# Step 6.7: Verify the synced web bundle has production server defaults
|
||||
if [ "$BUILD_MODE" = "production" ]; then
|
||||
safe_execute "Checking production bundle" "./scripts/check-prod-bundle.sh ios/App/App/public" || exit 10
|
||||
fi
|
||||
|
||||
# Step 7: Generate assets
|
||||
safe_execute "Generating assets" "generate_ios_assets" || exit 7
|
||||
|
||||
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
# check-prod-bundle.sh
|
||||
# Fails if a built web bundle has test/dev server URLs baked in as defaults.
|
||||
#
|
||||
# Native packaging (gradlew bundleRelease, Xcode archive) ships whatever web
|
||||
# bundle was last synced into the native project, whether it came from a
|
||||
# --test, --dev, or --prod build. Run this on the bundle before uploading.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/check-prod-bundle.sh [PATH...]
|
||||
#
|
||||
# Each PATH is a directory (e.g. android/app/src/main/assets/public,
|
||||
# ios/App/App/public, an .xcarchive) or an .aab, .apk, or .ipa file.
|
||||
# With no PATH, checks the synced Android and iOS web assets plus the
|
||||
# release AAB if it exists.
|
||||
#
|
||||
# Detection: the canary URLs below appear in src/ only as AppString.TEST_*
|
||||
# enum values, which minify to `x.TEST_..._SERVER="<url>"`. Any other quoted
|
||||
# occurrence is a VITE_* default compiled in from .env.test or
|
||||
# .env.development (.env.development also uses the test image server).
|
||||
#
|
||||
# Exit codes: 0 = clean, 1 = test defaults found, 2 = bad input
|
||||
|
||||
source "$(dirname "$0")/common.sh"
|
||||
|
||||
CANARY_REGEX='"https://test(-image-api|-notify-api)?\.timesafari\.app"'
|
||||
ENUM_REGEX='TEST[0-9]*_[A-Z_]+="https'
|
||||
|
||||
# Prints offending snippets from the JS files under a directory; returns 1 if any.
|
||||
check_js_dir() {
|
||||
local dir="$1"
|
||||
local js_count
|
||||
js_count=$(find "$dir" -name "*.js" -path "*assets*" | wc -l | tr -d ' ')
|
||||
if [ "$js_count" = "0" ]; then
|
||||
log_error "No JS assets found under $dir"
|
||||
return 2
|
||||
fi
|
||||
|
||||
local hits
|
||||
hits=$(find "$dir" -name "*.js" -path "*assets*" -print0 \
|
||||
| xargs -0 grep -ohE ".{0,40}${CANARY_REGEX}" \
|
||||
| grep -vE "$ENUM_REGEX")
|
||||
if [ -n "$hits" ]; then
|
||||
log_error "Test/dev server defaults found in bundle:"
|
||||
echo "$hits" | sed 's/^/ /' >&2
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
check_path() {
|
||||
local path="$1"
|
||||
local result
|
||||
|
||||
if [ -d "$path" ]; then
|
||||
check_js_dir "$path"
|
||||
result=$?
|
||||
elif [ -f "$path" ]; then
|
||||
case "$path" in
|
||||
*.aab|*.apk|*.ipa) ;;
|
||||
*)
|
||||
log_error "Unsupported file type: $path"
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
local tmp
|
||||
tmp=$(mktemp -d)
|
||||
unzip -q "$path" '*public/assets/*.js' -d "$tmp" 2>/dev/null
|
||||
check_js_dir "$tmp"
|
||||
result=$?
|
||||
rm -rf "$tmp"
|
||||
else
|
||||
log_error "Not found: $path"
|
||||
return 2
|
||||
fi
|
||||
|
||||
if [ "$result" = "0" ]; then
|
||||
log_success "Production defaults OK: $path"
|
||||
else
|
||||
log_error "Not a production bundle: $path"
|
||||
fi
|
||||
return $result
|
||||
}
|
||||
|
||||
paths=("$@")
|
||||
if [ ${#paths[@]} -eq 0 ]; then
|
||||
for p in android/app/src/main/assets/public \
|
||||
ios/App/App/public \
|
||||
android/app/build/outputs/bundle/release/app-release.aab; do
|
||||
[ -e "$p" ] && paths+=("$p")
|
||||
done
|
||||
fi
|
||||
|
||||
status=0
|
||||
for p in "${paths[@]}"; do
|
||||
check_path "$p"
|
||||
rc=$?
|
||||
[ $rc -gt $status ] && status=$rc
|
||||
done
|
||||
exit $status
|
||||
Reference in New Issue
Block a user