DEV Community

Karl Taylor
Karl Taylor

Posted on • Edited on

A successful git branching model & AppCenter testing CI flow for React Native apps.

After developing React Native applications for over 2 and a half years, I found a few paint points when developing, testing and releasing apps in a way that I could fully get my head around and keep my sanity, things like provisioning profiles and staging/production API URLs would cloud my vision. But I finally found an elegant solution.

The model I'm going to explain worked well for me and my team but YMMV.

Pain point 1

In an app stack with a staging and production environment, you need to change your API endpoint when developing for TestFlight or the App Store.

For example

https://api.staging.my-app.com
https://api.production.my-app.com
Enter fullscreen mode Exit fullscreen mode

Now back in the day, I would simply merge develop into master and then bump the version on master and also update the API endpoint manually. This is awful.

Solution

The solution was simple, I had a config file which included my endpoint:

// app/config/index.js
module.exports = {
  apiUrl: 'https://api.staging.myapp.com/graphql', // default to staging
  versionNumber: '1.0.0',
};
Enter fullscreen mode Exit fullscreen mode

Then I created a node script that will change the apiUrl depending on which arguments I pass to it.

// changeAppConfig.js
module.exports = async (env) => {
  await findAndReplace(
    config,
    /(apiUrl: 'https:\/\/)(.+)(.myapp.com\/graphql',)/,
    `$1${env}$3`,
  )
};
Enter fullscreen mode Exit fullscreen mode

Note: findAndReplace is just a function that takes a file, a regex, and a string which is the replacement using regex grouping. Here is a gist

Now I have a switch.js module which can take an argument of production. e.g. $ node switch production

// switch.js
const env = process.argv[2]
changeAppConfig(env)
Enter fullscreen mode Exit fullscreen mode

I would now have a config file which is set to production:

// app/config/index.js
module.exports = {
  apiUrl: 'https://api.production.myapp.com/graphql', // changed to production
  versionNumber: '1.0.0',
};
Enter fullscreen mode Exit fullscreen mode

So far so good, I can now easily switch between staging and production URLs. I can also utilize this within AppCenter by passing an appcenter-pre-build.sh script.

These run before your app is built and you can pass in environment variables in the build configuration on AppCenter. Here's an example:

#!/usr/bin/env bash

# APP_ENV would be staging or production.
yarn switch $APP_ENV
Enter fullscreen mode Exit fullscreen mode

Great! So now I can have 4 different apps on AppCenter with their environment variables set and the branches configured to build on push.

  • iOS staging
  • iOS Production
  • Android Staging
  • Android Production

Using git and releasing to staging/production.

So now I can easily switch between staging and production URLs. Let's talk about how we actually release the apps using AppCenter so QA can test the staging branch and master and build and release to production.

The flow

Our git flow was an adaption from the successful Git branching model with a few small tweaks.

I still use feature branches that are then merged into develop.

Alt Text

After I've got a few PR's merged into the develop branch, I would then create a staging release.

Now the way I've done this is as follows:

  1. Branch off of develop into a release branch with a version number and release candidate number. I try and keep in line with semver.

For this example, let's say it's a minor release, so we will increment the version number from 1.0.0 to 1.1.0. And it's the first release candidate to staging, so our branch will be release/1.1.0-rc.0

Alt Text

Now this works wonderfully. I can create a staging release candidate which will now build on AppCenter using the staging branch, which can now be reviewed by QA and features & develop branches can continue to be worked on.

If I add more features to dev, I can repeat the process and create a release/1.1.0-rc.1, release/1.1.0-rc.2 and so on.

Note: release branches should be deleted after they've been merged.

Releasing to master

Creating a release to master is similar to staging, but you simply merge the release branch into develop and into master, it is a full release, not an RC release, so we omit the -rc.x value.

Note: RC releases cannot be released to TestFlight, the value x.x.x-rc.x is not compatible.

Releasing to master

In my next post, I'll explain how I automate version bumps, branches, and pull requests to make deploying a whole lot easier.

How do you currently deploy your React Native applications? What are your pain points and achievements?

Top comments (0)