This document describes the end-to-end release process for Scan4D (wisescan-ios). The process uses release-please for versioning/changelog and Fastlane for TestFlight distribution.
Finalize Code → Merge release-please PR → Pull Tag Locally → Fastlane Build & Upload
-
Install Fastlane (via Bundler):
cd wisescan-ios bundle install -
App Store Connect API Key — required for Fastlane to upload to TestFlight without interactive login:
- Go to App Store Connect → Users and Access → Integrations → App Store Connect API
- Create a new key with App Manager role
- Download the
.p8file (you only get one chance) - Set these environment variables (e.g. in
~/.zshrcor a.envfile):export APP_STORE_CONNECT_API_KEY_KEY_ID="XXXXXXXXXX" export APP_STORE_CONNECT_API_KEY_ISSUER_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" export APP_STORE_CONNECT_API_KEY_KEY="$(base64 < /path/to/AuthKey_XXXXXXXXXX.p8)"
-
Xcode Signing — ensure automatic signing is configured with the correct team (
24D5JLAEA3) and that you have a valid App Store distribution certificate.
Ensure all features and fixes for this release are merged into main using Conventional Commits format:
feat: add new scan export option
fix: correct mesh rotation on older devices
chore: update dependencies
Note: Only
feat:andfix:commits generate changelog entries.chore:,docs:,ci:etc. are excluded from the changelog.
After pushing to main, the release-please GitHub Action automatically creates (or updates) a release PR titled something like:
chore(main): release 0.2.0
This PR contains:
- Updated
CHANGELOG.mdwith all new entries - Updated
.release-please-manifest.jsonwith the new version - Updated
MARKETING_VERSIONinwisescan-ios.xcodeproj/project.pbxproj— release-please'sextra-filesconfig bumps it via the/* x-release-please-version */annotation on the app target, so the app'sCFBundleShortVersionString(shown in Settings) matches the release version once merged
Review the changelog, then merge the PR. This triggers release-please to:
- Create a git tag (e.g.
v0.2.0) - Create a GitHub Release with the changelog
git pull origin main --tagsVerify the tag exists:
git describe --tags
# Should output: v0.2.0 (or similar)Note: The app version (
CFBundleShortVersionString) is derived fromMARKETING_VERSION, which release-please already bumped in the project file when you merged the release PR (step 2) — there is no build-time git/version injection (an oldergit describe --tagsArchive build phase is disabled). Pulling the tag here just syncs your local repo with the GitHub Release.
bundle exec fastlane betaThis single command:
- Authenticates with App Store Connect (via API key)
- Auto-increments the build number (fetches latest from TestFlight + 1)
- Fetches the Apple Distribution certificate + App Store provisioning profile via the API key (
get_certificates+get_provisioning_profile) and signs the export manually — so releasing needs no interactive Xcode account login. (The API key must have App Manager or Admin role to manage signing assets.) - Archives the app (using
MARKETING_VERSIONfrom the merged release PR; the build number is the auto-incrementedCURRENT_PROJECT_VERSION) - Uploads the
.ipato TestFlight - Sets the beta feedback email to
arenaxr@andrew.cmu.edu
After the build finishes processing on App Store Connect (~10-20 min):
- Go to App Store Connect → TestFlight
- Add release notes for testers
- Enable the build for your test groups
If this release is going to production (App Store), ensure the following are updated before submitting for review:
- Automated Screenshots: Run
bundle exec fastlane snapshotto automatically capture updated UI screenshots for the App Store using your UI tests. - App Store Listing: Update "What's New" and Promotional Text. Ensure your newly generated screenshots accurately reflect significant UI changes.
- Privacy Labels: If new SDKs (like Meta Wearables DAT) or tracking features were added, update the App Privacy section in App Store Connect to declare new data types (e.g., Bluetooth, Local Network, Camera).
- Privacy Policy Document: Ensure any external hosted privacy policies correctly reflect new data usage, especially regarding third-party wearables or AR features.
| Step | Command / Action | What Happens |
|---|---|---|
| Finalize | Merge feature/fix PRs to main |
Code is ready |
| Version | Merge the release-please PR | Tag + GitHub Release created |
| Sync | git pull origin main --tags |
Local repo has the new tag |
| Ship | bundle exec fastlane beta |
Archive → TestFlight upload |
| Distribute | App Store Connect UI | Enable build for testers |
| App Store | App Store Connect UI | Update metadata, privacy labels, and submit |
The displayed version is MARKETING_VERSION from the project file, bumped by release-please on the release PR via the /* x-release-please-version */ annotation on the app target's MARKETING_VERSION lines. If it's stale, confirm the release PR was merged and that the annotation is still present.
Fastlane auto-increments from the latest TestFlight build number. If you get a conflict, check App Store Connect for the current highest build number.
Ensure the API key environment variables are set:
echo $APP_STORE_CONNECT_API_KEY_KEY_ID # Should not be emptyThe beta_feedback_email in fastlane/Fastfile controls where TestFlight "Send Beta Feedback" reports go. Update this email as needed — this is the primary reason Fastlane is used in this project.