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
|
(.../.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`).
|
XCode outside that terminal (ie. not with `npx cap open ios`).
|
||||||
- Required password entry 26 times.
|
- 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
|
- Click Distribute -> App Store Connect
|
||||||
- In AppStoreConnect, add the build to the distribution. You may have to remove
|
- 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
|
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
|
... 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`.
|
* Note that F-Droid builds should omit `-PfirebaseEnabled`.
|
||||||
|
|
||||||
At play.google.com/console:
|
At play.google.com/console:
|
||||||
@@ -2222,6 +2233,8 @@ command chaining, following DRY principles.
|
|||||||
- `7` - Asset generation failed
|
- `7` - Asset generation failed
|
||||||
- `8` - Android Studio launch failed
|
- `8` - Android Studio launch failed
|
||||||
- `9` - Resource check 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
|
### A.4 build-ios.sh
|
||||||
|
|
||||||
@@ -2282,6 +2295,8 @@ command chaining, following DRY principles.
|
|||||||
- **Clean Build**: Removes Xcode build artifacts and DerivedData
|
- **Clean Build**: Removes Xcode build artifacts and DerivedData
|
||||||
- **Asset Generation**: Creates platform-specific assets
|
- **Asset Generation**: Creates platform-specific assets
|
||||||
- **Simulator Support**: Launches iOS Simulator for testing
|
- **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
|
### A.5 common.sh
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"test:prerequisites": "node scripts/check-prerequisites.js",
|
"test:prerequisites": "node scripts/check-prerequisites.js",
|
||||||
"test:unit": "jest",
|
"test:unit": "jest",
|
||||||
"check:dependencies": "./scripts/check-dependencies.sh",
|
"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",
|
"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: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",
|
"test:web": "npx playwright test -c playwright.config-local.ts --trace on",
|
||||||
|
|||||||
+21
-12
@@ -545,7 +545,7 @@ fi
|
|||||||
# Handle assets-only mode
|
# Handle assets-only mode
|
||||||
if [ "$ASSETS_ONLY" = true ]; then
|
if [ "$ASSETS_ONLY" = true ]; then
|
||||||
log_info "Assets-only mode: generating assets"
|
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!"
|
log_success "Assets generation completed successfully!"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -612,25 +612,31 @@ elif [ "$BUILD_MODE" = "production" ]; then
|
|||||||
safe_execute "Building Capacitor version (production)" "npm run build:capacitor -- --mode production" || exit 3
|
safe_execute "Building Capacitor version (production)" "npm run build:capacitor -- --mode production" || exit 3
|
||||||
fi
|
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
|
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
|
if [ "$BUILD_TYPE" = "debug" ]; then
|
||||||
safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5
|
safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5
|
||||||
elif [ "$BUILD_TYPE" = "release" ]; then
|
elif [ "$BUILD_TYPE" = "release" ]; then
|
||||||
safe_execute "Assembling release build" "cd android && ./gradlew assembleRelease && cd .." || exit 5
|
safe_execute "Assembling release build" "cd android && ./gradlew assembleRelease && cd .." || exit 5
|
||||||
fi
|
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
|
# Step 10: Build APK/AAB if requested
|
||||||
if [ "$BUILD_APK" = true ]; then
|
if [ "$BUILD_APK" = true ]; then
|
||||||
if [ "$BUILD_TYPE" = "debug" ]; then
|
if [ "$BUILD_TYPE" = "debug" ]; then
|
||||||
@@ -642,6 +648,9 @@ fi
|
|||||||
|
|
||||||
if [ "$BUILD_AAB" = true ]; then
|
if [ "$BUILD_AAB" = true ]; then
|
||||||
safe_execute "Building AAB" "cd android && ./gradlew bundleRelease && cd .." || exit 5
|
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
|
fi
|
||||||
|
|
||||||
# Step 11: Auto-run app if requested
|
# 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)
|
# 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
|
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
|
# Step 7: Generate assets
|
||||||
safe_execute "Generating assets" "generate_ios_assets" || exit 7
|
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