Notes

Continuous Deployment for React Native app to Expo using Bitbucket Pipelines

Edit on GitHub

DevOps
5 minutes
  • Expo lets you deploy and test your app
  • Bitbucket Pipelines lets you run commands in a Docker container

bitbucket-pipelines.yml

bitbucket-pipelines.yml is the file that you need to commit to the root of your repo in order to enable Pipelines. I’d recommend going to the Pipelines page for your repo and generate one from there. It’ll commit it to your repo and you can edit the configuration later in your code editor.

Variables in your pipeline

You can set your variables and their values under Repository Settings (and other places). They’ll be available for you to reference in your scripts like so

$AWS_SECRET

You can only set Repository Variables after you have added the bitbucket-pipelines.yml file

Configuration

Here’s my bitbucket-pipelines.yml file:

  • The file is heavily commented to give an idea of what’s happening at each step and why
  • I’m deploying master, develop and feature/* branches on Bitbucket to production, staging, test channels on Expo respectively.
  • Because i have mentioned deployment values, the builds will also show under the Deployments page in Bitbucket, giving you an overview of all your deployments.
  • You can configure deployment environments under Settings > Deployemnt
  • I’m not using tests at the moment so the Test with Jest step is fairly useless. But i have left it there for reference later.
  • Inside the Docker build container, you can install any app and run any command you want. This gives you a lot of freedom when defining your script
 1# This is the build configuration for React Native Expo project using Bitbucket Pipelines.
 2# Configuration options: https://confluence.atlassian.com/bitbucket/configure-bitbucket-pipelines-yml-792298910.html
 3# Only use spaces to indent your .yml configuration.
 4# -----
 5# You can specify a custom docker image from Docker Hub as your build environment.
 6---
 7image: node:latest
 8
 9definitions:
10  caches: # configure caches to speed up builds. more: https://confluence.atlassian.com/bitbucket/caching-dependencies-895552876.html
11    npm: '${HOME}/.npm'
12    jest: .jest
13
14pipelines: # contains all your pipeline definitions. you can define multiple pipelines in the configuration file
15  default: # contains the steps that run on every push for any branche that isn't specifically added in this config.
16    - step: # each step starts a new Docker container with a clone of your repository, then runs the contents of your script section.
17        name: Test with Jest
18        caches:
19          - npm
20          - jest
21        script: # a list of commands that are executed in sequence.
22          - npm ci
23          # - npx jest --ci
24
25  branches:
26    master: # This script runs only on commit to the master branch.
27      - step:
28          name: Deploy to Expo # https://exp.host/@USERNAME/PROJECT?release-channel=CHANNEL
29          deployment: production # used in the Deployments dashboard. Valid values are: test, staging, or production.
30          caches:
31            - npm # keep the npm cache around to speed up installs
32          script:
33            # Modify the commands below to build your Expo project
34            - unset NPM_CONFIG_USER # see: https://github.com/expo/sentry-expo/pull/26#issuecomment-453822980
35            - npm ci # ci = clean install
36            - npm i -g --unsafe-perm expo-cli # install Expo globally cz npx wasn't working
37            - expo login -u ${EXPO_USERNAME} -p ${EXPO_PASSWORD} # Use variables defined in Repository Settings
38            - expo publish --non-interactive --clear --release-channel production
39
40    develop: # This script runs only on commits to develop branch
41      - step:
42          name: Deploy to Expo
43          deployment: staging
44          caches:
45            - npm
46          script:
47            - unset NPM_CONFIG_USER
48            - npm ci
49            - npm i -g --unsafe-perm expo-cli
50            - expo login -u ${EXPO_USERNAME} -p ${EXPO_PASSWORD}
51            - expo publish --non-interactive --clear --release-channel staging
52
53    feature/*: # This script runs only on commit to branches with names that match the feature/* pattern.
54      - step:
55          name: Deploy to Expo
56          deployment: test
57          caches:
58            - npm
59          script:
60            - unset NPM_CONFIG_USER
61            - npm ci
62            - npm i -g --unsafe-perm expo-cli
63            - expo login -u ${EXPO_USERNAME} -p ${EXPO_PASSWORD}
64            - expo publish --non-interactive --clear --release-channel test

bitbucket pipeline for app center bitbucket pipeline for firebase

Notes

  • Ended up using latest instead of alpine to get rid of common issues like git not being installed and such
  • Had to add unset NPM_CONFIG_USER because of Sentry’s permission errors during install
  • Publishing to Expo with --clear to make sure it clears the bundler’s cache and doesn’t deploy cached stuff
  • Ended up instaling expo-cli globally and not running npx because of errors
  • The entire build takes 4m 09s for me
  • If you have Gitflow setup and are used to creating feature branches, make sure you push (and edit) your bitbucket-pipelines.yml in the master branch. Otherwise you’ll end up doing a lot of cherry-picking like me to get the changes back in master to see if the pipeline worked..

Trubleshooting

Ended up troubleshooting quite a bit as the build kept failing. It’s different running things in Docker containers..

Sentry issues
Bitbucket Pipeline: Error: EACCES: permission denied, mkdir '/root/.npm/sentry-cli' #47

resolved by adding unset NPM_CONFIG_USER before runnig any npm install commands

Opencollective
sh: ./node_modules/.bin/opencollective: not found

It’s some stupid dependency of a dependency to invite people to donate, causing CI/CD scripts to fail. react-native-router-flux uses it.. see npm install fails on 1.0.4. The workaround was to install the bloody thing manually before installing the rest of the packages and make it shutup.

1npm i opencollective
2# or following depending on what version a package is depending on
3# npm i opencollective-postinstall

I ended up removing react-native-router-flux altogether from my project because:

  • It’s not being actively developed, last change was to a beta version in 2017..
  • I can’t use the same knowledge for my React web projects - learn once, route anywhere principle.
  • npm ads will be banned
  • It’s causing my build to fail!
Expo

Got the following error when trying to run Expo commands with npx.

This command requires Expo CLI.
Do you want to install it globally [Y/n]? 

Resolved this by not using npx and installing Expo globally

NOTES

  • You can manually trigger deploys for branches that are not master to save up on your 50 free build minutes per month.