UnlyEd/next-right-now

View on GitHub
.github/workflows/deploy-vercel-storybook.yml

Summary

Maintainability
Test Coverage
# Summary:
# Builds a static version of the Storybook website and triggers a new deployment on Vercel's platform, when anything is pushed in any branch.
#
# LEARN MORE AT https://unlyed.github.io/next-right-now/guides/ci-cd/
#
# Dependencies overview:
# - See https://github.com/actions/setup-node https://github.com/actions/setup-node/tree/v2
# - See https://github.com/actions/checkout https://github.com/actions/checkout/tree/v1
# - See https://github.com/actions/upload-artifact https://github.com/actions/upload-artifact/tree/v1
# - See https://github.com/rlespinasse/github-slug-action https://github.com/rlespinasse/github-slug-action/tree/3.x
# - See https://github.com/jwalton/gh-find-current-pr https://github.com/jwalton/gh-find-current-pr/tree/v1
# - See https://github.com/peter-evans/create-or-update-comment https://github.com/peter-evans/create-or-update-comment/tree/v1
# - See https://github.com/UnlyEd/github-action-await-vercel https://github.com/UnlyEd/github-action-await-vercel/tree/v1.1.1
# - See https://github.com/UnlyEd/github-action-store-variable https://github.com/UnlyEd/github-action-store-variable/tree/v2.1.1
# - See https://github.com/cypress-io/github-action https://github.com/cypress-io/github-action/tree/v2

name: Deploy Storybook static site to Vercel

on:
  # There are several ways to trigger Github actions - See https://help.github.com/en/actions/reference/events-that-trigger-workflows#example-using-a-single-event for a comprehensive list:
  # - "push": Triggers each time a commit is pushed
  # - "pull_request": Triggers each time a commit is pushed within a pull request, it makes it much easier to write comments within the PR, but it suffers some strong limitations:
  #   - There is no way to trigger when a PR is merged into another - See https://github.community/t/pull-request-action-does-not-run-on-merge/16092?u=vadorequest
  #   - It won't trigger when the PR is conflicting with its base branch - See https://github.community/t/run-actions-on-pull-requests-with-merge-conflicts/17104/2?u=vadorequest
  push: # Triggers on each pushed commit
    branches:
      - '*'

    # Runs the deployment workflow only when there are changes made to specific files, in any of the below paths
    # Optimizes our CI/CD by not deploying the Storybook static site needlessly (faster deploy, lower cost)
    # XXX Filter pattern cheat sheet https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
    paths:
      - '.github/workflows/deploy-vercel-storybook.yml'
      - '.storybook/**'
      - 'cypress/**'
      - '!cypress/_examples/**'
      - '!cypress/fixture/**'
      - '!cypress/integration/**'
      - '!cypress/config-*.json' # Exclude all config files
      - 'cypress/config-storybook.json' # Force include storybook config file
      - 'src/stories/**'
      - 'src/common/components/**'
      - 'src/**/components/**' # Any component in any "components" folder under "src". (e.g: "src/auth/components/comp1", "src/modules/core/auth/components/comp1", etc.)
      - '!src/app/components/*Bootstrap*' # Ignore bootstrap components, as they aren't used by Storybook
      - '*.js*' # Includes all .js/.json at the root level
      - '*.ts' # Includes all .ts at the root level
      - '.*ignore' # Includes .gitignore and .vercelignore
      - 'yarn.lock'
      - '!**/*.md' # Exclude all markdown files
      - 'stories/**/*.md' # Force include all markdown files within stories (because they're used for storybook)

env:
  STAGE: staging

