From 36acf1517c708d1a22543b5c91ace5be192a27b4 Mon Sep 17 00:00:00 2001 From: Adam Borbas Date: Fri, 17 Jul 2026 23:00:55 +0200 Subject: [PATCH] Screenshots: target iOS 26 sims + run capture on CI capture-screenshots.sh now selects only iOS 26+ simulators (highest version wins) so screenshots show the iOS 26 Liquid Glass styling, and fails loudly if a required device is missing on that runtime. It also honours SCREENSHOT_XCODEBUILD_ARGS so CI can disable code signing (simulator builds need none). Adds an 'App Store Screenshots' workflow_dispatch workflow that runs the script on the Xcode 26 image and uploads the result as an artifact, and wires the same signing-flag env into the existing promo-screenshots job (resolving its TODO). Co-Authored-By: Claude Opus 4.8 --- .github/workflows/release.yml | 8 +++++--- .github/workflows/screenshots.yml | 33 +++++++++++++++++++++++++++++++ scripts/capture-screenshots.sh | 30 +++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/screenshots.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f9ed6dc..10716ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,10 +59,12 @@ jobs: - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer - # TODO: The script was written for local use and will need CI-friendly - # xcodebuild flags (CODE_SIGN_IDENTITY="", CODE_SIGNING_REQUIRED=NO) - # passed through to capture-screenshots.sh before this works on runners. + # SCREENSHOT_XCODEBUILD_ARGS disables code signing for the underlying + # capture-screenshots.sh so the UI-test build works on a runner (simulator + # builds need no signing). - name: Generate promo screenshots + env: + SCREENSHOT_XCODEBUILD_ARGS: 'CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO COMPILER_INDEX_STORE_ENABLE=NO' run: ./scripts/generate-promo-screenshots.sh - name: Upload promo screenshots diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml new file mode 100644 index 0000000..56ea8cf --- /dev/null +++ b/.github/workflows/screenshots.yml @@ -0,0 +1,33 @@ +name: App Store Screenshots + +on: + workflow_dispatch: + +env: + XCODE_VERSION: '26.2' + +jobs: + screenshots: + name: Capture App Store Screenshots + runs-on: macos-15 + timeout-minutes: 60 + if: github.actor == 'adborbas' + steps: + - uses: actions/checkout@v4 + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer + + # The script targets iOS 26 simulators (Liquid Glass styling), which ship + # with the Xcode 26 image. SCREENSHOT_XCODEBUILD_ARGS disables code signing + # so the UI-test build works on a runner (simulator builds need no signing). + - name: Capture App Store screenshots + env: + SCREENSHOT_XCODEBUILD_ARGS: 'CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO COMPILER_INDEX_STORE_ENABLE=NO' + run: ./scripts/capture-screenshots.sh + + - name: Upload screenshots + uses: actions/upload-artifact@v4 + with: + name: app-store-screenshots + path: Screenshots/ diff --git a/scripts/capture-screenshots.sh b/scripts/capture-screenshots.sh index 1139a68..7694455 100755 --- a/scripts/capture-screenshots.sh +++ b/scripts/capture-screenshots.sh @@ -7,21 +7,32 @@ SCHEME="Hemera" OUTPUT_DIR="$PROJECT_DIR/Screenshots" DERIVED_DATA="$PROJECT_DIR/.deriveddata-screenshots" -# Find simulator UDID for a device name, preferring the latest runtime. +# Extra args appended to every `xcodebuild test` run. CI sets this to pass the +# code-signing flags a simulator build needs on a runner (no signing identity); +# empty for local runs, which sign automatically. Word-split on spaces. +EXTRA_XCODEBUILD_ARGS=(${SCREENSHOT_XCODEBUILD_ARGS:-}) + +# Find simulator UDID for a device name, restricted to iOS 26+ runtimes so the +# screenshots capture the iOS 26 "Liquid Glass" styling — older runtimes render +# the pre-26 look. Among matching runtimes the highest version wins. # Args: DEVICE_NAME MATCH_MODE (exact|substring) find_simulator() { local name="$1" local match_mode="${2:-exact}" xcrun simctl list devices available -j | python3 -c " -import json, sys +import json, sys, re data = json.load(sys.stdin) name, match_mode = sys.argv[1], sys.argv[2] candidates = [] for runtime, devices in data['devices'].items(): + m = re.search(r'iOS-(\d+)-(\d+)', runtime) + if not m or int(m.group(1)) < 26: + continue + version = (int(m.group(1)), int(m.group(2))) for d in devices: matched = (name == d['name'].strip()) if match_mode == 'exact' else (name in d['name']) if matched and d['isAvailable']: - candidates.append((runtime, d['udid'])) + candidates.append((version, d['udid'])) candidates.sort(key=lambda x: x[0]) if candidates: print(candidates[-1][1]) @@ -32,6 +43,18 @@ IPHONE_69_ID="$(find_simulator "iPhone 16 Pro Max" "exact")" IPAD_13_ID="$(find_simulator "iPad Pro 13-inch (M4)" "substring")" +# These devices are expected on an iOS 26+ runtime (guaranteed by the CI Xcode 26 +# image). Fail loudly if either is missing rather than silently capturing a +# partial set — or, on an older runtime, the pre-26 look. +missing=() +[ -z "$IPHONE_69_ID" ] && missing+=("iPhone 16 Pro Max") +[ -z "$IPAD_13_ID" ] && missing+=("iPad Pro 13-inch (M4)") +if [ ${#missing[@]} -gt 0 ]; then + echo "ERROR: No iOS 26+ simulator found for: ${missing[*]}." >&2 + echo "This script targets iOS 26 for the Liquid Glass styling; those sims ship with the CI Xcode 26 image (locally, add an iOS 26 device for each)." >&2 + exit 1 +fi + capture_screenshots() { local device_name="$1" local device_id="$2" @@ -65,6 +88,7 @@ capture_screenshots() { "${testing_args[@]}" \ -derivedDataPath "$DERIVED_DATA" \ -resultBundlePath "$result_bundle" \ + ${EXTRA_XCODEBUILD_ARGS[@]+"${EXTRA_XCODEBUILD_ARGS[@]}"} \ 2>&1 | tail -5 local attachment_dir="$OUTPUT_DIR/$output_subdir"