{
  "attachments": [
    "./shaven_yak.png",
    "./GitHub Actions for Didthis - storybook.png",
    "./GitHub Actions for Didthis - commit status checks.png",
    "GitHub Actions for Didthis - expo updates.png",
    "IMG_5002.PNG",
    "GitHub Actions for Didthis - QR codes.png",
    "${{ steps.preview.outputs.qr }}"
  ],
  "title": "I like automations for inclusive development",
  "tags": [
    "didthis",
    "github",
    "githubactions",
    "mobile",
    "webdev"
  ],
  "year": "2024",
  "month": "03",
  "day": "13",
  "isDir": true,
  "slug": "github-actions-for-didthis",
  "type": "entry",
  "date": "2024-03-13T19:00:00.000Z",
  "postName": "2024-03-13-github-actions-for-didthis",
  "html": "<p><strong>TL;DR</strong>: I like deploying robots to include more of the team in our core development loop</p>\n<!--more-->\n\n\n\n<p>Although it's very dangerously close to <a href=\"https://blog.lmorchard.com/2016/08/31/yak-shaving-habits/\">Yak Shaving</a>, a thing I really enjoy doing is taking a dive deep into tools &amp; automations for a project at work. In a job interview, I'd tell you that's because I learned the value of being a \"force multiplier\" from <a href=\"https://dougengelbart.org/content/view/192/\">Douglas Engelbart's ABCs of Organizational Improvement</a>.</p>\n<figure class=\"inset right\">\n  <img src=\"./shaven_yak.png\" width=\"\" height=\"\">\n  <figcaption>A photo of my Shaven Yak figurine from Ren &amp; Stimpy</figcaption>\n</figure>\n\n<p>And, while that's not untrue, I also like <a href=\"https://en.wikipedia.org/wiki/Rube_Goldberg_machine\">Rube Goldberg machines</a> that tell me I did a good job - especially if there are great big green checkmarks involved. ✅</p>\n<h2 id=\"empowering-teammates-with-robots\">Empowering teammates with robots</h2>\n<p>Besides getting praise from robots 🤖, I also like deploying them in systems to include more of the team in our core development loop.</p>\n<p>For example, in web development, an evergreen problem is where you have to run the whole stack on your laptop just to get a look at work in progress.</p>\n<p>But, there are usually other folks on the team who <em>don't</em> primarily code or fuss with servers for a living - e.g. product managers, designers, writers, researchers, et al. I'd like to empower these folks to help contribute to the development process just as easily as any coder.</p>\n<h2 id=\"storybook\">Storybook</h2>\n<p>A lightweight tool I've used toward this end is <a href=\"https://storybook.js.org/\">Storybook</a>. It helps you build a browsable catalog of pre-defined scenarios for web UI components - kind of a cross between unit tests and a style guide.</p>\n<figure class=\"fullwidth\">\n  <img src=\"./GitHub Actions for Didthis - storybook.png\" width=\"\" height=\"\">\n  <figcaption>A screenshot of <a href=\"https://storybook.js.org/\">Storybook</a></figcaption>\n</figure>\n\n<p>The catch is that it only really exercises the client-side frontend, in isolation from the server-side backend. Still, you can mock up scenarios which might be accessible only through tediously arranged circumstances on the full application stack.</p>\n<p>The neat trick, though, is that Storybook can <a href=\"https://storybook.js.org/docs/sharing/publish-storybook#build-storybook-as-a-static-web-application\">generate a static web site</a>. That's inevitably cheaper to deploy and keep available than a full replica of a live production environment. In fact, it's so cheap that I've built GitHub Actions workflows to publish Storybook snapshots to GitHub Pages for every commit in a busy project and the system never broke a sweat.</p>\n<p>Here's an example workflow from one of my work projects, which builds a Storybook snapshot and publishes it to GitHub Pages for a subset of branches. The only real hacky part is hitting the GitHub API to derive the base URL for the project's GitHub Pages site, but the rest is straightforward:</p>\n<pre><code class=\"language-yaml\">name: \"Build &amp; Deploy Storybook\"\non:\n  push:\n    branches:\n      - 'main'\n      - 'preview/**'\npermissions:\n  contents: write\n  checks: write\n  pages: write\n  statuses: write\njobs:\n  storybook:\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: appserver\n    steps:\n      - uses: actions/checkout@v3\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: \"lts/*\"\n          cache: \"yarn\"\n          cache-dependency-path: \"appserver/yarn.lock\"\n      - name: Install Dependencies\n        run: yarn install\n      - name: Build Storybook\n        run: yarn build-storybook\n      - name: Deploy Storybook\n        uses: JamesIves/github-pages-deploy-action@v4\n        with:\n          folder: appserver/storybook-static\n          target-folder: storybooks/${{ github.head_ref || github.ref_name }}/\n      - name: Get Github Pages Base URL\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          githubPagesUrl=\"$(gh api \"repos/$GITHUB_REPOSITORY/pages\" --jq '.html_url')\"\n          echo 'GITHUB_PAGES_URL='$githubPagesUrl &gt;&gt; $GITHUB_ENV\n      - name: Create Status Check\n        uses: Sibz/github-status-action@v1\n        with:\n          authToken: ${{ secrets.GITHUB_TOKEN }}\n          sha: ${{ github.event.pull_request.head.sha || github.sha }}\n          state: 'success'\n          context: 'Storybook Deployment'\n          description: 'Storybook Deployment for ${{ github.head_ref || github.ref_name }}'\n          target_url: '${{ env.GITHUB_PAGES_URL }}storybooks/${{ github.head_ref || github.ref_name }}/index.html'\n</code></pre>\n<p>The great thing about a workflow like this is every commit maps to a URL with a preview of the work. Here, that's used to set a <a href=\"https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks\">GitHub Status Check</a> result for the commit.</p>\n<p>So, anyone on the team with a browser can click the \"Details\" link to preview the work and chime in with review comments. (By the way, have you clicked on the little green checkmark for a commit in GitHub? Lots of interesting info behind there.)</p>\n<img src=\"./GitHub Actions for Didthis - commit status checks.png\" width=\"\" height=\"\">\n\n<h2 id=\"react-native-and-expo\">React Native and Expo</h2>\n<p>So, that's all fine for web applications - but what about mobile apps? This came up for me last Fall, when our team decided to pivot from a web-based experience to <a href=\"https://apps.apple.com/us/app/mozilla-didthis/id6468680088\">an installable iOS app in the Store</a>.</p>\n<p>In building this app, I chose to go with <a href=\"https://reactnative.dev/\">React Native</a> and <a href=\"https://docs.expo.dev/\">Expo</a> as the foundation. This seemed like a good idea <a href=\"https://blog.lmorchard.com/2015/07/22/react-multiplatform/\">to further leverage our React chops</a> and <a href=\"https://blog.lmorchard.com/2015/09/21/react-native-android/\">maybe even reuse some code</a>.</p>\n<p>One of the things I've found frustrating is getting development builds onto teammates' devices on a regular cadence. Apple and Google both have mechanisms for installing in-progress app builds, but they have their quirks &amp; limitations.</p>\n<p>Building atop React Native, though, <a href=\"https://docs.expo.dev/eas-update/how-it-works/\">Expo Updates</a> offers some particular architectural advantages:</p>\n<figure>\n  <img src=\"GitHub Actions for Didthis - expo updates.png\" width=\"\" height=\"\">\n  <figcaption>A diagram showing <a href=\"https://docs.expo.dev/eas-update/how-it-works/\">the native and update layers of an Expo App</a></figcaption>\n</figure>\n\n<p>One half of an Expo app is a native runtime shell that hosts the JavaScript engine and bindings to native capabilities. The other half is a bundle of JavaScript and application assets executed by the runtime shell. The runtime shell is least likely to change.</p>\n<p>So, Expo Updates makes it easy to swap in fresh revisions of the application bundle without having to rebuild the whole application - i.e. <a href=\"https://docs.expo.dev/eas-update/how-it-works/#publishing-an-update\">\"Over the Air\" updates</a>. Since it fetches these bundles via URL from the web, that makes deploying new bundles <em>almost</em> as easy as updating a static web site.</p>\n<p>Maybe you can see where I'm going with this?</p>\n<h2 id=\"expo-go-and-storybook\">Expo Go and Storybook</h2>\n<figure class=\"inset right\">\n  <img src=\"IMG_5002.PNG\" width=\"\" height=\"\">\n  <figcaption>A screenshot of Expo Go on my iPhone running a Storybook build</figcaption>\n</figure>\n\n<p>Relatedly, <a href=\"https://docs.expo.dev/get-started/expo-go/\">Expo Go</a> is a fun utility app in this ecosystem: Since many apps use a common subset of native capabilities, it's reasonable to build a big, common kitchen-sink runtime that supports most of what you might want to use in an app.</p>\n<p>You wouldn't really want to distribute your app with this runtime, per se. But, if you squint a certain way, Expo Go looks like a peculiar kind of web browser - it lets your device load application code on demand via URL or QR code.</p>\n<p>And, as it turns out, <a href=\"https://storybook.js.org/tutorials/intro-to-storybook/react-native/en/get-started/\">Storybook also supports React Native</a>. It provides a pre-built component that renders the browsable catalog of application scenarios right on your device. From there, you can change the component used as the entry point via an environment variable during build.</p>\n<h2 id=\"expo-application-services-and-github-actions\">Expo Application Services and GitHub Actions</h2>\n<p>Putting this all together led me to another set of GitHub Actions - I can build <em>two</em> app bundles for every commit: One builds the app proper, while the other builds it in Storybook mode.</p>\n<p>Rather than publishing to GitHub Pages, though, these workflows take advantage of <a href=\"https://expo.dev/eas\">Expo Application Services</a> (or EAS). There's a lot more to it but, in a nutshell, you can use EAS to host application bundles at unique URLs tagged with various bits of metadata useful for over-the-air updates.</p>\n<p>The really neat part, though, is that you can get a QR code for each application bundle uploaded to EAS. And that, in turn, can be automatically posted as a comment in a Pull Request - thus making it easy for any teammate to point their phone's camera at the PR to preview the work-in-progress using Expo Go! </p>\n<p>Here's what that looks like in a Pull Request:</p>\n<figure>\n  <img src=\"GitHub Actions for Didthis - QR codes.png\" width=\"\" height=\"\">\n  <figcaption>Screenshot of a GitHub Pull Request with QR codes for Expo Go in comments</figcaption>\n</figure>\n\n<p>These QR codes might even work for you, if you install Expo Go on your own device. Since <a href=\"https://apps.apple.com/us/app/mozilla-didthis/id6468680088\">the app's already released</a>, I don't think I'm revealing any secrets by including these.</p>\n<p>Your mileage may vary, though, by the time you read this. Our server-side APIs may have moved on from compatibility with this particular app build, or the builds may eventually get garbage collected from the EAS servers.</p>\n<p>Here's a peek at the GitHub Actions workflow for building the normal application bundle:</p>\n<pre><code class=\"language-yaml\">name: \"Build Expo Preview for PR\"\non:\n  pull_request:\njobs:\n  tests:\n    uses: ./.github/workflows/tests.yml\n  preview:\n    needs: tests\n    permissions:\n      contents: read\n      pull-requests: write # Allow comments on PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🏗 Setup repo\n        uses: actions/checkout@v3\n      - name: 🏗 Setup Node\n        uses: actions/setup-node@v3\n        with:\n          node-version: 18.x\n          cache: yarn\n      - name: 🏗 Setup EAS\n        uses: expo/expo-github-action@v8\n        with:\n          eas-version: latest\n          token: ${{ secrets.EXPO_TOKEN }}\n      - name: 📦 Install dependencies\n        run: yarn install\n      - name: 🚀 Create preview\n        id: preview\n        env:\n          EXPO_PUBLIC_GIT_TAG: ${{ github.sha }}\n        uses: expo/expo-github-action/preview@v8\n        with:\n          command: eas update --auto --branch=pr-${{ github.event.number }}\n          comment: false\n      - name: Comment PR\n        uses: thollander/actions-comment-pull-request@v2\n        with:\n          comment_tag: preview-app-build\n          message: |\n            🚀 **App** [preview update](${{ steps.preview.outputs.link }}) is ready for use with [Expo Go](https://expo.dev/expo-go):\n\n            &lt;a href=\"${{ steps.preview.outputs.link }}\"&gt;&lt;img src=\"${{ steps.preview.outputs.qr }}\" width=\"250px\" height=\"250px\" /&gt;&lt;/a&gt;\n</code></pre>\n<p>And, here's the YAML for the Storybook workflow:</p>\n<pre><code class=\"language-yaml\">name: \"Build Expo Storybook for PR\"\non:\n  pull_request:\nenv:\n  EXPO_PUBLIC_STORYBOOK_ENABLED: true\njobs:\n  tests:\n    uses: ./.github/workflows/tests.yml\n  preview:\n    needs: tests\n    permissions:\n      contents: read\n      pull-requests: write # Allow comments on PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🏗 Setup repo\n        uses: actions/checkout@v3\n      - name: 🏗 Setup Node\n        uses: actions/setup-node@v3\n        with:\n          node-version: 18.x\n          cache: yarn\n      - name: 🏗 Setup EAS\n        uses: expo/expo-github-action@v8\n        with:\n          eas-version: latest\n          token: ${{ secrets.EXPO_TOKEN }}\n      - name: 📦 Install dependencies\n        run: yarn install\n      - name: 🚀 Create preview\n        id: preview\n        uses: expo/expo-github-action/preview@v8\n        with:\n          command: eas update --auto --branch=pr-${{ github.event.number }}-storybook\n          comment: false\n      - name: Comment PR\n        uses: thollander/actions-comment-pull-request@v2\n        with:\n          comment_tag: preview-storybook-build\n          message: |\n            📓 **Storybook** [preview update](${{ steps.preview.outputs.link }}) is ready for use with [Expo Go](https://expo.dev/expo-go):\n\n            &lt;a href=\"${{ steps.preview.outputs.link }}\"&gt;&lt;img src=\"${{ steps.preview.outputs.qr }}\" width=\"250px\" height=\"250px\" /&gt;&lt;/a&gt;\n</code></pre>\n<p>You can see that these workflows are essentially identical - except for some unique IDs and flipping the <code>EXPO_PUBLIC_STORYBOOK_ENABLED</code> variable to <code>true</code> during the Storybook build.</p>\n<p>Also, using the <code>comment_tag</code> option of the <a href=\"https://github.com/thollander/actions-comment-pull-request\"><code>thollander/actions-comment-pull-request@v2</code></a> step with distinct values (e.g. <code>preview-app-build</code> vs <code>preview-storybook-build</code>) means the workflow will edit those existing comments on subsequent builds - rather than posting new comments every time.</p>\n<p>The end result of these workflows were that, all along the journey of getting this app ready for <a href=\"https://apps.apple.com/us/app/mozilla-didthis/id6468680088\">an App Store release</a>, everyone on the team with an iPhone could scan a QR code to pull up a preview of any branch in progress and chime in with comments and suggestions. We also got a lot of early bug reports, since everyone on the team had a slightly different device model with fun edge cases to exercise.</p>\n<h2 id=\"summing-up\">Summing up</h2>\n<p>The central notion is that I like making it easier to include the whole team in review cycles during feature development. It doesn't even have to be that hard - the implementations I describe here were mainly just hacking and gluing things together. It can be quick &amp; dirty, but the payoff can be huge for empowering everyone to contribute.</p>\n",
  "body": "**TL;DR**: I like deploying robots to include more of the team in our core development loop\n\n<!--more-->\n\nAlthough it's very dangerously close to [Yak Shaving](https://blog.lmorchard.com/2016/08/31/yak-shaving-habits/), a thing I really enjoy doing is taking a dive deep into tools & automations for a project at work. In a job interview, I'd tell you that's because I learned the value of being a \"force multiplier\" from [Douglas Engelbart's ABCs of Organizational Improvement](https://dougengelbart.org/content/view/192/).\n\n<figure class=\"inset right\">\n  <img src=\"./shaven_yak.png\">\n  <figcaption>A photo of my Shaven Yak figurine from Ren & Stimpy</figcaption>\n</figure>\n\nAnd, while that's not untrue, I also like [Rube Goldberg machines](https://en.wikipedia.org/wiki/Rube_Goldberg_machine) that tell me I did a good job - especially if there are great big green checkmarks involved. ✅\n\n## Empowering teammates with robots\n\nBesides getting praise from robots 🤖, I also like deploying them in systems to include more of the team in our core development loop.\n\nFor example, in web development, an evergreen problem is where you have to run the whole stack on your laptop just to get a look at work in progress.\n\nBut, there are usually other folks on the team who *don't* primarily code or fuss with servers for a living - e.g. product managers, designers, writers, researchers, et al. I'd like to empower these folks to help contribute to the development process just as easily as any coder.\n\n## Storybook\n\nA lightweight tool I've used toward this end is [Storybook](https://storybook.js.org/). It helps you build a browsable catalog of pre-defined scenarios for web UI components - kind of a cross between unit tests and a style guide.\n\n<figure class=\"fullwidth\">\n  <img src=\"./GitHub Actions for Didthis - storybook.png\" />\n  <figcaption>A screenshot of <a href=\"https://storybook.js.org/\">Storybook</a></figcaption>\n</figure>\n\nThe catch is that it only really exercises the client-side frontend, in isolation from the server-side backend. Still, you can mock up scenarios which might be accessible only through tediously arranged circumstances on the full application stack.\n\nThe neat trick, though, is that Storybook can [generate a static web site](https://storybook.js.org/docs/sharing/publish-storybook#build-storybook-as-a-static-web-application). That's inevitably cheaper to deploy and keep available than a full replica of a live production environment. In fact, it's so cheap that I've built GitHub Actions workflows to publish Storybook snapshots to GitHub Pages for every commit in a busy project and the system never broke a sweat.\n\nHere's an example workflow from one of my work projects, which builds a Storybook snapshot and publishes it to GitHub Pages for a subset of branches. The only real hacky part is hitting the GitHub API to derive the base URL for the project's GitHub Pages site, but the rest is straightforward:\n\n```yaml\nname: \"Build & Deploy Storybook\"\non:\n  push:\n    branches:\n      - 'main'\n      - 'preview/**'\npermissions:\n  contents: write\n  checks: write\n  pages: write\n  statuses: write\njobs:\n  storybook:\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: appserver\n    steps:\n      - uses: actions/checkout@v3\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: \"lts/*\"\n          cache: \"yarn\"\n          cache-dependency-path: \"appserver/yarn.lock\"\n      - name: Install Dependencies\n        run: yarn install\n      - name: Build Storybook\n        run: yarn build-storybook\n      - name: Deploy Storybook\n        uses: JamesIves/github-pages-deploy-action@v4\n        with:\n          folder: appserver/storybook-static\n          target-folder: storybooks/${{ github.head_ref || github.ref_name }}/\n      - name: Get Github Pages Base URL\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          githubPagesUrl=\"$(gh api \"repos/$GITHUB_REPOSITORY/pages\" --jq '.html_url')\"\n          echo 'GITHUB_PAGES_URL='$githubPagesUrl >> $GITHUB_ENV\n      - name: Create Status Check\n        uses: Sibz/github-status-action@v1\n        with:\n          authToken: ${{ secrets.GITHUB_TOKEN }}\n          sha: ${{ github.event.pull_request.head.sha || github.sha }}\n          state: 'success'\n          context: 'Storybook Deployment'\n          description: 'Storybook Deployment for ${{ github.head_ref || github.ref_name }}'\n          target_url: '${{ env.GITHUB_PAGES_URL }}storybooks/${{ github.head_ref || github.ref_name }}/index.html'\n```\n\nThe great thing about a workflow like this is every commit maps to a URL with a preview of the work. Here, that's used to set a [GitHub Status Check](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks) result for the commit.\n\nSo, anyone on the team with a browser can click the \"Details\" link to preview the work and chime in with review comments. (By the way, have you clicked on the little green checkmark for a commit in GitHub? Lots of interesting info behind there.)\n\n<img src=\"./GitHub Actions for Didthis - commit status checks.png\" />\n\n## React Native and Expo\n\nSo, that's all fine for web applications - but what about mobile apps? This came up for me last Fall, when our team decided to pivot from a web-based experience to [an installable iOS app in the Store](https://apps.apple.com/us/app/mozilla-didthis/id6468680088).\n\nIn building this app, I chose to go with [React Native](https://reactnative.dev/) and [Expo](https://docs.expo.dev/) as the foundation. This seemed like a good idea [to further leverage our React chops](https://blog.lmorchard.com/2015/07/22/react-multiplatform/) and [maybe even reuse some code](https://blog.lmorchard.com/2015/09/21/react-native-android/).\n\nOne of the things I've found frustrating is getting development builds onto teammates' devices on a regular cadence. Apple and Google both have mechanisms for installing in-progress app builds, but they have their quirks & limitations.\n\nBuilding atop React Native, though, [Expo Updates](https://docs.expo.dev/eas-update/how-it-works/) offers some particular architectural advantages:\n\n<figure>\n  <img src=\"GitHub Actions for Didthis - expo updates.png\" />\n  <figcaption>A diagram showing <a href=\"https://docs.expo.dev/eas-update/how-it-works/\">the native and update layers of an Expo App</a></figcaption>\n</figure>\n\nOne half of an Expo app is a native runtime shell that hosts the JavaScript engine and bindings to native capabilities. The other half is a bundle of JavaScript and application assets executed by the runtime shell. The runtime shell is least likely to change.\n\nSo, Expo Updates makes it easy to swap in fresh revisions of the application bundle without having to rebuild the whole application - i.e. [\"Over the Air\" updates](https://docs.expo.dev/eas-update/how-it-works/#publishing-an-update). Since it fetches these bundles via URL from the web, that makes deploying new bundles *almost* as easy as updating a static web site.\n\nMaybe you can see where I'm going with this?\n\n## Expo Go and Storybook\n\n<figure class=\"inset right\">\n  <img src=\"IMG_5002.PNG\" />\n  <figcaption>A screenshot of Expo Go on my iPhone running a Storybook build</figcaption>\n</figure>\n\nRelatedly, [Expo Go](https://docs.expo.dev/get-started/expo-go/) is a fun utility app in this ecosystem: Since many apps use a common subset of native capabilities, it's reasonable to build a big, common kitchen-sink runtime that supports most of what you might want to use in an app.\n\nYou wouldn't really want to distribute your app with this runtime, per se. But, if you squint a certain way, Expo Go looks like a peculiar kind of web browser - it lets your device load application code on demand via URL or QR code.\n\nAnd, as it turns out, [Storybook also supports React Native](https://storybook.js.org/tutorials/intro-to-storybook/react-native/en/get-started/). It provides a pre-built component that renders the browsable catalog of application scenarios right on your device. From there, you can change the component used as the entry point via an environment variable during build.\n\n## Expo Application Services and GitHub Actions\n\nPutting this all together led me to another set of GitHub Actions - I can build *two* app bundles for every commit: One builds the app proper, while the other builds it in Storybook mode.\n\nRather than publishing to GitHub Pages, though, these workflows take advantage of [Expo Application Services](https://expo.dev/eas) (or EAS). There's a lot more to it but, in a nutshell, you can use EAS to host application bundles at unique URLs tagged with various bits of metadata useful for over-the-air updates.\n\nThe really neat part, though, is that you can get a QR code for each application bundle uploaded to EAS. And that, in turn, can be automatically posted as a comment in a Pull Request - thus making it easy for any teammate to point their phone's camera at the PR to preview the work-in-progress using Expo Go! \n\nHere's what that looks like in a Pull Request:\n\n<figure>\n  <img src=\"GitHub Actions for Didthis - QR codes.png\" />\n  <figcaption>Screenshot of a GitHub Pull Request with QR codes for Expo Go in comments</figcaption>\n</figure>\n\nThese QR codes might even work for you, if you install Expo Go on your own device. Since [the app's already released](https://apps.apple.com/us/app/mozilla-didthis/id6468680088), I don't think I'm revealing any secrets by including these.\n\nYour mileage may vary, though, by the time you read this. Our server-side APIs may have moved on from compatibility with this particular app build, or the builds may eventually get garbage collected from the EAS servers.\n\nHere's a peek at the GitHub Actions workflow for building the normal application bundle:\n\n```yaml\nname: \"Build Expo Preview for PR\"\non:\n  pull_request:\njobs:\n  tests:\n    uses: ./.github/workflows/tests.yml\n  preview:\n    needs: tests\n    permissions:\n      contents: read\n      pull-requests: write # Allow comments on PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🏗 Setup repo\n        uses: actions/checkout@v3\n      - name: 🏗 Setup Node\n        uses: actions/setup-node@v3\n        with:\n          node-version: 18.x\n          cache: yarn\n      - name: 🏗 Setup EAS\n        uses: expo/expo-github-action@v8\n        with:\n          eas-version: latest\n          token: ${{ secrets.EXPO_TOKEN }}\n      - name: 📦 Install dependencies\n        run: yarn install\n      - name: 🚀 Create preview\n        id: preview\n        env:\n          EXPO_PUBLIC_GIT_TAG: ${{ github.sha }}\n        uses: expo/expo-github-action/preview@v8\n        with:\n          command: eas update --auto --branch=pr-${{ github.event.number }}\n          comment: false\n      - name: Comment PR\n        uses: thollander/actions-comment-pull-request@v2\n        with:\n          comment_tag: preview-app-build\n          message: |\n            🚀 **App** [preview update](${{ steps.preview.outputs.link }}) is ready for use with [Expo Go](https://expo.dev/expo-go):\n\n            <a href=\"${{ steps.preview.outputs.link }}\"><img src=\"${{ steps.preview.outputs.qr }}\" width=\"250px\" height=\"250px\" /></a>\n```\n\nAnd, here's the YAML for the Storybook workflow:\n\n```yaml\nname: \"Build Expo Storybook for PR\"\non:\n  pull_request:\nenv:\n  EXPO_PUBLIC_STORYBOOK_ENABLED: true\njobs:\n  tests:\n    uses: ./.github/workflows/tests.yml\n  preview:\n    needs: tests\n    permissions:\n      contents: read\n      pull-requests: write # Allow comments on PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: 🏗 Setup repo\n        uses: actions/checkout@v3\n      - name: 🏗 Setup Node\n        uses: actions/setup-node@v3\n        with:\n          node-version: 18.x\n          cache: yarn\n      - name: 🏗 Setup EAS\n        uses: expo/expo-github-action@v8\n        with:\n          eas-version: latest\n          token: ${{ secrets.EXPO_TOKEN }}\n      - name: 📦 Install dependencies\n        run: yarn install\n      - name: 🚀 Create preview\n        id: preview\n        uses: expo/expo-github-action/preview@v8\n        with:\n          command: eas update --auto --branch=pr-${{ github.event.number }}-storybook\n          comment: false\n      - name: Comment PR\n        uses: thollander/actions-comment-pull-request@v2\n        with:\n          comment_tag: preview-storybook-build\n          message: |\n            📓 **Storybook** [preview update](${{ steps.preview.outputs.link }}) is ready for use with [Expo Go](https://expo.dev/expo-go):\n\n            <a href=\"${{ steps.preview.outputs.link }}\"><img src=\"${{ steps.preview.outputs.qr }}\" width=\"250px\" height=\"250px\" /></a>\n```\n\nYou can see that these workflows are essentially identical - except for some unique IDs and flipping the `EXPO_PUBLIC_STORYBOOK_ENABLED` variable to `true` during the Storybook build.\n\nAlso, using the `comment_tag` option of the [`thollander/actions-comment-pull-request@v2`](https://github.com/thollander/actions-comment-pull-request) step with distinct values (e.g. `preview-app-build` vs `preview-storybook-build`) means the workflow will edit those existing comments on subsequent builds - rather than posting new comments every time.\n\nThe end result of these workflows were that, all along the journey of getting this app ready for [an App Store release](https://apps.apple.com/us/app/mozilla-didthis/id6468680088), everyone on the team with an iPhone could scan a QR code to pull up a preview of any branch in progress and chime in with comments and suggestions. We also got a lot of early bug reports, since everyone on the team had a slightly different device model with fun edge cases to exercise.\n\n## Summing up\n\nThe central notion is that I like making it easier to include the whole team in review cycles during feature development. It doesn't even have to be that hard - the implementations I describe here were mainly just hacking and gluing things together. It can be quick & dirty, but the payoff can be huge for empowering everyone to contribute.\n",
  "parentPath": "./content/posts/archives/2024/2024-03-13-github-actions-for-didthis",
  "path": "2024/03/13/github-actions-for-didthis",
  "thumbnail": "/2024/03/13/github-actions-for-didthis/shaven_yak.png",
  "summary": "TL;DR: I like deploying robots to include more of the team in our core development loop",
  "needsBuild": true,
  "prevPostPath": "2024/03/11/dance-for-the-bots",
  "prevPostTitle": "Dance like the bots aren't watching?",
  "nextPostPath": "2024/04/27/topic-clustering-gen-ai",
  "nextPostTitle": "Clustering ideas by topic with machine learning and generative AI"
}