<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Justus Soh</title>
    <description>The latest articles on Forem by Justus Soh (@justussoh).</description>
    <link>https://forem.com/justussoh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F453459%2Fd65c6fff-6332-42fb-959b-3edfc83e0139.jpeg</url>
      <title>Forem: Justus Soh</title>
      <link>https://forem.com/justussoh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/justussoh"/>
    <language>en</language>
    <item>
      <title>Using GitHub Actions to seamlessly deploy Expo applications (Part 2)</title>
      <dc:creator>Justus Soh</dc:creator>
      <pubDate>Mon, 24 Aug 2020 04:45:45 +0000</pubDate>
      <link>https://forem.com/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-2-57mi</link>
      <guid>https://forem.com/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-2-57mi</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Continuation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In part 1 of this series, I went through some of the pre-requisites to use Expo with GitHub actions and demonstrated how to set up your first action. If you want to learn more about how to run tests and publish branches, you can check out &lt;a href="https://dev.to/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-1-3jfb"&gt;part 1 here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;In this section, I will explain the purpose of versioning and how to build the application using the Expo turtle service for the distribution of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Importance of versioning&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Why should we version? Is it necessary? How will this improve user experience? As the project grows, the number of dependencies grows and gets more difficult to manage. Eventually, one might find it difficult to upgrade without breaking contracts with other services. Version control is a simple way we can manage these dependencies with a common set of rules so that everyone can be on the same page. This is &lt;a href="https://semver.org/"&gt;Semantic Versioning&lt;/a&gt; and follows a given rule in the format &lt;code&gt;Major.Minor.Patch&lt;/code&gt;. Major changes include breaking API changes, Minor changes add functionality that is backward compatible and Patch adds bug fix.&lt;/p&gt;

&lt;p&gt;The proper use of versioning could bring about a slew of advantages to the application. In-app versioning could allow for easy debugging of reported bugs by verifying code base and app version. Configuring over the air updates (OTA) to only send minor and patch updates would prevent breaking changes from bricking your application. This would also allow for different major versions of the application to existing and be maintained for users who haven't grab the latest version from the respective application stores.&lt;/p&gt;

&lt;p&gt;In my implementation, I will specifically be using the GitHub release tag to trigger my workflows and also specify the name of the tag to match &lt;code&gt;prod-Major.Minor.Patch&lt;/code&gt; so as to inform the action which release-channels to deploy the application to.&lt;/p&gt;

&lt;p&gt;There are a lot of things going on in the code. I will first provide the code followed by a detailed explanation of some choices I have made.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;name: Create Release
on:
  push:
    tags:
      - &lt;span class="s2"&gt;"prod-[1-9]+.[0-9]+.[0-9]+"&lt;/span&gt; &lt;span class="c"&gt;# Push events to matching prod-*, i.e.prod-20.15.10&lt;/span&gt;

