@@ -859,7 +859,9 @@ build:mobile-ota:
859859 script :
860860 - cd app/mobile
861861 - npm ci
862- - npm run build:protos
862+ # protos are generated by the `protos` job and pulled in via `needs`; copy the
863+ # grpc-web TS stubs in rather than re-downloading protoc and regenerating.
864+ - mkdir -p proto && cp -a ../proto/gen/ts/proto/. proto/
863865 - npx expo config --type public --json > ota-expo-config.json
864866 - |
865867 for P in $OTA_PLATFORMS; do
@@ -981,6 +983,78 @@ build:devtool-native:
981983 - app/proto/**/*
982984 - app/mobile/**/*
983985
986+ # Staging OTA auto-deploy. Mirrors the web staging deploy (build a static bundle,
987+ # publish to dev-assets, serve from there): bundle the staging variant, stage the
988+ # (unsigned) Expo Updates output, upload bundle+assets to the dev-assets CDN under
989+ # an immutable per-SHA prefix, and print the native_ota_bundles JSON. The staging
990+ # backend (dev-api.couchershq.org/native/ota/manifest) builds the served manifest
991+ # from that flag, with asset URLs pointing at what this job uploaded. Runs on
992+ # develop only. Production publishing goes through the tools/ ops deploy.
993+ build:mobile-ota-staging :
994+ needs : ["protos"]
995+ stage : build
996+ image : node:22
997+ inherit :
998+ default : false
999+ variables :
1000+ APP_VARIANT : staging
1001+ EXPO_PUBLIC_COUCHERS_ENV : preview
1002+ EXPO_PUBLIC_API_BASE_URL : https://dev-api.couchershq.org
1003+ EXPO_PUBLIC_WEB_BASE_URL : https://next.couchershq.org
1004+ OTA_PLATFORMS : " ios android"
1005+ script :
1006+ - cd app/mobile
1007+ - npm ci
1008+ # protos are generated by the `protos` job and pulled in via `needs`; copy the
1009+ # grpc-web TS stubs in rather than re-downloading protoc and regenerating.
1010+ - mkdir -p proto && cp -a ../proto/gen/ts/proto/. proto/
1011+ - npx expo config --type public --json > ota-expo-config.json
1012+ - |
1013+ for P in $OTA_PLATFORMS; do
1014+ rm -rf dist
1015+ npx expo export --platform "$P"
1016+ RV=$(npx expo-updates fingerprint:generate --platform "$P" 2>/dev/null | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).hash))')
1017+ echo "fingerprint($P) = $RV"
1018+ # The asset URLs baked into the manifest must resolve to the upload location
1019+ # below; the CDN host maps <sha>--ota-staging -> the /ota-staging/<sha>/ prefix.
1020+ node scripts/ota-stage.mjs --platform "$P" --runtime-version "$RV" --base-url "https://$CI_COMMIT_SHORT_SHA--ota-staging.$PREVIEW_DOMAIN" --dist dist --out ota-staging-out --expo-config ota-expo-config.json
1021+ done
1022+ - node scripts/ota-growthbook-flag.mjs --out ota-staging-out --platforms "$OTA_PLATFORMS" | tee ota-staging-out/native_ota_bundles.json
1023+ artifacts :
1024+ paths :
1025+ - app/mobile/ota-staging-out/
1026+ expire_in : 1 week
1027+ rules :
1028+ - if : ($BUILD_MOBILE == "true") && ($CI_COMMIT_BRANCH == $RELEASE_BRANCH)
1029+ # TEMP: run on this branch to validate the pipeline; revert before merge.
1030+ - if : $CI_COMMIT_BRANCH == "mobile/feature/ota-staging-publish"
1031+
1032+ deploy:mobile-ota-staging :
1033+ needs : ["build:mobile-ota-staging"]
1034+ stage : deploy
1035+ image : registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest
1036+ inherit :
1037+ # no docker login
1038+ default : false
1039+ variables :
1040+ OTA_PLATFORMS : " ios android"
1041+ script :
1042+ - |
1043+ for P in $OTA_PLATFORMS; do
1044+ D="app/mobile/ota-staging-out/$P"
1045+ # Only the bundle + assets go on the CDN; the manifest is served by the backend.
1046+ aws s3 cp "$D/bundle.hbc" "s3://$AWS_PREVIEW_BUCKET/ota-staging/$CI_COMMIT_SHORT_SHA/$P/bundle.hbc" --content-type application/javascript
1047+ if [ -d "$D/assets" ]; then
1048+ aws s3 cp "$D/assets/" "s3://$AWS_PREVIEW_BUCKET/ota-staging/$CI_COMMIT_SHORT_SHA/$P/assets/" --recursive
1049+ fi
1050+ done
1051+ - echo "Bundle + assets uploaded. Paste this into the staging GrowthBook 'native_ota_bundles' flag:"
1052+ - cat app/mobile/ota-staging-out/native_ota_bundles.json
1053+ rules :
1054+ - if : ($BUILD_MOBILE == "true") && ($CI_COMMIT_BRANCH == $RELEASE_BRANCH)
1055+ # TEMP: run on this branch to validate the pipeline; revert before merge.
1056+ - if : $CI_COMMIT_BRANCH == "mobile/feature/ota-staging-publish"
1057+
9841058preview:protos :
9851059 needs : ["protos"]
9861060 stage : preview
0 commit comments