3 EAS Pipelines for Deploying React Native Apps in Teams

One of the best ways to increase productivity in a react native project is to automate the process of deploying builds you want to share internally in your team or with actual costumers via the app store. And you might be surprised at how easy it can actually be implemented when you have the right set of tools like GitHub Actions and EAS.

We'll look at a few different ways that will make your life more productive through the power of continuous deployment with EAS, or Expo Application Services. If you choose to follow along with your own project we will have it fully configured in no time.

What is continuous deployment?

Let's first get clear on what continuous deployment actually is. It's the practice of frequently making new builds and deploying them into production, in our case App Store and Play Store. We'll automate this process with some pipelines so we don't need to do this manually which is both more time consuming and error prone.

That's exactly what EAS and GitHub Actions can help us up with. EAS is a set of cloud services provided by the Expo team that makes it very easy for us as app developers to make builds that we can test on our devices and deploy to App Store and Play Store.

The GitFlow branch strategy

We'll be following the GitFlow branching strategy that involves using feature branches as well as two primary branches, the develop range and the main branch.

New code added to the code base needs to first be created in a feature branch, then from a pull request be merged into the develop branch and from here the develop branch can be merged into the main branch which is going to send the code into production.

Setting up the EAS project

The first thing we need to do is to create a new project called todo-app on http://expo.dev.

It's going to tell us to run the following commands.

Before you do any of these steps, log in to your expo account by running eas login.

Once that's done, we can go ahead and setup the actual pipelines.

The EAS pipelines

We will essentially be building 3 different pipelines that we will be using throughout our daily workflow.

The first pipeline we will be building is one for deploying new builds whenever a new pull request is created making it very easy for our team members to test our code simply by scanning a QR code and testing the code in the Expo Go app.

In order to trigger new builds with EAS from GitHub Actions, we first need to create an access token called EXPO_TOKEN on our http://expo.dev project.

Next, add this access token to your repository secrets on GitHub.

So now go ahead and .github/workflows folder with a file inside called publish-pull-request.yml.