&lt;span class="nb"&gt;jobs&lt;/span&gt;:
  deploy_prod:
    name: Deploy To Production
    needs: &lt;span class="nb"&gt;test
    &lt;/span&gt;runs-on: ubuntu-latest
    outputs:
      releaseChannel: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ steps.releaseChannel.outputs.releaseChannel &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
      latestBinaryVersion: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ steps.latestBinaryVersion.outputs.version &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
    steps:
      - uses: actions/checkout@v2
        with:
          ref: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.head_ref &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
      - name: Fetch Tags
        run: |
          git fetch &lt;span class="nt"&gt;--prune&lt;/span&gt; &lt;span class="nt"&gt;--unshallow&lt;/span&gt; &lt;span class="nt"&gt;--tags&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - uses: expo/expo-github-action@v5
        with:
          expo-packager: npm
          expo-username: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.EXPO_CLI_USERNAME &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          expo-password: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.EXPO_CLI_PASSWORD &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          expo-cache: &lt;span class="nb"&gt;true&lt;/span&gt;
      - uses: rlespinasse/github-slug-action@v2.x
      - name: Generate Release Channel &lt;span class="c"&gt;# Release Channels are named prod-&amp;lt;Major Release&amp;gt;, i.e. prod-1, prod-3&lt;/span&gt;
        &lt;span class="nb"&gt;id&lt;/span&gt;: releaseChannel
        run: |
          &lt;span class="nv"&gt;RELEASE_CHANNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.GITHUB_REF_SLUG &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'s/\.[0-9]+\.[0-9]+$//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
          &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"::set-output name=releaseChannel::&lt;/span&gt;&lt;span class="nv"&gt;$RELEASE_CHANNEL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      - name: Install Packages
        run: npm &lt;span class="nb"&gt;install&lt;/span&gt;
      - name: Get Latest Binary Version &lt;span class="c"&gt;# Binary Version will be x.x.x based on the latest tag&lt;/span&gt;
        &lt;span class="nb"&gt;id&lt;/span&gt;: latestBinaryVersion
        run: |
          &lt;span class="c"&gt;# Release tag finds the lastest tag in the tree branch - i.e. prod-x.x.x&lt;/span&gt;
          &lt;span class="nv"&gt;RELEASE_TAG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;git describe &lt;span class="nt"&gt;--tags&lt;/span&gt; &lt;span class="nt"&gt;--abbrev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="si"&gt;))&lt;/span&gt;
          &lt;span class="c"&gt;# Using param substitution, we output x.x.x instead&lt;/span&gt;
          &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"::set-output name=version::&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RELEASE_TAG&lt;/span&gt;&lt;span class="p"&gt;#*-&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      - name: Echo Version Details
        run: |
          &lt;span class="nb"&gt;echo &lt;/span&gt;Build number is &lt;span class="nv"&gt;$GITHUB_RUN_NUMBER&lt;/span&gt;
          &lt;span class="nb"&gt;echo &lt;/span&gt;Latest release is &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ steps.latestBinaryVersion.outputs.version &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
      - name: Expo Publish Channel
        run: expo publish &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; &lt;span class="nt"&gt;--release-channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ steps.releaseChannel.outputs.releaseChannel &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In the first few lines, we can see that this action will only occur if a tag with name &lt;code&gt;prod-x.x.x&lt;/code&gt; is pushed. This gives us the flexibility to run the action either with the git command-line tool or the GitHub GUI create release page.&lt;/p&gt;

