# Codemagic CI/CD configuration for OOTT. # # Builds the Flutter iOS app on a cloud macOS machine and publishes it to # TestFlight. No local Mac is required. # # Triggered automatically by the `vX.Y.Z` git tags that `release.sh` pushes, # so cutting a release also ships a new TestFlight build. Can also be run # on demand via the "Run build" button in the Codemagic UI. # # SECRETS: none live in this repo. The App Store Connect API key (.p8, Key ID, # Issuer ID) is stored in Codemagic's encrypted credential store and referenced # here only by integration name. Signing certificates and provisioning profiles # are fetched on the build machine at build time and discarded with it. # # One-time setup required in the Codemagic UI before the first build: # 1. Add an App Store Connect integration (upload the .p8, Key ID, Issuer ID) # and put its name in `integrations.app_store_connect` below. # 2. Create an environment variable group named `appstore_connect` containing # APP_STORE_APP_ID = the numeric Apple ID of the app record in # App Store Connect. # 3. Make sure GitHub actually delivers events to Codemagic, or the `tag` # trigger below never fires (the tag push is pushed into the void and no # build starts). The `triggering` block alone is NOT enough. Either: # - install the Codemagic CI/CD GitHub App and grant it this repo # (https://github.com/settings/installations), or # - add the app's webhook URL (from the Codemagic app's Webhooks page) # to the repo: Settings -> Webhooks, content type `application/json`, # "push" events (tag pushes arrive as push events). # Verify a real tag push shows up under the Codemagic app's Webhooks # deliveries; an empty `GET /repos///hooks` plus no GitHub # App install means nothing is listening. workflows: ios-testflight: name: iOS TestFlight instance_type: mac_mini_m2 max_build_duration: 60 working_directory: frontend integrations: # Name of the App Store Connect integration configured in the Codemagic UI # (Settings -> Integrations -> Developer Portal). app_store_connect: Codemagic environment: flutter: stable xcode: latest cocoapods: default groups: - appstore_connect # provides APP_STORE_APP_ID (not a secret) vars: BUNDLE_ID: "net.oott-security.app" # not secret; ships inside every app triggering: events: - tag tag_patterns: - pattern: "v*" # matches the vX.Y.Z tags release.sh pushes include: true scripts: - name: Set up automatic code signing script: | keychain initialize # Reuse a persistent private key (CERTIFICATE_PRIVATE_KEY secret) so the # distribution certificate is created/reused with a key Codemagic owns. # Without this, each ephemeral build VM loses the key and signing fails. app-store-connect fetch-signing-files "$BUNDLE_ID" \ --type IOS_APP_STORE \ --certificate-key @env:CERTIFICATE_PRIVATE_KEY \ --create keychain add-certificates xcode-project use-profiles - name: Get Flutter packages script: flutter pub get - name: Run frontend tests script: flutter test - name: Build IPA script: | # Each TestFlight upload needs a unique, increasing build number. # On the very first build there are no TestFlight builds yet, so the # lookup fails - fall back to 0 so the first build number is 1. LATEST_BUILD_NUMBER=$(app-store-connect get-latest-testflight-build-number "$APP_STORE_APP_ID" 2>/dev/null || echo 0) BUILD_NUMBER=$((LATEST_BUILD_NUMBER + 1)) flutter build ipa --release \ --build-number=$BUILD_NUMBER \ --export-options-plist=/Users/builder/export_options.plist artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log publishing: app_store_connect: auth: integration submit_to_testflight: true beta_groups: - Internal Testers