+++
title = "React Native with Gitlab CI/CD"
date = "2020-04-06"
author = "Ceda EI"
authorTwitter = "" #do not include @
cover = ""
tags = ["react-native", "javascript", "gitlab"]
keywords = ["react-native", "javascript", "gitlab", "ci", "cd"]
description = "Recently, I decided to set up automated builds for Sonzai"
showFullContent = false
aliases = [
	"/2020/04/06/React-Native-with-Gitlab-CI.html"
]
+++

## Introduction

The aim of setting up CI/CD is to automatically build the app on every commit
and send the APK. I looked into Gitlab CI/CD for this purpose since
[Sonzai](https://gitlab.com/ceda_ei/sonzai/) is already hosted on Gitlab.

## Build Stage

To get started, I needed to choose a docker image in which the repo would be
built. After looking around a bit, I found that the
[react-native-community](https://github.com/react-native-community/) has an
official [Docker
image](https://hub.docker.com/r/reactnativecommunity/react-native-android), the
source of which can be found on
[GitHub](https://github.com/react-native-community/docker-android).

Gitlab CI/CD is controlled by a versioned file in the repo: `.gitlab-ci.yml`.
To start off, I added the `build` job in the file and set image to the docker
image above.

```yml
stages:
    - build

build:
    image: reactnativecommunity/react-native-android
    stage: build
```

I needed to add the commands to be executed in order to build the app. Those
commands are added under the `script` key as an array. In my case, I need to
run `yarn install` to install all dependencies followed by `./gradlew
assembleRelease` in the `android` directory. The file now looks like.

```yml
stages:
    - build

build:
    image: reactnativecommunity/react-native-android
    stage: build
    script:
        - yarn install
        - cd android && chmod +x gradlew
        - ./gradlew assembleRelease
```

Next, once the build is done, I need to export the `outputs` generated in the
build to be consumed by the deploy stage. This is done by adding an `artifacts`
object which contains a `path` array for all the paths that need to be included
in the artifacts. In this case, the outputs are in
`android/app/build/outputs/`. The file now looks like:

```yml
stages:
    - build
    - deploy

build:
    image: reactnativecommunity/react-native-android
    stage: build
    script:
        - yarn install
        - cd android && chmod +x gradlew
        - ./gradlew assembleRelease
    artifacts:
        paths:
            - android/app/build/outputs/
```

The build stage is now done.

## Deploy Stage

Although I could use the same image, the image is fairly large and takes time
to initialize. So, I used
[curlimages/curl](https://hub.docker.com/r/curlimages/curl) which is an alpine
image with curl added and thus is really light. I will be using `curl` to
upload the file to Telegram. Check out the
[documentation](core.telegram.org/bots/api) for bots API. Adding the deploy
stage, the file looks as:

```yml
stages:
    - build
    - deploy

build:
    image: reactnativecommunity/react-native-android
    stage: build
    script:
        - yarn install
        - cd android && chmod +x gradlew
        - ./gradlew assembleRelease
    artifacts:
        paths:
            - android/app/build/outputs/


deploy_tg:
    image: curlimages/curl
    stage: deploy
```

I created a bot via [@BotFather](https://t.me/BotFather) and added it to a
[channel](https://t.me/sonzai_builds). Next, I got the channel's chat ID. I
stored the Bot Token and the channel's chat ID as variables in Gitlab's UI
under Repository > Settings > CI / CD > Variables as `TG_BOT_TOKEN` and
`TG_CHAT_ID` respectively.

![Gitlab's UI screenshot](/images/gitlab-ci.jpg)

Next, I added a curl request in the script array to make the actual request to
Telegram Bot API which utilizes these variables. It also utilizes some
predefined variables in [Gitlab's default
environment](https://gitlab.com/help/ci/variables/predefined_variables.md).
Here is the final `.gitlab-ci.yml`

```yml
stages:
    - build
    - deploy

build:
    image: reactnativecommunity/react-native-android
    stage: build
    script:
        - yarn install
        - cd android && chmod +x gradlew
        - ./gradlew assembleRelease
    artifacts:
        paths:
            - android/app/build/outputs/


deploy_tg:
    image: curlimages/curl
    stage: deploy
    script:
        - >-
            curl
            -F chat_id=$TG_CHAT_ID
            -F document=@android/app/build/outputs/apk/release/app-release.apk
            -F caption=" <b>Branch</b>: <code>$CI_COMMIT_BRANCH</code>

            <b>Commit</b>: <code>$CI_COMMIT_SHORT_SHA</code>

            <b>Tag(if any)</b>: <code>$CI_COMMIT_TAG</code>


            <code>$CI_COMMIT_MESSAGE</code>"
            -F parse_mode=html
            https://api.telegram.org/bot${TG_BOT_TOKEN}/sendDocument
```

Here is the first build using this.

{{< rawhtml >}}
<script async src="https://telegram.org/js/telegram-widget.js?7" data-telegram-post="sonzai_builds/8" data-width="100%"></script>
{{< /rawhtml >}}