&lt;p&gt;Next, we can take a closer look at the step &lt;code&gt;Fetch Tag&lt;/code&gt; and &lt;code&gt;Get Latest Binary Version&lt;/code&gt;. Normally if we were to just grab the latest tag from the repo, the latest release tag will be grabbed, so instead, I decided to make this fail-proof through only taking the latest tag from that branch we are referencing.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;buildNumber&lt;/code&gt; also must be provided to the &lt;code&gt;app.json&lt;/code&gt; for the app to be built. In this case, I have chosen to use the GitHub actions run number (it is the small number beside the name of each run on the actions tab of the repo which counts the unique times the action is played not including reruns, you can find more info &lt;a href="https://docs.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tj9nOAZe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yajiq13xozy5xq9zbuqo.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tj9nOAZe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yajiq13xozy5xq9zbuqo.PNG" alt="GitHub run number"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the case of &lt;code&gt;Create Release&lt;/code&gt; out &lt;code&gt;buildNumber&lt;/code&gt; will be &lt;code&gt;3&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I also altered the release-channel for Expo to be represented as &lt;code&gt;prod-Major&lt;/code&gt; grabbing only the major version from the latest tag as we want to route the OTA updates to those channels. This also allows us to do hotfixes for older versions of the application by creating release on another branch so nothing will be broken.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Writing releases&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Being able to see and track changes from release to release is a game-changer. However, the hassle of creating a changelog for release to release brings about the stress of missing out on important changes. Fear not more, the community has written many some actions which we can utilize to help us generate a changelog from the past commits, this way no changes will be missed out and we can integrate it directly into the job. In my case, I have chosen &lt;a href="https://github.com/metcalfc/changelog-generator"&gt;metcalfc/changelog-generator&lt;/a&gt; because it's simple and gets the job done. After this is done, we will be using another community action &lt;a href="https://github.com/ncipollo/release-action"&gt;ncipollo/release-action&lt;/a&gt; to create or update the existing release tag.&lt;/p&gt;

&lt;p&gt;The example job is as follows:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;create_release:
    name: Create Release
    needs: deploy_prod
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: rlespinasse/github-slug-action@v2.x
      - name: Generate Changelog
        &lt;span class="nb"&gt;id&lt;/span&gt;: changelog
        uses: metcalfc/changelog-generator@v0.4.0
        with:
          myToken: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GITHUB_TOKEN &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          base-ref: &lt;span class="s1"&gt;'prod-0'&lt;/span&gt;
      - name: Creating Release
        uses: ncipollo/release-action@v1
        with:
          body: |
            Changes &lt;span class="k"&gt;in &lt;/span&gt;this Release: 
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ steps.changelog.outputs.changelog &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          token: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GITHUB_TOKEN &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          name: Release &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.GITHUB_REF_SLUG &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          allowUpdates: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Building and Distribution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The last and most important step in this would be building and distributing the application to the masses. The build time for the application is usually dependent on the &lt;a href="https://expo.io/turtle-status"&gt;number of projects queuing&lt;/a&gt; for the Expo build service, this process is usually quite lengthy (20 to 30 mins). Imagine waiting for about an hour just to build both Android and iOS binaries before every release, that would be a pain. But thankfully for us, we can write an action every release automatically and upload the binaries on the release itself or even the respective app stores! There are generally two approaches when it comes to using the free Expo build service that is to either wait for the service to complete before grabbing the URL or generated binaries or using a hook to send a POST request to a server when the build job is done. For simplicity and not wanting to spin up job listening for hooks in GitHub actions, I decided to go with the former option.&lt;/p&gt;

&lt;p&gt;Here is a code snippet of how the job may look like for an android apk package, iOS would just be a mirror running &lt;code&gt;build:ios&lt;/code&gt; instead:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt; build_android:
    needs: &lt;span class="o"&gt;[&lt;/span&gt;deploy_prod, create_release]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: rlespinasse/github-slug-action@v2.x
      - uses: expo/expo-github-action@v5
        with:
          expo-packager: npm
          expo-username: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.EXPO_CLI_USERNAME &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          expo-password: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.EXPO_CLI_PASSWORD &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          expo-cache: &lt;span class="nb"&gt;true&lt;/span&gt;
      - name: Install Packages
        run: npm &lt;span class="nb"&gt;install&lt;/span&gt;
      - name: Build Android Release
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          APP_BUILD_VERSION: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.run_number &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          APP_BINARY_VERSION: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ needs.deploy_prod.outputs.latestBinaryVersion &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
        run: |
          expo build:android &lt;span class="nt"&gt;--release-channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ needs.deploy_prod.outputs.releaseChannel &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; buildLogAndroid.txt
          &lt;span class="nb"&gt;cat &lt;/span&gt;buildLogAndroid.txt
      - name: Parse Asset URL
        &lt;span class="nb"&gt;id&lt;/span&gt;: androidUrl
        run: |
          &lt;span class="nv"&gt;ASSET_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;buildLogAndroid.txt | &lt;span class="nb"&gt;tail&lt;/span&gt; | egrep &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'https?://expo\.io/artifacts/[^ ]+'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
          &lt;span class="nb"&gt;echo &lt;/span&gt;The android url is &lt;span class="nv"&gt;$ASSET_URL&lt;/span&gt;
          &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"::set-output name=assetUrl::&lt;/span&gt;&lt;span class="nv"&gt;$ASSET_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      - name: Download APK Asset
        run: wget &lt;span class="nt"&gt;-O&lt;/span&gt; example-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.GITHUB_REF_SLUG &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;.apk &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ steps.androidUrl.outputs.assetUrl &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
      - name: Upload Release Asset
        uses: svenstaro/upload-release-action@v2
        with:
          repo_token: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GITHUB_TOKEN &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          file: ./example-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.GITHUB_REF_SLUG &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;.apk
          asset_name: example-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.GITHUB_REF_SLUG &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;.apk
          tag: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.ref &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;One challenge I faced was grabbing the &lt;code&gt;.apk&lt;/code&gt; asset when the build was complete. In some cases, using the &lt;code&gt;expo url:apk&lt;/code&gt; would yield the wrong result as only the latest build would not be updated, hence I decided to stick to using good old trusty regex to solve the problem. After which the uploading of assets to the release was smooth sailing.&lt;/p&gt;

&lt;p&gt;The final output of the release should look something like this! Concise with all the parts we need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BAcfrp9f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jtujn14s5yiul2h59anm.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BAcfrp9f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jtujn14s5yiul2h59anm.PNG" alt="release snapshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Improvements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Some improvements we could make would be to use a community action like &lt;a href="https://github.com/marketplace/actions/github-tag-bump"&gt;GitHub Tag Bump&lt;/a&gt; to store the latest version as a tag and automatically bump up the version base on the PR description, but that will be a story for another time. Another area for improvement would be to automatically add the upload the built &lt;code&gt;.apk&lt;/code&gt; and &lt;code&gt;.ipa&lt;/code&gt; binaries to the app stores directly. If you would like to do that you can read more about the process &lt;a href="https://docs.expo.io/distribution/uploading-apps/#2-start-the-upload"&gt;here&lt;/a&gt;. There are definitely many other areas of improvement and I'll continue working on the repo to add functionality to the CI/CD workflow.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Overall, it has been a fun journey planning out how I wanted the workflow to run and how it should be implemented. Also, documenting the process was enjoyable so that others can learn from and use GitHub Actions for themselves. I want to give a shout out to my mentor Sebastian as well for guiding me in the process and reviewing the same jobs and workflows for another project.&lt;/p&gt;

&lt;p&gt;You can check out the entire repo here! Do fork it and play around with it however you like.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/justussoh"&gt;
        justussoh
      &lt;/a&gt; / &lt;a href="https://github.com/justussoh/github-actions-expo-boiler-template"&gt;
        github-actions-expo-boiler-template
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Expo working together with GitHub Actions starter&lt;/h1&gt;
&lt;p&gt;This is the example explained in a dev.to post, more details will be available soon.&lt;/p&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/justussoh/github-actions-expo-boiler-template"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>expo</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Using GitHub Actions to seamlessly deploy Expo applications (Part 1)</title>
      <dc:creator>Justus Soh</dc:creator>
      <pubDate>Sun, 23 Aug 2020 12:53:57 +0000</pubDate>
      <link>https://forem.com/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-1-3jfb</link>
      <guid>https://forem.com/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-1-3jfb</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;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). &lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find time to do a release&lt;/li&gt;
&lt;li&gt;Publish the changes to a staging channel&lt;/li&gt;
&lt;li&gt;Test that staging functionality is working&lt;/li&gt;
&lt;li&gt;Build the application using Expo's instance of turtle Cli&lt;/li&gt;
&lt;li&gt;Wait 30 minutes for each app binary to complete (iOS and Android)&lt;/li&gt;
&lt;li&gt;Uploading of files to the Testflight/Google store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;An integrated solution&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Expo also offers a &lt;a href="https://github.com/expo/expo-github-action" rel="noopener noreferrer"&gt;GitHub action tool&lt;/a&gt; called &lt;code&gt;expo/expo-github-action&lt;/code&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Setting up Expo deployments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before we get started, we need to &lt;a href="https://expo.io/signup" rel="noopener noreferrer"&gt;sign up for an Expo account&lt;/a&gt; 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 &lt;code&gt;EXPO_CLI_USERNAME&lt;/code&gt; and &lt;code&gt;EXPO_CLI_PASSWORD&lt;/code&gt; variables. You can find out &lt;a href="https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository" rel="noopener noreferrer"&gt;how to store secrets on the GitHub documentation site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://docs.expo.io/distribution/uploading-apps" rel="noopener noreferrer"&gt;here on the Expo site&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Running Unit Test and Linting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;To begin we first have to make a &lt;code&gt;.github/workflows&lt;/code&gt; directory where we will be storing all our workflows.&lt;/p&gt;

&lt;p&gt;We can use the following example as a boiler template to perform our test automatically on each pull request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;name: Deploy Branch Preview

on: &lt;span class="o"&gt;[&lt;/span&gt;pull_request]

&lt;span class="nb"&gt;jobs&lt;/span&gt;:
  &lt;span class="nb"&gt;test&lt;/span&gt;:
    name: Lint &amp;amp; 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
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          cache-name: cache-node-modules
        with:
          &lt;span class="c"&gt;# npm cache files are stored in `~/.npm` on Linux/macOS&lt;/span&gt;
          path: ~/.npm
          key: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-build-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.cache-name &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ hashFiles(&lt;/span&gt;&lt;span class="s1"&gt;'**/package-lock.json'&lt;/span&gt;&lt;span class="p"&gt;) &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          restore-keys: |
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-build-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.cache-name &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;-   
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-build-&lt;/span&gt; 
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;-
      - name: Install Packages
        run: npm &lt;span class="nb"&gt;install&lt;/span&gt;
      &lt;span class="c"&gt;# Peform a type check if you are using typescript&lt;/span&gt;
      - name: Typecheck
        run: npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; tsc &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
      - name: Check Lint
        run: npm run lint
      - name: Test
        run: npm run &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;The repo link can be found at the bottom of the article&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Automated PR deployments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The following piece of code is a job to publish a release for a PR review on the Exponent server:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  deploy_branch_preview:
    name: Deploy Branch Preview
    needs: &lt;span class="nb"&gt;test
    &lt;/span&gt;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: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.EXPO_CLI_USERNAME &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          expo-password: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.EXPO_CLI_PASSWORD &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          expo-cache: &lt;span class="nb"&gt;true&lt;/span&gt;
      - name: Cache Node Modules
        uses: actions/cache@v2
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          cache-name: cache-node-modules
        with:
          path: ~/.npm
          key: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-build-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.cache-name &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ hashFiles(&lt;/span&gt;&lt;span class="s1"&gt;'**/package-lock.json'&lt;/span&gt;&lt;span class="p"&gt;) &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          restore-keys: |
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-build-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.cache-name &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;-
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-build-&lt;/span&gt;
            &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ runner.os &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;-
      - name: Install Packages
        run: npm &lt;span class="nb"&gt;install&lt;/span&gt;
      - name: Expo Publish Channel
        run: expo publish &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; &lt;span class="nt"&gt;--release-channel&lt;/span&gt; &lt;span class="nb"&gt;pr&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.event.number &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
      - name: Add Comment To PR
        uses: mshick/add-pr-comment@v1
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          GITHUB_TOKEN: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GITHUB_TOKEN &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          EXPO_PROJECT: &lt;span class="s2"&gt;"@justussoh/github-actions-expo-boiler-template"&lt;/span&gt; &lt;span class="c"&gt;# Put in your own Expo project name here&lt;/span&gt;
        with:
          message: |
            &lt;span class="c"&gt;## Application&lt;/span&gt;
            &lt;span class="o"&gt;![&lt;/span&gt;Expo QR]&lt;span class="o"&gt;(&lt;/span&gt;https://api.qrserver.com/v1/create-qr-code/?size&lt;span class="o"&gt;=&lt;/span&gt;250x250&amp;amp;data&lt;span class="o"&gt;=&lt;/span&gt;exp://exp.host/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.EXPO_PROJECT &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;?release-channel&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;pr&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.event.number &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
            Published to https://exp.host/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ env.EXPO_PROJECT &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;?release-channel&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;pr&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.event.number &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;The repo link can be found at the bottom of the article&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;You can the application via scanning the QR code with your Expo client application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg8yscc5zi8dlr3m35csy.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg8yscc5zi8dlr3m35csy.PNG" alt="QR"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Publishing to a staging environment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The code will be relatively similar to the PR actions, therefore I will link the file &lt;a href="https://github.com/justussoh/github-actions-expo-boiler-template/pull/2#issuecomment-675628863" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;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 &lt;a href="https://dev.to/justussoh/using-github-actions-to-seamlessly-deploy-expo-applications-part-2-57mi"&gt;part 2&lt;/a&gt; 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.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/justussoh" rel="noopener noreferrer"&gt;
        justussoh
      &lt;/a&gt; / &lt;a href="https://github.com/justussoh/github-actions-expo-boiler-template" rel="noopener noreferrer"&gt;
        github-actions-expo-boiler-template
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Expo working together with GitHub Actions starter&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;This is the example explained in a dev.to post, more details will be available soon.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/justussoh/github-actions-expo-boiler-template" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>expo</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
