From an empty developer account to the store, on a button.
Apple Developer and Google Play Console accounts set up for clients, and push-button release pipelines for the apps that ship through them: four apps live on the App Store and Google Play.
- 4Apps live in the stores
- 2Stores per pipeline
- 0Signing files in any repo
- 1Human button before live
Accounts, signing and pipelines
I set up the developer accounts in the clients' names, then made shipping boring: a push to a release branch builds, signs and uploads, and the last step to go live is always a person.
- Apple Developer and Google Play Console organisation accounts for clients
- App Store Connect records, store listings, screenshots and review submissions
- Signing with API keys, provisioning created on demand
- GitHub Actions pipelines for TestFlight, App Store, Play internal and Play production
- Shipped: Bsheel, iEvents, iEvents Vendor and Hader
One release
Two branches, both stores at once. Nothing on main ever publishes.
- 1Merge into deploy/test or deploy/live
- 2Check who pushed
- 3Check signing secrets
- 4Refuse a version Apple would reject
- 5Build number from the run
- 6Build, sign, upload
- 7TestFlight and Play internal, or review and a 20% draft
- 8A person presses release
The apps
Store screenshots from the apps these pipelines ship.

Bsheel, App Store and Google Play 
iEvents, App Store and Google Play 
iEvents Vendor, App Store and Google Play
What it does
- 01
Accounts in the client's name
Organisation accounts on both stores so the client owns the listing, the reviews and the revenue from day one.
- 02
Bsheel: two branches, two destinations
A push to publish-test sends a TestFlight build, a push to publish-store submits to Apple for review, both through the same signed release script.
- 03
Hader: both stores in one run
deploy/test sends to TestFlight internal and Play internal testing, deploy/live to App Store review and a Play production draft at a 20% staged rollout.
- 04
Build numbers that never collide
Taken from the CI run number, never from a hand-edited file, because both stores reject a duplicate.
- 05
Store listings as code
fastlane metadata and screenshots in the repo, with a metadata-only lane to update a listing without a build.
- 06
Guard rails
The job checks who pushed, that every secret exists before it starts, and that the version is one Apple will accept.
Stack
- CI
- GitHub Actions on macOS and Ubuntu runners.
- Release
- fastlane lanes for beta, release and metadata, plus a shared signed release script.
- Stores
- App Store Connect API, TestFlight, Google Play Console API.
- Apps
- Flutter, built for iOS and Android.