Become a master of automation with Fastlane

There are several reasons to start using automation in your application development process: running your tests, distributing your app internally or into the App Store, or setting up well-defined processes in your team. Whatever the reason, if you are a mobile developer you might want to consider using Fastlane.

iOS project automation

Automation is your best friend when working on a project. With a small investment of time you can get rid of all the operations you normally have to do manually. It saves you time, helps you maintain high quality standards and avoids human error when doing releases.
Here at Novoda we use automation to: run tests every time changes are pushed to the repository (ensuring we don't create regression bugs), build and distribute an artefact every night to our internal QA testers, and minimise human errors with signing certificates as part of our release process.

Fastlane is a command line tool, initially created by Felix Krause, and recently acquired by Google within the Fabric suite. It is currently the most popular solution for automation on iOS and they've recently rolled out support for Android too.
You can trigger Fastlane on your computer if you wish, or integrate it with popular CI solutions like Jenkins to trigger your jobs there.

Fastlane install requirements

To get started you need an up-to-date version of Ruby (at time of writing 2.4.0). You might have a problem installing Fastlane on Ruby 2.0 and below. To update, use your preferred Ruby version manager - RVM or RBENV - to get the last stable version of Ruby.

At this point you can install Fastlane using gem install fastlane -NV or Homebrew if you prefer brew cask install fastlane.

Now you have everything you need to start to automate all the things! 🍭

Fastlane project setup

You need to remember one command to do almost everything: fastlane.
The first time you run the command from your project directory it will ask you basic information about your project and your Apple Developer account. Everything is interactive and all the required configuration will be created. Don't worry if your Apple Developer account has multiple teams or it's protected with 2-step authentication, Fastlane can handle that.

A new directory is created for you with two different configuration files.

─── fastlane
    ├── Appfile
    └── Fastfile

The Fastlane folder contains all the configuration used by Fastlane. It's strongly recommended to include this folder in your VCS so that you can share it with everyone in your team. There are just two files at the moment, as you add more actions, other configuration files will be added.

The Appfile stores general information about your app that can be shared across all the different actions: the bundle identifier, your Apple Developer account and your Team ID.
The Fastfile is where you defined your lanes. It's the most important file of your configuration and where you are going to spend most of your time.

Fastfile is where you defined your lanes and it's the most important file of your configuration

Configuring Fastlane

By default Fastlane is already configured to drive some lanes (which means 'run some jobs' in their jargon). Now that you have the basic configuration, you can type fastlane again and you will see the list of possible lanes:

$ fastlane

Welcome to fastlane! Here's what your app is setup to do:  
+--------+-------------+----------------------------------------------------+
|                          Available lanes to run                           |
+--------+-------------+----------------------------------------------------+
| Number | Lane Name   | Description                                        |
+--------+-------------+----------------------------------------------------+
| 1      | ios test    | Runs all the tests                                 |
| 2      | ios beta    | Submit a new Beta Build to Apple TestFlight        |
|        |             | This will also make sure the profile is up to date |
| 3      | ios release | Deploy a new version to the App Store              |
| 0      | cancel      | No selection, exit fastlane!                       |
+--------+-------------+----------------------------------------------------+
Which number would you like run?  

If you already know the name of the lane you want to drive, you can append it to the Fastlane command. Let's say you want to run the tests in your app, type
fastlane ios test. If you don't have any Android projects in the same folder you can type fastlane test.

If you already have the relevant certificates installed on your machine you can run all the existing lanes, otherwise you need to set up match in order to run beta and release. We will look at this in more detail in a future blog post.

You can do almost everything using the command fastlane

Configure your first lane

The Fastfile contains the configuration of your lanes. 90% of the work is normally done in this file, so let's open it and take a closer look.
The Fastlane team help you here. The file is commented and you have all the information you need to understand what's going on.
For this blog post, I have reduced the Fastfile to the bare minimum with a single lane that will only execute the tests of your app.

fastlane_version "2.14.2"  
default_platform :ios

platform :ios do

  desc "Runs all the tests"
  lane :test do
    scan
  end

end

Starting from now, test will be the only lane available. A lane is composed of a list of sequential actions. In this case, we are only using the scan action, which is the recommended way to run tests. Actions can be configured and you can see the list of possible arguments directly from Fastlane: fastlane action scan

Scan can be configured with several options. By default, you don't need to specify anything, as Fastlane infers most of the information for you. When you're ready to specify your own options, the easiest way is to define them directly inside the lane where you use the action. For example:

desc "Runs all the tests"  
  lane :test do
    scan(
      scheme: 'RandMTests',
      clean: true
    )
  end

We're now using scan with a well-defined scheme and we're forcing the tool to clean the project before building it. You can find all the keys for your configuration dictionary in the first column of the documentation of the action, as seen above.

Check the documentation of an action using fastlane action #{actionName}

Fastlane configuration tips

If you want to set up a default value for your action, you can define an environment variable. There are different ways to setup an environment variable, and some people do it directly inside the Fastfile. I prefer to create an .env file to define them, as the separation makes your configuration more readable.

SCAN_SCHEME='RandMTests'  
SCAN_CLEAN=true  

After you have declared the default values in your .env, you can now remove the values from the configuration for scan in the Fastfile

desc "Runs all the tests"  
  lane :test do
    scan
  end

As a rule of thumb, I always configure my actions in the .env file. I pass options directly on the action only when necessary, for example when I want to use the same action in different lanes with different options.

Chaining actions

In a real world scenario, you’ll want to add more actions into the same lane, which is trivial using Fastlane.

All the output parameters of an action are available in the next actions

gym is the action to build and create an IPA of your app. This is maintained by the Fastlane team and it’s the recommended solution to build your project. testflight is the action that will upload the IPA file for testing.

If you run gym you don't need to manually tell testflight the path of your IPA as this is automatically done for you by Fastlane. Cool, isn't it?

When you create your lanes you don't have to set up every required option/parameter as some previous action might have set up those values for you.

You can see all the available actions in Fastlane using fastlane actions. There are several and you can do a lot of cool advanced things by chaining them, for example:

  1. Generate localised screenshot of your app with snapshot
  2. Add device frames to these screenshots with frameit
  3. Create an ipa of your app with gym
  4. Send your ipa and the screenshot to iTunes with deliver

You can even go more advanced and have an entire release workflow that executes your tests, updates the build number of your app, commits the changes and creates a Git tag for you. Fastlane is very flexible, you just have to configure the actions already available.

Configuration Example

You already have all the information that you need, but here’s an example from a recent Novoda project for inspiration:

fastlane_version "2.14.2"  
default_platform :ios

platform :ios do  
  desc "Runs all the tests"
  lane :test do
    scan
  end

  desc "Runs all the UI tests"
  lane :ui_tests do
    scan(scheme: 'UITests')
  end

  desc "Build and send the release to Crashlytics for internal testing"
  lane :release_dev do
    ensure_git_status_clean
    match(type: 'development')
    increment_build_number
    increment_version_number
    commit_version_bump
    custom_overlay
    gym(configuration: 'Debug')
    crashlytics(notes: release_notes)
    reset_git_repo
  end

  desc "Test, Build and send a release to Testflight"
  lane :release_testflight do
    gym(configuration: 'Release')
    testflight
  end

  desc "Generate Unit Test Code Coverage" 
  lane :code_coverage do 
    scan
    xcov(scheme: MyScheme, only_project_targets: true)
  end

  desc "Update the version number for a new sprint"
  lane :new_sprint do
    ensure_git_status_clean
    get_version_number
    current_version = lane_context[SharedValues::VERSION_NUMBER]
    version_array = current_version.split(".").map(&:to_i)

    new_sprint_number = version_array[1] + 1

    version_array[1] = new_sprint_number
    version_array[2] = 0

    new_version = version_array.join(".")
    increment_version_number(
      version_number: new_version
    )
    commit_version_bump
  end

  desc "Install developer certificates and provisioning profiles"
  lane :install_certificates do
    match(type: 'development')
  end

  desc "Generate a custom icon overlay"
  private_lane :custom_overlay do
    git_commit = last_git_commit[:abbreviated_commit_hash]
    get_version_number
    version_number = lane_context[SharedValues::VERSION_NUMBER]
    badge(
     shield: "#{version_number}-#{git_commit}-blue",
     alpha: true
    )
  end

  desc "Generate release notes"
  private_lane :release_notes do
    get_version_number
    changelog = changelog_from_git_commits
    version_number = lane_context[SharedValues::VERSION_NUMBER]
    "Release notes #{version_number} Automatic build (Last 5 PR):\n#{changelog}"
  end
end  

One of my favourite actions in this project is release_dev, because it:

  1. Ensures the local Git repository is clean
  2. Installs or updates certificates
  3. Increments build and version numbers
  4. Commits the changes
  5. Creates a custom overlay of the app icon with the version number and the last git commit hash
  6. Builds and archives
  7. Upload the app to Crashlytics and shares it with the beta users
  8. Cleans the repo (we don't want to keep the changed icons)

Can you imagine having to do all these steps each day to send the build to your QA team?

You can always have a look at the collection of examples maintained in the Fastlane repo.

Master of Fastlane

You are now ready to start automating your tasks using Fastlane. There are more topics to discuss and no doubt you'll discover even more advanced uses of the tool as you become more familiar with it. If you want to discuss Fastlane or have a feature you want me to explain in another blog post then get in touch @pepito. There are recommended best practices, which I may go into further in a future blog post. For now, my advice is to open your terminal and start automating!

About Novoda

We plan, design, and develop the world’s most desirable software products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.

Let’s get in contact