/ iOS

Managing Version Numbers with Fastlane

In this post I will describe how I use fastlane to manage my iOS and macOS version numbers for my releases.

There are many ways to deal with versioning, but I prefer to define them manually loosely following a semver model.

If you're not familiar, that means:

  • Major versions for large/breaking changes
  • Minor version for new features
  • Patch for bug fixes

You can of course set a version number in Xcode, but this only works for one target at a time, and if you have any Extension targets (for things like Push Notifications) then they need to be set to the same version.

Setting a version number in Xcode is easy, but you need to keep it in sync with extensions.

Instead, I like to set it with fastlane when doing a release.

Bumping the Version Manually

If you just want to increment one of the version components you can do something like this:

%w{major minor patch}.each do |part|
  lane "bump_#{part}".to_sym do
    increment_version_number(bump_type: part)
  end
end

This is dynamically defining 3 new lanes that I can invoke from the CLI or from other lanes in my Fastfile:

bump_major
bump_minor
bump_patch

This leans on the builtin action to increment the version number from Fastlane.

To invoke this from the command line I can run:

bin/fastlane bump_patch

And I can do this once and be sure that both targets have the new version.

Prompting for the Version Number

Another approach I've taken is to prompt for the marketing version number when doing a release.

Again we're leaning on builtin fastlane actions here, which make it easy:

private_lane :prompt_for_marketing_version do |options|
  marketing_version = get_version_number
  new_version = UI.input("What marketing version? <enter to keep it at #{marketing_version}>")
  unless new_version.strip == ""
    increment_version_number(version_number: new_version)
    UI.message("Version number set to #{new_version}")
    marketing_version = new_version
  end
end

I'll call this in my release lane:

I can press enter to skip it, or type a new number and it will set the target at that version.

Committing the Version Change and Tagging the Commit

After the release it is important to note only commit the version change, but tag the commit in Git so that you have a solid version history you can refer back to later.

if UI.confirm "Commit version bump and Tag this version?"
  commit_version_bump
  add_git_tag(tag: lane_context[SharedValues::VERSION_NUMBER])
  push_git_tags
end

If we say yes to the prompt, we'll get a commit in the git history, then it will automatically tag the release with that version number we set earlier. Finally it will push the tags to the git remote (which is often forgotten).

This type of setup is especially important if multiple people are doing releases. You want to have a consistent strategy so that people don't forget to tag (or forget to push them) and so that the tags all have the same naming consistency.

ben@mac $ git tag
1.0
1.0.1
1.0.2
1.1
1.2
2.0
2.0.1

If a customer experiences an issue, you can always checkout the tag for that release and start building your fix from there.