Step 3 · Verify signing and artifacts separately
Use one Fastfile to connect match, gym and pilot
From the project root, run bundle installand commit Gemfile.lock. The workflow below assumes your signing repository is initialized, your app already exists, and CI injects environment variables securely. It doesn’t create new signing assets.
Remote preflight · Check the toolchain first
xcode-select -p
xcodebuild -version
xcodebuild -showsdks
ruby --version
bundle --version
bundle exec fastlane --version
security find-identity -v -p codesigning
df -h "$HOME"
Set the signing repository URL in MATCH_GIT_URLand the decryption passphrase in MATCH_PASSWORD. For uploads, use a server-side API key. Set the key file path with ASC_KEY_PATH , and provide the key ID and issuer ID with ASC_KEY_IDandASC_ISSUER_ID . Store the key file as a CI secret and write it to disk at runtime; don’t commit it to the project repository.
Set IOS_APP_IDENTIFIER,IOS_TEAM_ID,IOS_WORKSPACE and IOS_SCHEME. Set the distribution type in the signing repository to match appstore . Verify the shared scheme before running the full pipeline.
fastlane/Fastfile · TestFlight pipeline for a single app
default_platform(:ios)
platform :ios do
desc "Archive a signed build and upload it to TestFlight"
lane :release do
setup_ci
api_key = app_store_connect_api_key(
key_id: ENV.fetch("ASC_KEY_ID"),
issuer_id: ENV.fetch("ASC_ISSUER_ID"),
key_filepath: ENV.fetch("ASC_KEY_PATH"),
in_house: false
)
match(
type: "appstore",
readonly: true,
git_url: ENV.fetch("MATCH_GIT_URL"),
app_identifier: ENV.fetch("IOS_APP_IDENTIFIER"),
team_id: ENV.fetch("IOS_TEAM_ID"),
api_key: api_key
)
gym(
workspace: ENV.fetch("IOS_WORKSPACE"),
scheme: ENV.fetch("IOS_SCHEME"),
configuration: "Release",
clean: true,
export_method: "app-store",
output_directory: "build/artifacts",
output_name: "release.ipa"
)
pilot(
api_key: api_key,
ipa: "build/artifacts/release.ipa",
skip_waiting_for_build_processing: true
)
end
end
Run and verify · CI injects the environment variables
bundle exec fastlane ios release
find build/artifacts -maxdepth 1 -type f -print
A successful upload doesn’t mean processing is complete.This example skips the post-upload processing wait. Check the build’s processing status in your distribution dashboard, and use a unique build number for every upload.readonly: true prevents CI from modifying the signing repository. If a certificate or provisioning profile expires, update it in a controlled environment and rerun the pipeline.