diff --git a/codemagic.yaml b/codemagic.yaml new file mode 100644 index 0000000..4214d36 --- /dev/null +++ b/codemagic.yaml @@ -0,0 +1,74 @@ +# 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. + +workflows: + ios-testflight: + name: iOS TestFlight + instance_type: mac_mini_m2 + max_build_duration: 60 + working_directory: frontend + integrations: + # Replace with the name of the App Store Connect integration configured + # in the Codemagic UI. + app_store_connect: OOTT App Store Connect + 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 + app-store-connect fetch-signing-files "$BUNDLE_ID" \ + --type IOS_APP_STORE \ + --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. + BUILD_NUMBER=$(($(app-store-connect get-latest-testflight-build-number "$APP_STORE_APP_ID") + 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 diff --git a/frontend/ios/Runner.xcodeproj/project.pbxproj b/frontend/ios/Runner.xcodeproj/project.pbxproj index dc26eb9..ade41ec 100644 --- a/frontend/ios/Runner.xcodeproj/project.pbxproj +++ b/frontend/ios/Runner.xcodeproj/project.pbxproj @@ -368,7 +368,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend; + PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -384,7 +384,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app.RunnerTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -401,7 +401,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app.RunnerTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -416,7 +416,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app.RunnerTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -547,7 +547,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend; + PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -569,7 +569,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend; + PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/frontend/ios/Runner/Info.plist b/frontend/ios/Runner/Info.plist index 848830a..b110363 100644 --- a/frontend/ios/Runner/Info.plist +++ b/frontend/ios/Runner/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Frontend + OOTT CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier