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_dispatch your native workflow with sha, version, ios, android, plus a report URL and token
  • Receive step reports and GitHub workflow_run events
  • 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 bundleRelease with 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.