How To: Automate Build/Release Using GitHub Actions, Expo Build, and EAS Submit!

Hi Everyone,

We wanted to share the code we developed at EateDigital.com to build and release our app using any deployment profile, release channel, and OS based on a pull request being completed AND merged on a specific branch in GitHub.

We want to preface that the building and submitting can actually be done with EAS Build and Auto Submit. However, it wasn’t using the correct version number and version code. It started at 1, despite our app having higher versions. That’s when we decided that it’s all bash commands and scripts that we can leverage. The Expo standalone build process works flawlessly when we were manually setting the version code and number, but it was just cumbersome to wait for the build to grab EAS submit url to get it into the respective app stores. Also, EAS kept saying certain features will soon be deprecated. Building as a standalone provides us more security and assurance things won’t randomly start breaking in the future.

Overview
The workflow action is triggered when a pull request is completed and merged on a specific branch. It uses a 3rd party service called Standard-Version (click here for more info) to increment the version code and version number, then commits and pushes the local changes on the Linux server. After the push, the version of Expo is installed. Then then respective OS standalone build is done for a specific release channel, while it skips the credentials check since it’s being provided.

Once the build is done. It checks the build status (expo build:status) to get the most recent build, which is always in the Index 0 portion of the response. That response is outputted into a file that we create in the same working folder that the workflow is running in. Then it loops through the file to locate the eas submit url and put it into a variable. Then the eas submit url command is ran for the respective development profile.

Note: In our script below, we run iOS first, then Android immediately after. This is because the iOS submission portion can take a while, so we can run the Android portion once EAS gives a response to move on.

Whew! Wow! Enough background, now for the fun stuff!

Configurations
Expo - Make sure you have EAS credentials for the OS’s you want to use in the root of your repo, and that you have those respective stores connected to Expo/EAS. Also have your EAS.json and credentials.json in the root of your folder. Lastly, make sure your app.json is configured.

Note: Expo’s documentation helped us create and configure the files needed. We’ll gladly monitor this thread to assist with any questions!

GitHub:

  1. For a workflow action to work, in your repository, you must first add the workflow in your default branch. For most it’s “master” or “main.” Here’s a link for understanding GitHub Actions.

  2. Create a PAT for the GitHub account of your choice. Make sure to give that token as much access as possible. We checked all boxes. Make sure to copy the PAT and save it in a place you’ll remember. You’ll need it for the next step. Creating a PAT on GitHub

  3. Create “Secrets” for the username and password used logging into expo. Typically an account with admin privileges. Also, create a secret for the PAT we just created. Create Secrets on GitHub

The Code

name: Update Version, Build And Release

on:
pull_request:
branches:
- develop
types: [closed]

jobs:
update_version_and_release:
if: github.event.pull_request.merged == true
name: Update Version
env:
EXPO_GIT_TOKEN: ${{ secrets.EXPO_GIT_TOKEN }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
token: ${{ env.EXPO_GIT_TOKEN }}
- uses: actions/setup-python@v2
- run: git config --global user.email “your_email_here@test.com
- run: git config --global user.name “Your Name Here”
- run: yarn install
- run: yarn standard-version
- run: git push --follow-tags origin develop
- uses: actions/setup-node@v2
with:
node-version: 14.x
- uses: expo/expo-github-action@v6
with:
expo-version: 4.x
eas-version: latest
expo-cache: true
username: ${{ secrets.EXPO_CLI_USERNAME }}
password: ${{ secrets.EXPO_CLI_PASSWORD }}
- run: yarn install
- run: yarn add expo@42.0.0
- run: expo build:ios -t archive --skip-credentials-check --release-channel qa
- run: echo “FILE_OUTPUT=/home/runner/work/expo_ios_output.txt” > $GITHUB_ENV
- run: expo build:status 2>&1 | tee ${{env.FILE_OUTPUT}}
- run: test -f ${{env.FILE_OUTPUT}} && echo “the file exists.”
- run: lenStr=129;foundLatest=false; buildFinished=false; while read p; do if [[ $p == “### 0 | iOS” ]]; then foundLatest=true; continue; fi; if [[ $foundLatest == “true” && $p == “finished” ]]; then buildFinished=true; continue; fi; if [[ $buildFinished == “true” && $p == “IPA” ]]; then lenStr=${#p}; echo “EAS_URL=${p:16:lenStr}” > $GITHUB_ENV; break; fi; done < ${{env.FILE_OUTPUT}};
- run: echo the eas submit url ${{ env.EAS_URL }}
- run: eas submit --platform ios --profile development --url ${{ env.EAS_URL }}
- run: expo build:android -t apk --non-interactive --release-channel qa
- run: echo “FILE_OUTPUT=/home/runner/work/expo_android_output.txt” > $GITHUB_ENV
- run: expo build:status 2>&1 | tee ${{env.FILE_OUTPUT}}
- run: test -f ${{env.FILE_OUTPUT}} && echo “the file exists.”
- run: lenStr=129;foundLatest=false; buildFinished=false; while read p; do if [[ $p == “### 0 | Android” ]]; then foundLatest=true; continue; fi; if [[ $foundLatest == “true” && $p == “finished” ]]; then buildFinished=true; continue; fi; if [[ $buildFinished == “true” && $p == “APK” ]]; then lenStr=${#p}; echo “EAS_URL=${p:16:lenStr}” > $GITHUB_ENV; break; fi; done < ${{env.FILE_OUTPUT}};
- run: echo the eas submit url ${{ env.EAS_URL }}
- run: eas submit --platform android --profile development --url ${{ env.EAS_URL }}

Conclusion
We at EateDigital hope this has been helpful. We know someone out there can use all of this, or at least portions of this, to get them through their development. Expo is a great product and service and they’re always getting better and simplifying, but everyone’s needs may not be satisfied by the latest versions. If there are questions, comments, concerns, or gratitude, feel free to reply!

Happy New Year!