Manager version-code/build-number with git tag for Mobile App
Tags: mobileapp, reactnative, version, git
Published: 2020-07-12 23:10:54

## TLDR;
- Use `git tag` to store version-code (aka build-number for iOS, for easier, I only mention version-code from now on)
- `Auto increase` version-code and `add a tag` when building a new release
- Version code is synced between developers/CI 
- Can be used for both iOS and Android
- Why we need this => check [Read More](#read-more)

### Result
**The build process before** 😬
1. Manually increase version, version-code
2. Manually switch environment (I have dev, stage and production)
3. Run fastlane to build iOS and Android
4. Wait build complete and manually add tag and push tag

**The build process after** 🚀🚀🚀
1. Run the script
```sh
yarn build-release
```
Yes! that's it. Only run one command. The build-release script build with `environment=stage` by default


## Let's do it
(you can read more at [Read More](#read-more))

1) tag name: because my repo contains multiple projects, so for mobile app, I added a prefix: `mobile`, and also the environment: `staging` or `production` (no need for dev)

Format: <project>/<environment>/v<version>-<version-code>
Example: `mobile/staging/v3.0.0-233`, `mobile/production/v3.0.0-400`

> I use the same version, and version-code for both iOS, Android to reduce the confusion here. Because in my team, we always release iOS, Android together


2) To configure the mobile, I also use some simple search and replace to set: version, version-code, android manifest file, ios info.plist, entitlement file, etc. But that's out of scope for this post. I will share the script in another blog :P

3) Tools
- I use JS with: `fs-extra`, `simple-git`

### The process
1) **Set environment** (opt): staging or production
- Skip this step if you don't have

2) **Get latest tag** and increase by one
- Fetch all tags => to make sure we have the latest tag (largest tag number)
- Get latest tag for mobile 
```sh
git tag --list mobile/* --sort=-taggerdate
```
- Increase tag, push back

Full code:
```js
async function getNextVerionCode(env) {
  try {
    console.log(`--- Git fetch --tags...`);
    await git.fetch("--tags");
    const result = await git.tag(["--list", `mobile/*`, "--sort=-taggerdate"]);
    if (!result) {
      throw new Error("mobile/production tags is missing");
    }
    const latestTag = result.split("\n")[0];
    if (!latestTag) {
      throw new Error("cannot parse tag");
    }
    const versionCode = parseInt(latestTag.split("-")[1]);
    if (!versionCode) {
      throw new Error("cannot parse version code");
    }
    return versionCode + 1;
  } catch (err) {
    console.warn(`getNextVersionCode error: ${err}`);
  }
}
```


3) Set version-code with the tag 
Full code:
```js
async function gitTagVersionCode(versionCode) {
  try {
    const versionTag = `v${appInfo.version}-${versionCode}`;

    let tag = argBuildLane === "staging" ? `mobile/staging/${versionTag}` : `mobile/production/${versionTag}`;
    console.log(`--- Git tag -a ${tag}...`);

    await git.tag(["-a", tag, "-m", `build release ${tag}`]);
    await git.push("origin", tag);
  } catch (err) {
    console.warn(`gitGagAppVersion error: ${err}`);
  }
}
```

4) Call fastlane to build
- At this step, we already have environment setup and correct version-number, the last step is call fastlane to build and upload to testflight

## Read more

### The project
- react-native cross-platform for iOS, Android
- mono repo, so the repo is including backend, DevOps, web app, mobile app

### Some other ways to store version-code (you can skip this)
1) https://proandroiddev.com/configuring-android-project-version-name-code-b168952f3323#.uccnmsg8b
> This is using `git-describe`: which is not fit for my project, because I need to use different tags for each project. For example: **web/production-v1.0.0, mobile/production-1.1.0**

2) https://wadehuang36.github.io/2018/05/18/use-git-tag-for-manage-app-version.html
> Like above, but using another tag name