prescottprue/fireadmin

View on GitHub
.github/workflows/app-verify.yml

Summary

Maintainability
Test Coverage
name: Verify App

on: 
  pull_request:
    paths-ignore:
      - 'docs/**'

jobs:
  verify-build:
    name: Verify + Build
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Cancel Previous Runs
        uses: styfle/cancel-workflow-action@0.9.0
        with:
          access_token: ${{ github.token }}

      - name: Checkout Repo
        uses: actions/checkout@v2

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

      - name: Get cache settings
        id: cache-settings
        run: |
          echo "::set-output name=dir::$(yarn cache dir)"
          echo "::set-output name=firebase-tools::$(yarn list -s --depth=0 --pattern firebase-tools | tail -n 1 | sed 's/.*@//g')"

      - name: Get Yarn Cache
        id: yarn-cache
        run: echo "::set-output name=dir::$(yarn cache dir)"

      - name: Cache NPM Dependencies
        uses: actions/cache@v2.1.6
        with:
          path: ${{ steps.yarn-cache.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}

      - name: Install Dependencies
        env:
          CYPRESS_INSTALL_BINARY: 0 # Skip installing of cypress
        run: |
          yarn install --frozen-lockfile
          yarn --cwd functions install --frozen-lockfile

      - name: Verify Functions
        # NOTE: Project name is hardcoded since emulators are being used
        run: |
          yarn functions:build
          yarn --cwd functions test:cov

      - name: Upload Functions Test Coverage
        uses: codecov/codecov-action@v1
        with:
          file: functions/coverage/lcov.info

      - name: Verify
        run: yarn lint

      - name: Expose Application Environment Variables
        env:
          GITHUB_REF: ${{ github.ref }}
          # Firebase token needed to authenticate firebase-tools to be able to load app configs
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
        run: |
          set -o pipefail

          gitBranch=${GITHUB_REF##*/}

          # Find the config associated to the firebase project in .firebaserc
          gcloudProject=$(cat .firebaserc | jq -r --arg alias "$gitBranch" '.projects[$alias]  // .projects.default')
          echo "GCLOUD_PROJECT=$gcloudProject" >> $GITHUB_ENV

          # Set other app configs (settings within .firebaserc in the ci.setEnv section)
          config=$(cat .firebaserc | jq -r --arg alias "$gitBranch" '.ci.setEnv[$alias] // .ci.setEnv.master')
          echo "REACT_APP_FIREADMIN_ENV=$(echo $config | jq -r '.REACT_APP_FIREADMIN_ENV')" >> $GITHUB_ENV
          echo "REACT_APP_SEGMENT_ID=$(echo $config | jq -r '.REACT_APP_SEGMENT_ID')" >> $GITHUB_ENV
          echo "REACT_APP_SENTRY_DSN=$(echo $config | jq -r '.REACT_APP_SENTRY_DSN')" >> $GITHUB_ENV
          echo "REACT_APP_PUBLIC_VAPID_KEY=$(echo $config | jq -r '.REACT_APP_PUBLIC_VAPID_KEY')" >> $GITHUB_ENV
          echo "REACT_APP_ALGOLIA_APP_ID=$(echo $config | jq -r '.REACT_APP_ALGOLIA_APP_ID')" >> $GITHUB_ENV
          echo "REACT_APP_ALGOLIA_API_KEY=$(echo $config | jq -r '.REACT_APP_ALGOLIA_API_KEY')" >> $GITHUB_ENV

          # Set emulator settings
          echo "REACT_APP_FIREBASE_DATABASE_EMULATOR_HOST=localhost:$(cat firebase.json | jq .emulators.database.port)" >> $GITHUB_ENV
          echo "REACT_APP_FIRESTORE_EMULATOR_HOST=localhost:$(cat firebase.json | jq .emulators.firestore.port)" >> $GITHUB_ENV

      - name: Generate Firebase SDK config for ${{ env.GCLOUD_PROJECT }}
        # Skip for forks (since they don't have access to secrets)
        if: github.event.pull_request.head.repo.full_name == github.repository
        env:
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
        run: |
          set -o pipefail

          # Throw a clear error if FIREBASE_TOKEN secret is not set
          if [ -z "$FIREBASE_TOKEN" ];
            then
              missingTokenErrMsg="\"FIREBASE_TOKEN\" github secret is required to load project configuration. Visit https://github.com/${{ github.repository }}/settings/secrets to set."
              echo "::error ::$missingTokenErrMsg"
              exit 1
          fi

          bin/generate-firebase-sdk-config.js --outputEnv >> .env

      - name: Print CI Env Variables
        run: |
          echo Available ENV vars:
          env | sort

      - name: Build App
        run: |
          yarn build

      - name: Archive Error Logs
        uses: actions/upload-artifact@v2
        if: failure()
        with:
          name: error-logs
          path: yarn-error.log

      - name: Archive Build Artifact
        uses: actions/upload-artifact@v2
        with:
          name: build
          path: build

  ui-tests:
    name: UI Test Emulated App
    needs: verify-build
    runs-on: ubuntu-20.04
    timeout-minutes: 20
    strategy:
      # Keep all in-progress jobs running if any matrix job fails. Needed to prevent
      # the Cypress Dashboard from being stuck in "in progress" state since not all tests run.
      # See the following for more details:
      # * Cypress Action Issue: https://github.com/cypress-io/github-action/issues/48
      # * Docs for fail-fast: https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategyfail-fast
      fail-fast: false
      matrix:
        # Run multiple copies of the current job in parallel
        containers: [1, 2, 3, 4]
    steps:
      - name: Setup Node
        uses: actions/setup-node@v2.2.0
        with:
          node-version: 14

      - name: Checkout Repo
        uses: actions/checkout@v2

      - name: Get Cache Settings
        id: cache-settings
        run: |
          echo "::set-output name=firebase-tools::$(yarn list -s --depth=0 --pattern firebase-tools | tail -n 1 | sed 's/.*@//g')"

      - name: Cache Firebase Emulator Binaries
        uses: actions/cache@v2.1.6
        with:
          path: ~/.cache/firebase/emulators
          key: ${{ runner.os }}-firebase-${{ steps.cache-settings.outputs.firebase-tools }}

      - name: Set Test Environment Settings
        env:
          GITHUB_REF: ${{ github.ref }}
          SKIP_CYPRESS_RECORDING: ${{ secrets.SKIP_CYPRESS_RECORDING }}
        run: |
          gitBranch=${GITHUB_REF##*/}
          gcloudProject=$(cat .firebaserc | jq -r --arg branch "$gitBranch" '.projects[$branch] // .projects.master')
          
          echo "Exposing settings to environment for branch: $gitBranch and project: $gcloudProject..."
          echo "GCLOUD_PROJECT=$gcloudProject" >> $GITHUB_ENV
          echo "FIREBASE_DATABASE_EMULATOR_HOST=localhost:$(cat firebase.json | jq .emulators.database.port)" >> $GITHUB_ENV
          echo "FIRESTORE_EMULATOR_HOST=localhost:$(cat firebase.json | jq .emulators.firestore.port)" >> $GITHUB_ENV
          echo "CYPRESS_BASE_URL=http://localhost:$(cat package.json | jq .config.port)" >> $GITHUB_ENV
          
          echo "Generating Service Account File..."
          echo "$(echo $SERVICE_ACCOUNT | jq .)" > $HOME/serviceAccount.json
          echo "GOOGLE_APPLICATION_CREDENTIALS=$HOME/serviceAccount.json" >> $GITHUB_ENV

      - name: Print CI Env Variables
        run: |
          echo Available ENV vars:
          env | sort

      - name: Download Build Artifact
        uses: actions/download-artifact@v2
        with:
          name: build
          path: build

      # Cypress action manages installing/caching npm dependencies and Cypress binary.
      # Because of "record" and "parallel" parameters these containers will load
      # balance all found tests among themselves. The step tests a version of the app
      # which is running locally in the container on port 3000
      - name: Cypress Run
        uses: cypress-io/github-action@v2
        with:
          browser: chrome
          parallel: true
          record: true
          headless: true
          group: 'UI Integration Tests'
          tag: emulated
          start: yarn emulators:no-functions --project ${{ env.GCLOUD_PROJECT }}
          wait-on: ${{ env.CYPRESS_BASE_URL }}
          wait-on-timeout: 120
        env:
          TZ: America/Los_Angeles
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_KEY }}
          GITHUB_HEAD_REF: ${{ github.head_ref }}
          GITHUB_REF: ${{ github.ref }}
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
          SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}
          CYPRESS_TEST_UID: ${{ secrets.TEST_UID }}