Since we originally built Eidolon – an auction bidding kiosk app – the project has largely remained in maintenance mode. Eidolon was one of the first projects that we used automated deploys for, and the deploy process has remained largely unchanged. I believe this stability of the deploy process is a testament to how well the automated deploys have gone.
This post is going to detail the mechanics of automated deploys for an enterprise-distributed iOS application, discuss lessons we learned and applied to other projects' deploy processes, and describe some of the changes we'd like to make. Our project is entirely open source, so you can check out any part of the code on your own or open an issue with questions.
It's one command on the terminal to deploy Eidolon:
- We run this command locally on a development machine that has the keys installed to sign a deploy.
- Our changelog is formatted in yaml, our script uses this strategically.
- Our deploy script modifies the project's Info.plist version and build number, as well as the changelog.
Let's dive in!
The first thing we do is verify that the version number we've been given is in the proper SemVer format.
We deploy using Hockey, so make sure that an environment variable with the Hockey API key is set.
We also want to verify that we have valid API keys for analytics, the Artsy API, and a few other services the app uses. This validation only makes sure the keys have been set to non-empty values. And we don't want to accidentally deploy uncommited changes, so we check the git status first.
Next we need to set the build number. These need to be unique, and we use the current date. This could be a problem if we need to deploy more than once in a day. It hasn't been a problem yet, though, since we rarely deploy.
We also want to set the Info.plist's version to the one specified when we run the
1 2 3 4
Okay, now it's time to generate markdown release notes from the changelog. Our changelog is in the following format:
1 2 3 4 5 6 7 8
We want to grab the
upcoming notes for the changelog, and then move them to the
releases section. Let's generate the notes first:
1 2 3
Updating the changelog is a little messy. I tried parsing the changelog as yaml, modifying it, and then writing it back as yaml, but kept running into trouble. Instead, I treat it as plain text. We open the changelog, split on
releases:, prepend the existing releases with a the generated release notes, and write the changelog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
At this point, we're ready to start the actual deploy process. First we need to download the provisioning profiles, which is only one step with Fastlane:
Next we build our app using
gym. We need to use the legacy build API, I can't remember why.
1 2 3 4 5
With our build finished, we upload to Hockey.
1 2 3 4
Okay, our build is deployed. Time to let the team know there's a new version available:
1 2 3 4 5 6 7 8 9
default_payloads needs to be empty I think, I can't remember why. Seems like "I can't remember why" is a common theme here...
Before committing the changes we've made to the changelog and Info.plist files, we need to clean any build artefacts. This includes the actual binary that was compiled, unit test coverage reports, and downloaded provisioning profiles.
Finally, we commit, tag the build, and push to GitHub. Fastlane's built-in commands to commit to git reject any changes except to Info.plist files, and we've modified the changelog, so I used
sh and used git directly.
1 2 3
And that's it! With one terminal command, we've done all the following:
- Verified version number format.
- Verified the local environment is set up to deploy.
- Verified API keys used by the app aren't empty.
- Incremented the build number and version.
- Updated the changelog.
- Built and signed the app.
- Uploaded the build to Hockey.
- Posted a notification to Slack.
- Tagged the release and pushed to GitHub.
Automating Eidolon deploys was one of the first automated deploys we built on Artsy's iOS team. Now, based on Eidolon's successful deploy process, all our iOS deploys are automated.
We've learned a few lessons.
First, running deploys locally is so 2015. Our more modern deploy processes run on continuous integration servers like Circle CI. This poses some problems around securing certificates necessary to deploy, maybe we'll cover that in a future blog post.
We deploy on CI based on pushes to a specific branch, and we run our deploy script only if the unit tests pass. This is a huge incentive to keep CI green.
On other iOS projects, we sometimes deploy more than once a day, so we use
Year.Month.Day.Hour as the build number format, which is unique enough to do one deploy per hour. This is good enough for now.
One thing I really wish I'd done when I set up automated deploys is to document things a little better. To be honest, that's part of the motivation to write this blog post (better late than never!).
Overall, automating deploys for Eidolon has been a huge win. The other night, we had an emergency at an auction: the Eidolon app was no longer working and we needed a new deploy.
Guess who’s got two thumbs and forgot that their enterprise distribution certificates expire in September.— Ash vs NSThread (@ashfurrow) October 8, 2016
From the time the team let me know about the problem to the time they had a fresh deploy with a new certificate, less than twenty minutes had passed. I issued one command and watched it do all the work for me. If I had to manually follow a set of arcane steps I hadn't done in a long time, our team might not have had the new build in time.