jobs:
  # Configures the deployment environment, install dependencies (like node, npm, etc.) that are requirements for the upcoming jobs
  # Ex: Necessary to run `yarn deploy`
  setup-environment:
    name: Setup deployment environment (Ubuntu latest - Node 14.x)
    runs-on: ubuntu-latest
    steps:
      - name: Installing node.js
        uses: actions/setup-node@v2 # Used to install node environment - https://github.com/actions/setup-node
        with:
          node-version: '14.x' # Use the same node.js version as the one Vercel's uses (currently node14.x)

  # Starts a Vercel deployment, using the storybook configuration file
  # N.B: It's Vercel that will perform the actual deployment
  start-deployment:
    name: Starts Vercel deployment (Ubuntu latest)
    runs-on: ubuntu-latest
    timeout-minutes: 40 # Limit current job timeout https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes
    needs: setup-environment
    steps:
      - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout

      - name: Expose GitHub slug/short variables # See https://github.com/rlespinasse/github-slug-action#exposed-github-environment-variables
        uses: rlespinasse/github-slug-action@v3.x # See https://github.com/rlespinasse/github-slug-action

      # Create a GitHub deployment (within a GitHub environment), useful to keep a public track of all deployments directly in GitHub
      - name: Start GitHub deployment
        uses: bobheadxi/deployments@v0.4.3 # See https://github.com/bobheadxi/deployments
        id: start-github-deployment
        with:
          step: start
          token: ${{ secrets.GITHUB_TOKEN }}
          env: storybook # Uses "storybook" as GitHub environment name, because we don't need to manage multiple environments for storybook
          no_override: true # Disables auto marking previous environments as "inactive", as they're still active (Vercel deployments don't auto-deactivate) and it would remove the previous deployment links needlessly

      - name: Install storybook dependencies
        run: yarn install

      - name: Deploying on Vercel
        uses: UnlyEd/github-action-deploy-on-vercel@94d41ec1ff9b5b1de5256312e385632b6fcd8fa4 # Pin "v1.2.1" - See https://github.com/UnlyEd/github-action-deploy-on-vercel/commit/94d41ec1ff9b5b1de5256312e385632b6fcd8fa4
        with:
          command: "yarn deploy:sb:gha --token ${{ secrets.VERCEL_TOKEN }}"
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} # Passing github's secret to the worker
          # Passing exposed GitHub environment variables - See https://github.com/rlespinasse/github-slug-action#exposed-github-environment-variables
          GITHUB_REF_SLUG: ${{ env.GITHUB_REF_SLUG }}

      # Update the previously created GitHub deployment, and link it to our Vercel deployment
      - name: Link GitHub deployment to Vercel
        uses: bobheadxi/deployments@v0.4.3 # See https://github.com/bobheadxi/deployments
        id: link-github-deployment-to-vercel
        if: always()
        with:
          step: finish
          token: ${{ secrets.GITHUB_TOKEN }}
          status: ${{ job.status }}
          deployment_id: ${{ steps.start-github-deployment.outputs.deployment_id }}
          env_url: ${{ env.VERCEL_DEPLOYMENT_URL }} # Link the Vercel deployment url to the GitHub environment

      # We need to find the PR id. Will be used later to comment on that PR.
      - name: Finding Pull Request ID
        uses: jwalton/gh-find-current-pr@v1 # See https://github.com/jwalton/gh-find-current-pr
        id: pr_id_finder
        if: always() # It forces the job to be always executed, even if a previous job fail.
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

      # On deployment failure, add a comment to the PR, if there is an open PR for the current branch
      - name: Comment PR (Deployment failure)
        uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
        if: steps.pr_id_finder.outputs.number && failure()
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ steps.pr_id_finder.outputs.number }}
          body: |
            :x:  Deployment **FAILED**
            Commit ${{ github.sha }} failed to deploy **Storybook static site** to [${{ env.VERCEL_DEPLOYMENT_URL }}](${{ env.VERCEL_DEPLOYMENT_URL }})
            [click to see logs](https://github.com/UnlyEd/next-right-now/pull/${{ steps.pr_id_finder.outputs.number }}/checks)

      # On deployment success, add a comment to the PR, if there is an open PR for the current branch
      - name: Comment PR (Deployment success)
        uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
        if: steps.pr_id_finder.outputs.number && success()
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ steps.pr_id_finder.outputs.number }}
          body: |
            :white_check_mark:  Deployment **SUCCESS**
            Commit ${{ github.sha }} successfully deployed **Storybook static site** :open_book: to [${{ env.VERCEL_DEPLOYMENT_URL }}](${{ env.VERCEL_DEPLOYMENT_URL }})
            Deployment aliases (${{ env.VERCEL_ALIASES_CREATED_COUNT }}): ${{ env.VERCEL_ALIASES_CREATED_URLS_MD }}

      # At the end of the job, store all variables we will need in the following jobs
      # The variables will be stored in and retrieved from a GitHub Artifact (each variable is stored in a different file)
      - name: Store variables for next jobs
        uses: UnlyEd/github-action-store-variable@v2.1.1 # See https://github.com/UnlyEd/github-action-store-variable
        with:
          variables: |
            VERCEL_DEPLOYMENT_URL=${{ env.VERCEL_DEPLOYMENT_URL }}
            VERCEL_DEPLOYMENT_DOMAIN=${{ env.VERCEL_DEPLOYMENT_DOMAIN }}
            GITHUB_PULL_REQUEST_ID=${{ steps.pr_id_finder.outputs.number }}

  # Waits for the Vercel deployment to reach "READY" state, so that other actions will be applied on a domain that is really online
  await-for-vercel-deployment:
    name: Await current deployment to be ready (Ubuntu latest)
    timeout-minutes: 5 # Limit current job timeout https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes
    runs-on: ubuntu-latest
    needs: start-deployment
    steps:
      - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout

      # Restore variables stored by previous jobs
      - name: Restore variables
        uses: UnlyEd/github-action-store-variable@v2.1.1 # See https://github.com/UnlyEd/github-action-store-variable
        id: restore-variable
        with:
          failIfNotFound: true
          variables: |
            VERCEL_DEPLOYMENT_DOMAIN

      # Wait for deployment to be ready, before running E2E (otherwise Cypress might start testing too early, and gets redirected to Vercel's "Login page", and tests fail)
      - name: Awaiting Vercel deployment to be ready
        uses: UnlyEd/github-action-await-vercel@v1.1.1 # See https://github.com/UnlyEd/github-action-await-vercel
        id: await-vercel
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
        with:
          deployment-url: ${{ env.VERCEL_DEPLOYMENT_DOMAIN }} # Must only contain the domain name (no http prefix, etc.)
          timeout: 90 # Wait for 90 seconds before failing

      - name: Display deployment status
        run: "echo The deployment is ${{ fromJson(steps.await-vercel.outputs.deploymentDetails).readyState }}"

  # Runs E2E tests against the Vercel deployment
  run-2e2-tests:
    name: Run end to end (E2E) tests (Ubuntu latest)
    timeout-minutes: 20 # Limit current job timeout https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes
    runs-on: ubuntu-latest
    # Docker image with Cypress pre-installed
    # https://github.com/cypress-io/cypress-docker-images/tree/master/included
    container: cypress/included:7.4.0
    needs: await-for-vercel-deployment
    steps:
      - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout

      # Restore variables stored by previous jobs
      - name: Restore variables
        uses: UnlyEd/github-action-store-variable@v2.1.1 # See https://github.com/UnlyEd/github-action-store-variable
        id: restore-variable
        with:
          failIfNotFound: true
          variables: |
            VERCEL_DEPLOYMENT_URL
            GITHUB_PULL_REQUEST_ID

      # Runs the E2E tests against the new Vercel deployment
      - name: Run E2E tests (Cypress)
        uses: cypress-io/github-action@v2 # See https://github.com/cypress-io/github-action
        with:
          # XXX We disabled "wait-on" option, because it's useless. Cypress will fail anyway, because it gets redirected to some internal Vercel URL if the domain isn't yet available - See https://github.com/cypress-io/github-action/issues/270
          # wait-on: '${{ env.VERCEL_DEPLOYMENT_URL }}' # Be sure that the endpoint is ready by pinging it before starting tests, using a default timeout of 60 seconds
          config-file: 'cypress/config-storybook.json' # Use Cypress config file for Storybook, and override it below
          config: baseUrl=${{ env.VERCEL_DEPLOYMENT_URL }} # Overriding baseUrl provided by config file to test the new deployment
        env:
          # Enables Cypress debugging logs, very useful if Cypress crashes, like out-of-memory issues.
          # DEBUG: "cypress:*" # Enable all logs. See https://docs.cypress.io/guides/references/troubleshooting.html#Print-DEBUG-logs
          DEBUG: "cypress:server:util:process_profiler" # Enable logs for "memory and CPU usage". See https://docs.cypress.io/guides/references/troubleshooting.html#Log-memory-and-CPU-usage

      # On E2E failure, upload screenshots
      - name: Upload screenshots artifacts (E2E failure)
        uses: actions/upload-artifact@v1 # On failure we upload artifacts, https://help.github.com/en/actions/automating-your-workflow-with-github-actions/persisting-workflow-data-using-artifacts
        if: failure()
        with:
          name: screenshots
          path: cypress/screenshots/

      # On E2E failure, upload videos
      - name: Upload videos artifacts (E2E failure)
        uses: actions/upload-artifact@v1 # On failure we upload artifacts, https://help.github.com/en/actions/automating-your-workflow-with-github-actions/persisting-workflow-data-using-artifacts
        if: failure()
        with:
          name: videos
          path: cypress/videos/

      # On E2E failure, add a comment to the PR with additional information, if there is an open PR for the current branch
      - name: Comment PR (E2E failure)
        uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
        if: env.GITHUB_PULL_REQUEST_ID && failure()
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ env.GITHUB_PULL_REQUEST_ID }}
          body: |
            :x:  E2E tests **FAILED** for commit ${{ github.sha }} previously deployed **Storybook static site** at [${{ env.VERCEL_DEPLOYMENT_URL }}](${{ env.VERCEL_DEPLOYMENT_URL }})
            Download artifacts (screenshots + videos) from [`checks`](https://github.com/UnlyEd/next-right-now/pull/${{ env.GITHUB_PULL_REQUEST_ID }}/checks) section

      # On E2E success, add a comment to the PR, if there is an open PR for the current branch
      - name: Comment PR (E2E success)
        uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
        if: env.GITHUB_PULL_REQUEST_ID && success()
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ env.GITHUB_PULL_REQUEST_ID }}
          body: |
            :white_check_mark:  E2E tests **SUCCESS** for commit ${{ github.sha }} previously deployed **Storybook static site** at [${{ env.VERCEL_DEPLOYMENT_URL }}](${{ env.VERCEL_DEPLOYMENT_URL }})
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}