From 22ef002e3fc0fe5a3ec1bc275111ec223e545146 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 17 Jun 2026 17:41:30 -0500 Subject: [PATCH] Read iOS build number from the IPA, not the remote counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setGitHubOutput.sh derives the build number from `eas build:version:get`, which reads EAS's remote counter. A --local build doesn't advance that counter, but use-build-number-with-bump bakes counter+1 into the IPA — so the queried number can be one less than what actually lands in App Store Connect. That made distribute_only poll for a nonexistent build and would have announced the wrong number in Slack. Read CFBundleVersion straight from the built IPA instead, which is the value uploaded to ASC. Repoint the fastlane assignment, the workflow_call build-number output, and the production Slack message at it. Android's version code has the same drift source but is display-only there (no version-code lookup gates submission), so it's left as-is. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/build-submit-ios.yml | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-submit-ios.yml b/.github/workflows/build-submit-ios.yml index 350957b897..73430687a0 100644 --- a/.github/workflows/build-submit-ios.yml +++ b/.github/workflows/build-submit-ios.yml @@ -51,7 +51,7 @@ jobs: cancel-in-progress: false outputs: package-version: ${{ steps.get-build-info.outputs.PACKAGE_VERSION }} - build-number: ${{ steps.get-build-info.outputs.BSKY_IOS_BUILD_NUMBER }} + build-number: ${{ steps.ipa-build-number.outputs.build-number }} steps: - name: Check for EXPO_TOKEN run: > @@ -193,6 +193,26 @@ jobs: id: get-build-info run: bash scripts/setGitHubOutput.sh + # Read the build number straight from the IPA's CFBundleVersion. This is the value + # baked in at build time by use-build-number-with-bump (remote counter + 1) and the + # number that actually lands in App Store Connect. `eas build:version:get` reads the + # remote counter, which a --local build does not advance, so it can be off by one — + # using it here would make distribute_only poll for a nonexistent build. + - name: 🔢 Read build number from IPA + id: ipa-build-number + run: | + plist_dir="$(mktemp -d)" + unzip -o -q "$BUILD_DIR/Bluesky.ipa" 'Payload/*.app/Info.plist' -d "$plist_dir" + plist="$(find "$plist_dir" -name Info.plist -print -quit)" + build_number="$(/usr/libexec/PlistBuddy -c 'Print CFBundleVersion' "$plist")" + rm -rf "$plist_dir" + if [ -z "$build_number" ]; then + echo "ERROR: could not read CFBundleVersion from IPA" + exit 1 + fi + echo "IPA build number: $build_number" + echo "build-number=$build_number" >> "$GITHUB_OUTPUT" + # eas submit only uploads to App Store Connect; it can't assign a build to a # TestFlight group. fastlane's distribute_only mode skips the upload and assigns the # already-submitted build to the group, polling until Apple finishes processing it. @@ -204,7 +224,7 @@ jobs: ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} ASC_KEY_P8_BASE64: ${{ secrets.ASC_KEY_P8_BASE64 }} APP_VERSION: ${{ steps.get-build-info.outputs.PACKAGE_VERSION }} - BUILD_NUMBER: ${{ steps.get-build-info.outputs.BSKY_IOS_BUILD_NUMBER }} + BUILD_NUMBER: ${{ steps.ipa-build-number.outputs.build-number }} RELEASE_NOTES: ${{ inputs.releaseNotes }} run: | # Ensure the API key material is removed even if fastlane exits non-zero @@ -234,7 +254,7 @@ jobs: webhook-type: incoming-webhook payload-templated: true payload: | - {"text": "iOS production build for App Store submission is ready!\n```Artifact: Check TestFlight to know when it is available\nVersion Number: ${{ steps.get-build-info.outputs.PACKAGE_VERSION }}\nBuild Number: ${{ steps.get-build-info.outputs.BSKY_IOS_BUILD_NUMBER }}```"} + {"text": "iOS production build for App Store submission is ready!\n```Artifact: Check TestFlight to know when it is available\nVersion Number: ${{ steps.get-build-info.outputs.PACKAGE_VERSION }}\nBuild Number: ${{ steps.ipa-build-number.outputs.build-number }}```"} - name: ⬇️ Restore Cache id: get-base-commit