Automating TestFlight Builds with CircleCI – Part 2
In Part 1, we set up two Fastlane commands:
bumpto increment the build number and
submit_to_testflightto upload the build to our TestFlight group
Let’s configure CircleCI to run these commands for us when new features are delivered to our master branch.
Initial CircleCI Setup
Let’s tell Circle CI that we want it to run some projects for us. Click on CircleCI’s Add Projects tab. Find your repository in the list and click
Set Up Project. Follow the initial setup steps on that page and then click
Bump the build number
config.yaml, add a new job to your job list:
bump-build: macos: xcode: "10.2.0" environment: # Silences warning from Fastlane - LC_ALL: "en_US.UTF-8" - LANG: "en_US.UTF-8" steps: - checkout # Install fastlane and its dependencies - run: name: install Brewfile command: brew bundle - run: name: Installing gem dependencies command: bundle install # Securely connect to GitHub - add_ssh_keys: fingerprints: - "SO:ME:FI:NG:ER:PR:IN:T" # Call the bump lane - run: name: Bump the build number and commit command: bundle exec fastlane bump
The interesting part is
add_ssh_keys. Deployment keys let CircleCI access your code. However, while you can set a service deployment key in CircleCI, it only gives read access. The
fastlane bump command needs write access to push the version bump commit to master. Therefore, we need to generate and register a user-deploy key with write access by following these instructions. Paste the key’s fingerprint here.
- That key should be added to the project repository’s settings in GitHub
- The fingerprint in this step should match.
Submit to TestFlight
Let’s add the job for submitting to TestFlight:
submit_to_testflight: macos: xcode: "10.2.0" environment: # Silences warning from Fastlane - LC_ALL: "en_US.UTF-8" - LANG: "en_US.UTF-8" steps: - checkout # Install fastlane and its dependencies - run: name: install Brewfile command: brew bundle - run: name: Installing gem dependencies command: bundle install # Securely connect to GitHub - add_ssh_keys: fingerprints: - "SO:ME:FI:NG:ER:PR:IN:T" # Call the submit lane - run: name: Deploy new build to TestFlight command: bundle exec fastlane submit_to_testflight
This looks very similar to the step for making the build. In fact, the only differences are:
- We install a different SSH key
- Our final run command is now
This SSH key is the one Circle CI will use to download your credentials from the repo that
fastlane match uses to store them. If you attempt to reuse your key from earlier, GitHub will reject it. Instead, you’ll need to do the same key generation process again, and add the fingerprint for the SSH key associated with the credentials repo here.
Build the workflow
Now that we’ve got two jobs, let’s put them together into a workflow:
#Defines work-flows for the jobs specified above workflows: version: 2 build-test-lint: jobs: - build-and-test: filters: tags: only: /.*/ - bump-build: requires: - build-and-test filters: branches: only: master tags: only: /.*/ - deploy-beta: requires: - build-and-test filters: branches: ignore: /.*/ tags: only: /^builds.*/
That’s a lot. Let’s look at each job in that workflow individually.
- build-and-test: filters: tags: only: /.*/
This builds and tests any commit to any branch. See CircleCI’s excellent guide on how to configure automated tests.
The filter here is odd. Why would we filter to a regex that matches everything? This is how CircleCI knows it should trigger this workflow for either a tag match or a branch match. It looks superfluous right now, but adding the “only run it for every tag” filter means we can specify “only run it for specific tags” in later, dependent jobs.
- bump-build: requires: - build-and-test filters: branches: only: master tags: only: /.*/
This runs our
fastlane bump job. This will only run on the master branch, and will run with any specified tag. And, it’ll only run after
build-and-test successfully completes.
Just like before, the “filter to only all of the tags” looks superfluous, but it’s not. Now that our parent task has started filtering for tags, if any job doesn’t specify a tag filter, then all tag filters will be ignored.
And now, the grand finale of CI config:
- deploy-to-testflight: requires: - build-and-test filters: branches: ignore: /.*/ tags: only: /^builds.*/
Finally, our deploy task ignores branches and only triggers if it sees a tag that starts with
builds. You can probably make the tag regex more specific, but this is good enough for me.
Both of these
filtersvalues are OR’d together. If we specified
branches: only: masterwith this filter tag, then it would run for every commit on master and also any commits that start with
builds. Ignoring the branch entirely and having
buildstags only added to master is the only way to achieve the desired effect.
Your automated process should now look like this:
Configure the CircleCI Environment
You’re still not done! There’s some state on your local machine that you need to go into CircleCI and add as environment variables. Specifically:
MATCH_PASSWORD– This is the password you use to decrypt your fastlane credentials.
FASTLANE_PASSWORD– This is the Apple ID password of the account you use to submit builds to Apple.
If the shared build account follows fastlane’s recommendation and doesn’t have two-factor authentication enabled, then you’re done. Otherwise, you’ll need these additional environment variables:
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD– This can be generated in Apple ID Settings, underneath Security > Generate Password.
FASTLANE_SESSION– A session token that’s sufficent for two-factor authentication. To generate, type the following command in the terminal, using the build account’s email address:
fastlane spaceauth -u firstname.lastname@example.org
FASTLANE_SESSIONexpires after a month. You will need to update this environment variable monthly in order to keep the build process automatic. Unfortunately, that’s the best fastlane can do.
Hope for the best
That’s it! Make your commits, get them reviewed and merged to master, and about 20-30 minutes later you should get a notification that you’ve got a new build to download from TestFlight.
If you’re anxiously watching the workflow process as this goes on, you should see each of the five jobs:
- Test your commit with
- Increment the build number with
bump-buildand tag the commit.
- Test the build tag commit with
bump-buildwith no effect on the tag commit.
- Deploy with