From 6575217467f38eef60131aeb0291d4091b3cc724 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 18 Aug 2026 23:48:35 +0200 Subject: [PATCH 1/2] Upload one app's screenshots at a time, and say when they doubled Both listings carry the same pictures and ran together, so App Store Connect was taking 264 at once. Enough came back failed that they were uploaded again, and a locale kept the same screenshot three times. The retry is now a failed job rather than a quiet success, because the pictures are up either way and somebody has to look. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01W2XM93Raj1jyvUuYmpQrcz --- .github/workflows/release.yml | 24 +++++++++++++++++++++++- README.md | 6 ++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 02ae1e4..52e6f78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -355,6 +355,11 @@ jobs: runs-on: ubuntu-24.04 strategy: fail-fast: false + # One app at a time. Both listings carry the same 132 pictures, and run + # together they were pushing 264 at App Store Connect at once - enough of + # them came back failed that deliver uploaded them again, which is how a + # locale ends up holding the same screenshot three times. + max-parallel: 1 matrix: include: - app: pro @@ -382,13 +387,30 @@ jobs: name: framed path: fastlane/framed + # Kept, because the check below reads it. `tee` rather than a redirect so + # the step still shows what it is doing while it runs. - name: write ${{ matrix.app }}'s listing env: ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} ASC_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }} ODR_VERSION: ${{ steps.version.outputs.version }} - run: bundle exec fastlane ios ${{ matrix.lane }} + run: | + set -o pipefail + bundle exec fastlane ios ${{ matrix.lane }} 2>&1 | tee listing.log + + # A picture that did not land is uploaded again, and if the delete of the + # failed one does not take, the store keeps both. That leaves a locale + # showing the same screenshot twice, which nothing else here would notice + # - deliver reports the run as a success. So the retry itself is the + # failure: the pictures are up either way, and this says to go and look. + - name: the screenshots went up once each + run: | + set -euo pipefail + if grep -q "Failed to upload all screenshots" listing.log; then + echo "::error::deliver retried the screenshot upload, which can leave duplicates in App Store Connect. Check ${{ matrix.app }}'s screenshots for every locale before submitting, and re-run this job to upload the set again." + exit 1 + fi record: needs: upload diff --git a/README.md b/README.md index 2aa2a9a..f5b159f 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,12 @@ It runs as five jobs: Both apps always go out together, and nothing chooses one: Pro and Lite are the same sources built as two targets, one of which links no ad sdk. +**If a `listing` job fails saying the screenshots did not go up once each**, the +set is up but a locale may hold a picture twice: deliver uploads what it thinks +did not land, and a delete that does not take leaves both. Look at the app's +screenshots in App Store Connect, and re-run that job - it clears the set before +it uploads, so a clean pass fixes it. + **If one app's upload fails, press "Re-run failed jobs".** Only that upload runs again, against the `.ipa` already built and signed - build number included, since it is baked in at archive time - and `record` runs behind it once it lands. From 47e54cc3e98c363a0a0d57252d385f8bfe0683bb Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 18 Aug 2026 23:52:50 +0200 Subject: [PATCH 2/2] Keep only the check, not the guess at the cause Uploading one app at a time was a guess at why the pictures doubled, and re-running one app on its own doubled them again - so the load is not it. The check stays: a run that had to go round again is one to look at. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01W2XM93Raj1jyvUuYmpQrcz --- .github/workflows/release.yml | 5 ----- README.md | 5 +++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52e6f78..b77eedd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -355,11 +355,6 @@ jobs: runs-on: ubuntu-24.04 strategy: fail-fast: false - # One app at a time. Both listings carry the same 132 pictures, and run - # together they were pushing 264 at App Store Connect at once - enough of - # them came back failed that deliver uploaded them again, which is how a - # locale ends up holding the same screenshot three times. - max-parallel: 1 matrix: include: - app: pro diff --git a/README.md b/README.md index f5b159f..feeba2f 100644 --- a/README.md +++ b/README.md @@ -136,8 +136,9 @@ same sources built as two targets, one of which links no ad sdk. **If a `listing` job fails saying the screenshots did not go up once each**, the set is up but a locale may hold a picture twice: deliver uploads what it thinks did not land, and a delete that does not take leaves both. Look at the app's -screenshots in App Store Connect, and re-run that job - it clears the set before -it uploads, so a clean pass fixes it. +screenshots in App Store Connect, and fix the set before submitting. Re-running +the job is worth a try - it clears the set before it uploads - but it has come +back doubled a second time, so check rather than assume. **If one app's upload fails, press "Re-run failed jobs".** Only that upload runs again, against the `.ipa` already built and signed - build number included, since