Automate your library releases with Fastlane

Today we’ll look into automating a CocoaPods library releases with fastlane. This post is part of a small series about automating these type of tasks. On upcoming posts, we’ll look into private Pods and automating releases from a CI service.

Let’s take a look at the manual release process of a CocoaPods library. If you need more information on how CocoaPods library releases are set up, I suggest you take a look at CocoaPods Trunk, the Authentication and API service provided for releasing new versions of your library.

The manual steps we are going to automate are:

This process is particularly useful when maintaining multiple libraries and it will help you focus on growing your libraries, shipping features instead of spending time on manual releases.

Setting up fastlane

You can take a look at fastlane’s installation guide if you’re new to it. Check the section named Use a Gem since we’ll be using bundle.

We’ll start by creating a file named Gemfile on the root of your project where we will list our dependencies:

source "https://rubygems.org"

gem "cocoapods"
gem "fastlane"

If you don’t have fastlane set up on your machine, run bundle install

Next, we’ll run bundle exec fastlane init, select manual setup and press enter until it’s finished.

The previous step generates a fastlane folder with our Fastfile inside.

Let’s start working on our Fastfile, here we’ll define our lanes and steps needed to release an update.

Below we can see the default Fastfile content.

default_platform(:ios)

platform :ios do
  desc "Description of what the lane does"
  lane :custom_lane do
    # add actions here: https://docs.fastlane.tools/actions
  end
end

We’ll rename custom_lane to release. Here’s the list of fastlane actions that we’ll use:

Each of these functions take parameters which give us flexibility when building our release process. Let’s edit our Fastfile with an initial release approach.

default_platform(:ios)
podspec_name = "MyPod.podspec" # Don’t forget to update the podspec_name to the name of your podspec file.

platform :ios do
    desc "Releases a new version automatically"
    lane :release
    pod_lib_lint
    version = version_bump_podspec(path: podspec_name)
    git_add(path: podspec_name)
    git_commit(path: [podspec_name],
               message: "#{version} release")
    add_git_tag(tag: "#{version}")
    push_to_git_remote
    pod_push
  end

We now reduced multiple manual steps to one single fastlane lane. The release lane delivers a patch update 0.0.X to the public CocoaPods specs repo. Let’s add a bit more flexibility for different bump types (major, minor and patch). Let’s extract the functionality and create new lanes for each bump type.

default_platform(:ios)
podspec_name = "MyPod.podspec"

platform :ios do

  desc "Release a new version with a patch bump_type"
  lane :patch do
    release("patch") # we could use __method__.to_s instead of duplicating the name
  end

  desc "Release a new version with a minor bump_type"
  lane :minor do
    release("minor")
  end

  desc "Release a new version with a major bump_type"
  lane :major do
    release("major")
  end

  def release(type)
    pod_lib_lint
    version = version_bump_podspec(path: podspec_name,
                                   bump_type: type)
    git_add(path: podspec_name)
    git_commit(path: [podspec_name],
               message: "#{version} release")
    add_git_tag(tag: "#{version}")
    push_to_git_remote
    pod_push
  end
end

That looks a lot better. Now we can call bundle exec fastlane (patch | minor | major) to release the new version of the library automatically once we finished committing our fixes or new features 🎉!

Thanks for reading! Stay tuned for the next post on releasing a library from a CI service.