A successful git branching model & AppCenter testing CI flow for React Native apps.
Tags: appcenter, reactnative, ios, android
Published: 2020-03-30 13:24:50

---
title: A successful git branching model & AppCenter testing CI flow for React Native apps.
published: true
description: An in-depth look at Deploying React Native apps via AppCenter with Staging and Production environments.
tags: appcenter, react-native, ios, android
---

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
```

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:

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

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


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

> 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](https://gist.github.com/karltaylor/88bf67f6699909890b767f895691142a)

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

```js
// switch.js
const env = process.argv[2]
changeAppConfig(env)
```

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

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

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:

```bash
#!/usr/bin/env bash

# APP_ENV would be staging or production.
yarn switch $APP_ENV
```

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](https://nvie.com/posts/a-successful-git-branching-model/) with a few small tweaks.

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

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rk5ss80zww2i3nkekojw.png)

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](https://semver.org/).

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](https://dev-to-uploads.s3.amazonaws.com/i/mhr8u71bns6n1tc3x2dy.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/i6z3yhgpyk3aio6vnw27.jpg)

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?