name: Publish Pull Request
on:
  pull_request:
    branches:
      - develop

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 14.x

      - name: Setup Expo
        uses: expo/expo-github-action@v6
        with:
          expo-version: 4.x
          expo-cache: true
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

      - name: Install Dependencies
        run: yarn

      - name: Publish to Expo Go
        run: NODE_ENV=dev expo publish --non-interactive --release-channel pr-${{ github.event.number }}

      - name: Add Expo Link to PR
        uses: mshick/add-pr-comment@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          message: |
            ## Test this PR with Expo Go
            ![Expo QR](https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=exp://exp.host/@andreaslydemann/todo-app?release-channel=pr-${{ github.event.number }})
            **------ Build published to [Expo](https://exp.host/@andreaslydemann/todo-app?release-channel=pr-${{ github.event.number }}) ------**

In this GitHub Action we first specify when it should be triggered which is on pull request to the develop branch.

Then we will create a new job called "publish" which runs on Ubuntu and has some necessary permissions set up. Now we will set up the first steps of our GitHub action including setting up Node.js and Expo where we have to specify our EXPO_TOKEN that we inserted in our repository secrets.

Next, we install dependencies using yarn and we go ahead and set up the step to actually publish to Expo. First we need to specify our environment using the NODE_ENV variable. This is only irrelevant if you're using dotenv or another environment variable framework to control your environment variable in your React Native project.

Next we will use the expo publish command and give it a few parameters including non-interactive so it doesn't take any user inputs and a release channel as well which is where we can find our published app. We'll name it using the generated GitHub Actions run number.

Once the app is published the app is made available through a new link. We can transform this link into a QR code using the qrserver.com website. Now we want to add our QR code to the PR so our team members can easily test our code by scanning the QR code. We will use a third-party GitHub Action for this which takes the default GitHub token in order to modify our pull requests. We specify the exact message where we will display the QR code including a regular link to the published app that our team members can also use.

Once we publish a new pull request, we can see that a new comment is added where we can test the pull request.

The next pipeline is going to run whenever our pull request is merged to the develop branch so we always have a fresh build that our testers on the team can download on their various devices to search for new bugs introduced in the code base.

So go ahead and create a new pipeline called publish-test-build.yml.

name: Publish Test Build
on:
  push:
    branches:
      - develop

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 14.x

      - name: Setup Expo
        uses: expo/expo-github-action@v6
        with:
          expo-version: 4.x
          expo-cache: true
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

      - name: Install Dependencies
        run: yarn

      - name: Publish to Expo Go
        run: NODE_ENV=test expo publish --non-interactive --release-channel test

This does almost the same as our first pipeline, except creating a QR code. Instead it published the app to a release channel we call "test", exclusively for testing the app on the test environment.

The last pipeline is gonna be triggered whenever we merge the develop range into the main range here we want the pipeline to make a new build and deploy it to the App Store and Play Store.

In order to start setting up deployment to App Store and Play Store, run eas build:configure. It'll create a file called eas.json.

We will configure the file like this.

{
  "cli": {
    "requireCommit": false,
    "version": ">= 3.5.2"
  },
  "build": {
    "production": {
      "releaseChannel": "production",
      "distribution": "store",
      "ios": {
        "resourceClass": "m1-medium",
        "cocoapods": "1.11.2"
      },
      "env": {
        "NODE_ENV": "prod",
        "VERSION": "1.0.0",
        "BUILD_NUMBER": "1"
      }
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "yourappleid@apple.com",
        "ascAppId": "XXXXXXXX",
        "appleTeamId": "XXXXXXXX"
      },
      "android": {
        "track": "production",
        "changesNotSentForReview": true
      }
    }
  },
}

In this file we first set up some options for the CLI tool, such as version. Then we configure the build command where we define how our build to production should be configured, including the name of the release channel, the method of distribution and some specific settings for iOS, and some environment variables for app to use such as what environment we are on, the version number and the build number.

Finally we will configure the submit command for our apps that we are submitted to the App Store and Play Store. For iOS we need to define the Apple ID we'll be using to submit the build to App Store Connect account, the app ID where the app is going to land as well as our team ID.

Lastly we configure the Android build with submission to the production track and we disable automatically submitting our build to review.

To configure the deployment with details on code signing (creation of provisioning profiles, key store etc.), we need to run eas build and go through the various steps of the configuration process.

Now we can begin by create the actual pipeline. Go ahead and create one called publish-prod-build.

name: Publish Prod Build
on:
  push:
    branches:
      - main

jobs:
  publish-app-store:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 14.x

      - name: Setup Expo
        uses: expo/expo-github-action@v6
        with:
          expo-version: 4.x
          expo-cache: true
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

      - name: Install Dependencies
        run: yarn

      - name: EAS Build
        run: npx eas-cli build --platform all --profile production --non-interactive

      - name: Publish to App Store
        run: EXPO-APPLE-APP-SPECIFIC-PASSWORD=XXXX-XXXX-XXXX-XXXX npx eas-cli submit --platform ios --latest --non-interactive

      - name: Publish to Play Store
        run: npx eas-cli submit --platform android --latest --non-interactive

in here we'll give the pipeline a name and set it to be triggered on pushes to the main branch.

Next we'll configure the exact same first couple of steps we've used in the previous pipelines. But now we will define the EAS build step, including a few parameters such as the platforms you want to build for, the profile which is a reference to the entry in the eas.json file where we have a production entry with all the configurations for production build.

Now we will add the EAS submit steps. First for App Store where we will first give it an app specific password. You should also create an app specific password from the Apple Developer website. This is going to allow EAS to actually deploy our app to App Store Connect. Next we set the platform to iOS and set it to use the latest successful iOS build on EAS.

Finally we define the last EAS submit step for Android to the Play Store with almost the exact same parameters.

Now whenever we merge our develop branch into the main branch, it will trigger a new production build that goes to EAS first and then it's automatically submitted to App Store and Play Store.

All submissions to the App Store and Play Store will now start showing up in our expo project.

Conclusion

Implementing these 3 pipelines in your project will automate your entire deployment process, and if you implement these your development workflow is about to skyrocket.

Now, having an automated deployment process is one thing, but there is so much more potential with what you can automate to further increase your workflow. I'm sharing with you in my next post exactly how to generate your React Native apps API client code, including all the models you'll be using to communicate with the backend, so make sure to check that one out.

You can check out the full repository here.

Share this post

Facebook
Twitter
LinkedIn
Reddit

You may also like

Design

How to Make Animated 3D Mockups in Seconds

As an individual app developer, you need to bring attention to your published apps. Companies of top-selling apps agree on how this is executed successfully. They create stunning and professional-looking animated 3D mockups of the apps. I’m here to tell you how you can create these for yourself in a matter of seconds.

Swift

7 Useful Filtering Operators in RxSwift

After using RxSwift for several months now, I can safely say that filtering is a key feature that has saved me plenty of lines of code. To know which filtering operators to use when, requires a basic overview, so let’s look at 7 of my favorite filtering operators this library has to offer.