Is it deployable? What is the next version number? How to generate release notes automatically?

Alpha. Beta. Production. Times two — iOS and Android. Plus Codepush. Those could be versions of your React Native app. I want to share with you guys how we deploy everything automatically by using GIT flow and Conventional Commits. Inspired by semantic-release.

When do we release those versions?

  • Alpha Version. Every night. For in-house testing. Based on the develop branch.
  • Beta Version. Triggered by pushing to the beta branch.
  • Production Version. Uploaded to Apple Store and Google Play. Triggered by pushing to master branch.

All those versions are released only when there is a reason to release it. If there is no new commit since the last version the workflow will be canceled automatically.

How does our version look like?

We use a semver. Major. Minor. Patch. It could be 1.3.4. When we release a version, we create a unique tag in the GIT. For example, android/production/1.3.4/7683 or ios/alpha/1.5.0/8754.

Our tag system — [platform]/[flavor]/[version]/[build number]

Why we do not store version in a package.json 🚫

If we stored the version inpackage.json file (as many people do) we wouldn’t be able to increase the version automatically. Because it is changed by CircleCI and CircleCI would have to push the change back to the repository. That would trigger a new release. Because every single push triggers a release. Not talking about how many Bump version commits we would have in the history of GIT.

How does it work with Production Release?

In this example, we push to the master branch and expect Android and the iOS app will be uploaded to the stores. We will simulate a fail of the iOS build.

Push to Master #1

The master branch was “fast forwarded” (merged) from the commit A to the commit D. The last version for both is on commit A (see tags).

Git History After Merge Master Branch

Release workflow is triggered. First step. Install dependencies. No big deal. It only creates a node modules folder. The second step. Code quality check. Jest. Lint. Flow. If one of them ends up with an error, the whole workflow will be canceled.

Production Release Workflow

After this step, our workflow is separated into the Android branch and iOS branch. And this is a point where the commit analysis plays a big part in the workflow.

Android
Our script (Android Analysis) finds the last tag for android/production(simply by using the git command line tool). The tag is found on the commit A. It gets the last version by parsing of the tag name. It is 1.3.4. Then, by analyzing commits, it finds out a next version number.

  • Commit B. Feature (feat keyword). It means we have to increase a minor number 1.4.0. If you increase the minor number you must reset patch number (see semver documentation).
  • Commit C. Fix (fix keyword). Increases patch number 1.4.1.
  • Commit D. It is just an update of documentation (doc keyword). There is no change in the version number.

That’s it. We got the next version number. No manual actions! Next version 1.4.1 is higher than the current version 1.3.4. Release continues. Decided automatically. We can pass the number to the Fastlane and build a release. Once the build is ready, it continues by deploying the version to the store. After deployment, it creates a new tag on HEAD (commit D) and generates release notes. Android is done!

iOS
Our script (iOS Analysis step) finds the last tag for ios/production. It continues in the same way as the android part. It gets the next version number 1.4.1 and continues to build and deploy steps.

To make it a bit complicated, let’s say that the build of the iOS release failed. Because of our build tool is badly configurated.

What should we do now? Android is already released. If we change something and push to the master it will release Android again. We could wait on CircleCI and cancel the job manually. 🤔 Fortunately, we don’t have to. Let’s see why.

Push to master #2

We fixed the problem that caused our iOS app wasn’t released. Now we pushed the fix to the master. It will trigger the deployment workflow again. But because of our scripts, the workflow will be different this time.

Android
There is only one commit since the last version of android production (1.4.1). And that’s what was changed since the last release. Because Android was successfully released (Push to master #1). The new commit E won’t increase a version number. Because it is just updating of building tools. The workflow for Android ends with Android Analysis step.

Production Release Workflow

iOS
The situation will be the same as during the push to master #1. There is only one commit more. But this commit doesn’t change the version. The last release of the iOS version is 1.3.4 on commit A. It analyses commits and finds out that the new version will be 1.4.1. It continues with the build, deploy and it will be successful this time. 🎉

Even though we pushed to the master again, the Android version wasn’t released again. We didn’t have to cancel anything manually. Everything works automatically. Just by analyzing commits.

Release Notes

It can even generate release notes by analyzing of the commits. This is our GIT history after the push to master #2.

GIT History after Push to Master #2

Release notes for iOS include commit B as a new feature and commitC as a fix (patch). It will skip commit C and commit D because they don’t change anything for users.

Codepush friendly? 👍

You very likely already heard about codepush. A tool that provides us a possibility to release only javascript part. Users would get updates immediately. Nice idea. But in the real world, when we were preparing a release, it was always hard to know if we can release just a javascript or not. There were always doubts. And something extra we needed to do every release.Now, we have this release tool. It analyzes commits for us. Our developers just have to mark the commit they are working on. Let’s say they will write a keyword to the commit message. For example [codepush-ok].Then it does exactly the same as during the upload to the stores. Finds the last tag of codepush release. Analyze commits since that release. If there is one commit which is not marked as [codepush-ok] it will cancel deploy. If all commits are marked with [codepush-ok] we can release codepush version. Isn’t it easy?

How do you release React Native apps?

I’ll be happy if you leave a comment and tell me your secret about releasing. How do you deal with versioning of React Native app? Are you still doing that manually? Do you use package.json?