Using GitHub Actions to seamlessly deploy Expo applications (Part 1)
Tags: expo, githubactions
Published: 2020-08-23 12:53:57

### **Introduction**
My first experience with mobile application development was using react native with Expo (in case you didn't know Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React, this means that you didn't need to know java or swift to create native applications). 


Coming from a React background, it was quite easy for me to adapt and pick it up. I was especially impressed with the ability to preview and live-reload the application on my phone just like a web application and also with the packages made available by Expo to interact with the phone hardware. I felt that all these improvements helped to improve the speed and quality during development.


However, the release process was not really ideal. As a newcomer, I was confused with the concept of publishing building and uploading to the respective app stores. Besides that, every new release involved getting a senior engineer to:
* Find time to do a release
* Publish the changes to a staging channel
* Test that staging functionality is working
* Build the application using Expo's instance of turtle Cli
* Wait 30 minutes for each app binary to complete (iOS and Android)
* Uploading of files to the Testflight/Google store


What if there was an easier way to update the application? I wanted to improve on this existing flow making sure to automate the testing and release process. 


The following article will be a 2 part series on first setting up Continuous Integration (applying tests and publishing PR reviews) then the second part will cover Continuous Deployment with GitHub Actions for your Expo projects.

### **An integrated solution**
I have been using GitHub actions for a while now as a CI/CD, it is not only versatile in allowing for self-host runners but also comes with a slew of actions made by the community. It is also free for any public repository making it a very appealing choice for our project.


Expo also offers a [GitHub action tool](https://github.com/expo/expo-github-action) called `expo/expo-github-action` which allows us to run expo commands in our workflows. This means that we can publish and review any version of the code to ensure everything is working.

### **Setting up Expo deployments**
Before we get started, we need to [sign up for an Expo account](https://expo.io/signup) in order to publish applications. We will then need to store these credentials within the secure GitHub Secrets Store for later use. I recommend using `EXPO_CLI_USERNAME` and `EXPO_CLI_PASSWORD` variables. You can find out [how to store secrets on the GitHub documentation site](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository).


For now, we only plan to publish the Expo application for user testing. However, for distributing and uploading applications to the respective stores, a detailed guide can be found on [here on the Expo site](https://docs.expo.io/distribution/uploading-apps).

### **Running Unit Test and Linting**
Testing is essential, its purpose is to validate that each unit of the software code performs as expected and helps engineers to spot bugs early before production, bring cost and productivity savings late on. 

To begin we first have to make a `.github/workflows` directory where we will be storing all our workflows.

We can use the following example as a boiler template to perform our test automatically on each pull request:

```bash
name: Deploy Branch Preview

on: [pull_request]

jobs:
  test:
    name: Lint & Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - name: Cache Node Modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          # npm cache files are stored in `~/.npm` on Linux/macOS
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-	
            ${{ runner.os }}-build-	
            ${{ runner.os }}-
      - name: Install Packages
        run: npm install
      # Peform a type check if you are using typescript
      - name: Typecheck
        run: npx --no-install tsc --noEmit
      - name: Check Lint
        run: npm run lint
      - name: Test
        run: npm run test -- --coverage
```
_The repo link can be found at the bottom of the article_

### **Automated PR deployments**
One thing I enjoy and find especially helpful in my react native development process is to publish and check the application on code review before pushing any code. This allows me to better understand the changes made in that pull request and provide a better review.

The following piece of code is a job to publish a release for a PR review on the Exponent server:

```bash
  deploy_branch_preview:
    name: Deploy Branch Preview
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - uses: expo/expo-github-action@v5
        with:
          expo-packager: npm
          expo-username: ${{ secrets.EXPO_CLI_USERNAME }}
          expo-password: ${{ secrets.EXPO_CLI_PASSWORD }}
          expo-cache: true
      - name: Cache Node Modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-
      - name: Install Packages
        run: npm install
      - name: Expo Publish Channel
        run: expo publish --non-interactive --release-channel pr${{ github.event.number }}
      - name: Add Comment To PR
        uses: mshick/add-pr-comment@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EXPO_PROJECT: "@justussoh/github-actions-expo-boiler-template" # Put in your own Expo project name here
        with:
          message: |
            ## Application
            ![Expo QR](https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=exp://exp.host/${{ env.EXPO_PROJECT }}?release-channel=pr${{ github.event.number }})
            Published to https://exp.host/${{ env.EXPO_PROJECT }}?release-channel=pr${{ github.event.number }}
```
_The repo link can be found at the bottom of the article_

Deploying always generates a fixed URL for anyone to open the application. Here I used a QR generator to churn a  QR from the link for the application which will be commented on the pull request so that anyone can easily check it.

You can the application via scanning the QR code with your Expo client application. 

![QR](https://dev-to-uploads.s3.amazonaws.com/i/g8yscc5zi8dlr3m35csy.PNG)

### **Publishing to a staging environment**

To further maximize efficiency, we can also configure the action to deploy to a staging environment after merging a pull request into master, this was a staging env will always be present before posting to production.

The code will be relatively similar to the PR actions, therefore I will link the file [here](https://github.com/justussoh/github-actions-expo-boiler-template/pull/2#issuecomment-675628863).

### **Conclusion**

In the above to parts, we achieved a robust CI to help run tests and publish the application for user testing. Keep a lookout for [part 2](https://dev.to/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-2-57mi) where I will be explaining how to version and publish your application to the app store to allow for over the air updates to your application. If you want to check out the full repo, the link is down below.


{% github justussoh/github-actions-expo-boiler-template %}