Automated React-Native Release Tagging Using GitHub Actions

In a recent client project, we set up automated iOS releases using GitHub actions and fastlane. We had a couple different specifications for it that made it a little more challenging than normal:

  • We wanted to be able to kick off the release both manually and on a schedule
  • We wanted to have tags created every time a build was created, and wanted this to be automated
  • We wanted to be able automate version bumps so that we didn’t have to make local changes to the version in the codebase

This led us to a solution that we’re proud of, and wanted to share with others who may be looking for a similar solution. The basic idea was that we set up a tagging process that was kicked off either through a manual workflow dispatch or a scheduled run. The tag being created triggers the release workflow, which receives the tag information and creates the release off of it.

Automated Tagging

To set this up, we create a file which has jobs that are triggered either on manual dispatch or on a schedule. The manual dispatch receives an input for the , which can be specified as either , , , or . That looks like this:

Now we can configure the job to run. In order to do this, we need to first specify the we use to authenticate with GitHub's API for the tag creation, as well as the base branch in the repo. The should be put into the secrets of the repo. For instructions on how to create a personal access token, look here.

The next step is to set up the environment variables we will need to decide what type of version bump (if any) should happen with our tagging. Because this can be triggered either with an input or on a schedule, we can’t just directly use the input value. Instead, we wrote a bash script which checks for the version change type, with as the default, and selectively outputs whether we need a version bump. It also outputs the branch name to tag, since we will be creating a branch and PR with our version change rather than pushing directly to the base branch. The way we set this up looked like this:

We can now check out the main branch that we’ll be bumping the version off of:

And then run our fastlane command to bump the version, but only if the environment variable we set earlier is set to true:

Our fastlane command also utilizes the environment variable we have set above to know what type of version bump to do:

Now that our version has been bumped in the native code, we can check out a branch and make a PR for these changes:

The last step is to actually create our tag using GitHub’s API. In order to do this, we need to write a script that checks our most recent version and bumps it in the same manner that Fastlane bumped our native code. Another important piece for mobile is to have a distinguishing number differentiating the tags so that we can create a new tag without actually bumping the version. This allows us to have as many tags on a single version as we want, so that we only need to bump the version once the most recent one has been actually sent to users on the app store. The way we did this was appending an incremental number onto each version after a so that we could see how many builds there were for a specific version. For example, if I created a new tag without specifying a version bump, and my most recent tag was , then the new tag would be . The Node script we wrote to do that looks like this:

Now that we have that added, the last step in our action is just to run it:

If you want to see all the pieces put together, you can check out this gist.

Releasing

The releasing process is very specific to each project, and can vary depending on how you want to do certs, what set up steps you have, how you build your app, what fastlane commands you use, etc… Because of this and for simplicity, I’ll just show the basic set up of our release file, and leave the actual building and upload process out.

In order to time our release right to ensure that the scheduled tag workflow is finished before our release workflow runs, it made the most sense to just trigger our release workflow based off when a tag was created. This also made our release process a 1 step process, so that you only had to manually kick off of the tag creation instead of waiting for it to finish and then kicking off the release. We still wanted to allow a manual dispatch with a specified ref in case you wanted to create a release off of a specific branch, tag, or commit. We also wanted to allow the user to specify whether they wanted an , , or release, with being the default for the automated releases. For production releases, those will have to be done manually. That workflow definition looks like this:

The only other set up step after that is to ensure we checked out the correct ref and set the correct release stage. That looks like this:

Once you get the building/releasing working in CI, you should be all set with an automated workflow of tagging and releasing both beta and production builds, with the click of a button and on a regular cadence of your choosing 🎉

More about:

Dominic Sherman

Dominic is a Senior Software Engineer at Echobind with a focus on React Native, NextJS, and GraphQL. Outside of his job, he can be found watching soccer, exploring the PNW with his family, or getting way too invested in a random sport like cycling or ping pong.