Documentation
What happens during a build
The exact GitHub Actions jobs CapWrap starts, how secrets arrive, and how status returns to the dashboard.
This page is the technical picture. You do not need it to tap Ship — it is here so you can debug with a developer, or understand GitHub invoices.
Who runs what
CapWrap’s servers:
- Store Apple / Google / env secrets (not in the Vite app, not in Git)
- Create a short-lived run token when you confirm
- Call GitHub’s API to
workflow_dispatchyour native workflow withsha,version,ios,android, plus a report URL and token - Receive step reports and GitHub
workflow_runevents - Advance “last native SHA” only after a successful native upload
GitHub Actions (on your repo):
- Checks out that SHA
- Builds and signs
- Uploads to Apple / Google with Fastlane
Job graph
The workflow is concurrent per repository (a second native ship waits; it does not cancel the first).
1. prepare (Linux)
- Check out the SHA you picked
- Overlay
.capwrap/helpers from the workflow branch (so old SHAs still get new scripts) - Install npm / pnpm / yarn / bun
- Fetch secrets from CapWrap
- Build the web app until there is a folder containing
index.html(Vite SPA, static export, etc.). Some SSR setups are patched for that job only npx cap sync- Upload
ios/,android/, web build, and helpers as an artifact
2. ios (macOS, if you ticked TestFlight)
- Check out the SHA, unpack iOS, install JS deps (CocoaPods needs
node_modules/@capacitor/ios), CocoaPods, set encryption plist flag - Fastlane lane
capwrap_internal→ signed IPA → App Store Connect / TestFlight - Build number: from TestFlight if possible, else the GitHub run number
3. android (Linux, if you ticked Play)
- Check out the SHA, unpack Android, install JS deps (Gradle needs
node_modules/@capacitor/android) - JDK 21, Android SDK
- Decode the upload keystore
- Bump
versionCode,gradlew bundleReleasewith injected signing - Fastlane → Play internal track
4. finish
Mark the CapWrap run succeeded or failed.
Each interesting step POSTs to CapWrap (checkout, install, web_build, cap_sync, ios_archive, ios_upload, android_bundle, android_upload, ready). The dashboard polls GitHub as a backup.
Secrets on the runner
fetch-secrets.sh uses the report token to download:
- App Store Connect API key, team, distribution cert
- Play JSON + keystore passwords
- Frontend env map
They are masked in logs where possible. They are not saved as GitHub repository secrets by CapWrap. When the job ends, they are gone with the runner.
What Fastlane does not do
It skips store listing metadata, screenshots, and review submission. Binary upload ≠ listing push.
Minutes and cost
macOS minutes are the expensive part. A failed iOS archive still consumes minutes. Watch the Actions log rather than tapping Ship repeatedly.