chore(screenshots): Commit only English Play Store screenshots

Only en-US screenshots are tracked from now on. The other 67 locales are
generated on demand and gitignored, which drops 35 PNGs and roughly 5 MB from
the repository and stops every screenshot refresh from churning binaries in
five languages nobody reviews.

Play Store still gets the full 68 locales. supply only uploads what is present
under fastlane/metadata/android/<locale>/images/phoneScreenshots/ and retains
whatever was last pushed for locales absent from an upload, so localization is
maintained by an occasional manual regen plus screenshots_only rather than by
every PR.

PlayStoreLocales.kt had been committed since February holding a truncated
four-locale batch slice, left behind when a run was killed before its EXIT trap
restored the file. The next run then copied that slice over its own backup and
faithfully restored the corruption, which is why the remnant survived six
months. It is replaced with a documented en-US placeholder, the generator no
longer emits an annotation nothing references, and the script now refuses to
start when a stale .bak is present instead of clobbering the only good copy.

The refresh runbook is corrected as well: it ended with a checkout that restores
tracked files from the index, which would have reverted the freshly rendered
English screenshots while the store received them, and its upload step is now
gated so a failed upload leaves them staged for a retry rather than committed as
though deployed.
This commit is contained in:
darken
2026-08-25 20:08:48 +02:00
committed by Matthias Urhahn
parent c49cd62b2a
commit a427fcbf4e
40 changed files with 31 additions and 32 deletions
+16 -5
View File
@@ -32,13 +32,15 @@ ScreenshotContent.kt (mock data + composables)
|------|---------|
| `app/src/debug/java/.../screenshots/ScreenshotContent.kt` | Mock data composables (7 exist; `HomescreenWidgetContent` has an IDE preview only and is **not** in the Play Store pipeline) |
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreScreenshots.kt` | `@PreviewTest` functions (currently: `DashboardLight`, `DashboardDark`, `CasePopUp`, `DeviceProfiles`, `AddProfile`, `DeviceSettingsReactions`, `WidgetConfiguration`) |
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreLocales.kt` | Multi-preview annotations (auto-generated by batch script) |
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreLocales.kt` | Multi-preview annotations. The committed content is an en-US placeholder, not meaningful data — `generate_screenshots.sh` rewrites it per batch and restores it from a `.bak` on exit. A run killed hard leaves that `.bak` behind, so the script now refuses to start until it is restored by hand |
| `fastlane/generate_screenshots.sh` | Batched generation; locale list (`ALL_LOCALES`) and `BATCH_SIZE` are defined inside the script |
| `fastlane/copy_screenshots.sh` | Copies rendered PNGs into fastlane structure |
## Commit policy
Only the 6 smoke locales (en-US, de-DE, ja-JP, ar, zh-CN, pt-BR) have `phoneScreenshots/*.png` checked into the repo. Non-smoke locales are excluded by `.gitignore`. This mirrors permission-pilot and keeps repo size small (~7 MB vs ~67 MB for the full 68 locales).
Only `en-US` has `phoneScreenshots/*.png` checked into the repo — 7 PNGs, ~1 MB tracked. Every other locale is excluded by `.gitignore`.
`--smoke` still *renders* 6 locales (en-US, de-DE, ja-JP, ar, zh-CN, pt-BR), but only en-US is committed. The other five cover LTR, RTL and CJK layout so a render that breaks on non-Latin script fails during generation, and the resulting PNGs sit in the working tree for manual inspection. Nothing compares them against a baseline, so this is render coverage plus eyeballing, not regression checking.
Play Store's `supply` only uploads what's present in `fastlane/metadata/android/<locale>/images/phoneScreenshots/`. For locales not in the upload, Play Store retains whatever was last pushed. So full localization on Play Store is maintained by an **occasional manual** full regen + `:screenshots_only` upload — not by every PR.
@@ -90,11 +92,20 @@ Periodic, manual operation — not per-PR:
```bash
./fastlane/generate_screenshots.sh # full, ~30 min, 476 PNGs (68 locales x 7)
./fastlane/copy_screenshots.sh --clean
bundle exec fastlane screenshots_only # uploads all 68 locales to Play Store
git checkout -- fastlane/metadata/android/ # discard non-smoke changes (gitignored anyway)
git add fastlane/metadata/android/en-US/images/phoneScreenshots/
if bundle exec fastlane screenshots_only; then
git checkout -- fastlane/metadata/android/ &&
git commit --only -m "chore(screenshots): Refresh Play Store screenshots" -- \
fastlane/metadata/android/en-US/images/phoneScreenshots/
else
git checkout -- fastlane/metadata/android/
echo "Upload failed; the refreshed en-US screenshots remain staged for retry."
fi
```
The `.gitignore` rule keeps non-smoke output unstaged automatically, so only the smoke locales' refreshed PNGs would show up as modifications and can be committed.
The `git add` has to happen before the upload. The final `git checkout` restores every tracked file under that path **from the index**, so staging the refreshed English set is precisely what makes it survive the checkout — skip the `git add` and the checkout silently reverts the refresh while the store still receives the new images.
Restoring is the checkout's job otherwise: `screenshots_only` runs `remove_unsupported_languages.sh`, which deletes 9 tracked locale directories (es-AR, sc-IT, sq-AL, uz, kmr-TR, ur-IN, zu, si-LK, nb) from the working tree before uploading — 35 tracked files, a subset of the 309 tracked non-screenshot metadata files under that path, all of them put back by the checkout. It does **not** touch the regenerated non-English PNGs: those are untracked and ignored, so they stay on disk and never show up in `git status`. Because the checkout discards any uncommitted metadata text edits too, run this refresh only with an otherwise-clean metadata tree. The final commit is path-limited on purpose, so an unrelated staged change can't ride along, and it is gated on `screenshots_only` succeeding rather than merely sequenced after it: if the upload fails, the refreshed English files stay staged for a retry instead of being committed as though they were deployed. The deleted locale directories are restored on either path.
## Technical Notes
+1 -6
View File
@@ -17,16 +17,11 @@
.kotlin
# Screenshot test reference images (ephemeral, regenerated on demand)
app/src/screenshotTest*/reference/
# Play Store phone screenshots: commit only the 6 smoke locales (mirrors permission-pilot).
# Play Store phone screenshots: commit only en-US.
# Full localization is uploaded by occasional manual regen + screenshots_only;
# Play Store retains previously-uploaded screenshots for locales not pushed.
fastlane/metadata/android/*/images/phoneScreenshots/*.png
!fastlane/metadata/android/en-US/images/phoneScreenshots/*.png
!fastlane/metadata/android/de-DE/images/phoneScreenshots/*.png
!fastlane/metadata/android/ja-JP/images/phoneScreenshots/*.png
!fastlane/metadata/android/ar/images/phoneScreenshots/*.png
!fastlane/metadata/android/zh-CN/images/phoneScreenshots/*.png
!fastlane/metadata/android/pt-BR/images/phoneScreenshots/*.png
.codex
protocol-research/
_site/
@@ -4,26 +4,17 @@ import android.content.res.Configuration
import androidx.compose.ui.tooling.preview.Preview
/**
* Multi-preview annotation generating one preview per Play Store-supported locale (light mode).
* Each [name] is the fastlane metadata directory name for direct use in the copy script.
* Placeholder locale set. `fastlane/generate_screenshots.sh` rewrites this file per batch and
* restores it afterwards, so the committed content only decides what a bare
* `./gradlew updateGplayDebugScreenshotTest` renders.
*
* [name] is the fastlane metadata directory the copy script sorts the output into.
*/
@Preview(locale = "en", name = "en-US", device = DS)
@Preview(locale = "af", name = "af", device = DS)
@Preview(locale = "am", name = "am", device = DS)
@Preview(locale = "ar", name = "ar", device = DS)
annotation class PlayStoreLocales
/**
* Same locales but with night mode enabled for dark theme screenshots.
*/
@Preview(locale = "en", name = "en-US", device = DS, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(locale = "af", name = "af", device = DS, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(locale = "am", name = "am", device = DS, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(locale = "ar", name = "ar", device = DS, uiMode = Configuration.UI_MODE_NIGHT_YES)
annotation class PlayStoreLocalesDark
/**
* Smoke test subset for fast iteration (6 locales covering LTR, RTL, CJK).
*/
@Preview(locale = "en", name = "en-US", device = DS)
annotation class PlayStoreLocalesSmoke
+9 -7
View File
@@ -122,6 +122,15 @@ echo "=== Localized Screenshot Generation ==="
echo "Locales: $TOTAL | Batch size: $BATCH_SIZE | Batches: $NUM_BATCHES"
echo ""
# A leftover .bak means a previous run died before its trap restored the file: the real source is
# in the .bak and copying over it here would destroy the only good copy.
if [[ -e "$LOCALES_FILE.bak" ]]; then
echo "ERROR: Stale backup found: $LOCALES_FILE.bak"
echo "A previous run was interrupted. Restore it first:"
echo " mv \"$LOCALES_FILE.bak\" \"$LOCALES_FILE\""
exit 1
fi
# Back up the original file
cp "$LOCALES_FILE" "$LOCALES_FILE.bak"
trap 'mv "$LOCALES_FILE.bak" "$LOCALES_FILE"; echo "Restored original PlayStoreLocales.kt"' EXIT
@@ -166,13 +175,6 @@ HEADER
done
echo "annotation class PlayStoreLocalesDark" >> "$file"
echo "" >> "$file"
# Smoke annotation (single entry placeholder)
echo "/**" >> "$file"
echo " * Smoke test subset for fast iteration (6 locales covering LTR, RTL, CJK)." >> "$file"
echo " */" >> "$file"
echo "@Preview(locale = \"en\", name = \"en-US\", device = DS)" >> "$file"
echo "annotation class PlayStoreLocalesSmoke" >> "$file"
}
for (( batch=0; batch < NUM_BATCHES; batch++ )); do
Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB