Browse Source

build(ci): Separate webpack from acceptance test runner (#27656)

This separates out the javascript + webpack dependencies in our acceptance tests into a new job that builds the frontend bundle for acceptance tests to use.

Instead of having `X` number of acceptance tests all running `yarn install` and `yarn build`, we now have a single job that builds the frontend bundle and then saves it as a GHA artifact. The acceptance test will run in parallel and setup the python environment and then wait and poll until the frontend bundle job is completed. It will then download the frontend artifacts and continue running acceptance tests.

The frontend job takes roughly ~5 minutes to run while the acceptance test setup takes about 2-2.5 minutes. This means our acceptance tests are polling for ~2 minutes while doing nothing. However this does give us about ~2-3 minutes (x 4 instances) of savings!

I think we can do some further optimizations with the frontend build (maybe dockerize the frontend build as yarn.lock shouldn't be updated that frequently).
Billy Vong 3 years ago
parent
commit
1f5d3409e9
1 changed files with 75 additions and 31 deletions
  1. 75 31
      .github/workflows/acceptance.yml

+ 75 - 31
.github/workflows/acceptance.yml

@@ -61,6 +61,7 @@ jobs:
       - name: Save HTML artifacts
         uses: actions/upload-artifact@v2
         with:
+          retention-days: 14
           name: jest-html
           path: .artifacts/visual-snapshots/jest
 
@@ -80,10 +81,72 @@ jobs:
       - name: Handle artifacts
         uses: ./.github/actions/artifacts
 
+  webpack:
+    name: create frontend bundle
+    runs-on: ubuntu-20.04
+    timeout-minutes: 10
+    outputs:
+      dist-path: ${{ steps.config.outputs.dist-path }}
+
+    steps:
+      - uses: actions/checkout@v2
+        name: Checkout sentry
+
+      - uses: volta-cli/action@v1
+
+      - name: Step configurations
+        id: config
+        run: |
+          echo "::set-output name=yarn-path::$(yarn cache dir)"
+          echo "::set-output name=webpack-path::.webpack_cache"
+          echo "::set-output name=dist-path::src/sentry/static/sentry/dist"
+
+      - name: yarn cache
+        uses: actions/cache@v2
+        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+        with:
+          path: ${{ steps.config.outputs.yarn-path }}
+          key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'api-docs/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn-
+
+      - name: webpack cache
+        uses: actions/cache@v2
+        with:
+          path: ${{ steps.config.outputs.webpack-path }}
+          key: ${{ runner.os }}-webpack-cache-${{ hashFiles('webpack.config.ts') }}
+          restore-keys: |
+            ${{ runner.os }}-webpack-cache-
+
+      - name: Install Javascript Dependencies
+        run: |
+          yarn install --frozen-lockfile
+
+      - name: webpack
+        env:
+          WEBPACK_CACHE_PATH: ${{ steps.config.outputs.webpack-path }}
+          SENTRY_INSTRUMENTATION: 1
+          # this is fine to not have for forks, it shouldn't fail
+          SENTRY_WEBPACK_WEBHOOK_SECRET: ${{ secrets.SENTRY_WEBPACK_WEBHOOK_SECRET }}
+        run: |
+          yarn build-acceptance
+
+      # Bundle dist for faster uploading
+      - name: bundle dist
+        run: |
+          tar czf dist.tar.gz ${{ steps.config.outputs.dist-path }}
+
+      - name: Save frontend dist
+        uses: actions/upload-artifact@v2
+        with:
+          retention-days: 3
+          name: frontend-dist
+          path: dist.tar.gz
+
   acceptance:
     name: acceptance
     runs-on: ubuntu-20.04
-    timeout-minutes: 25
+    timeout-minutes: 20
     strategy:
       matrix:
         instance: [0, 1, 2, 3]
@@ -96,17 +159,11 @@ jobs:
       - uses: actions/checkout@v2
         name: Checkout sentry
 
-      - uses: volta-cli/action@v1
-
       - name: Set python version output
         id: python-version
         run: |
           echo "::set-output name=python-version::$(cat .python-version)"
 
-      - name: Setup webpack cache
-        id: webpack-cache
-        run: echo "::set-output name=path::.webpack_cache"
-
       # Until GH composite actions can use `uses`, we need to setup python here
       - uses: actions/setup-python@v2
         with:
@@ -131,35 +188,22 @@ jobs:
         with:
           snuba: true
 
-      - name: yarn cache
-        uses: actions/cache@v2
-        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+      - name: Wait for frontend build
+        uses: getsentry/action-wait-for-check@v1.0.0
+        id: wait-for-frontend
         with:
-          path: ${{ steps.setup.outputs.yarn-cache-dir }}
-          key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'api-docs/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.os }}-yarn-
+          token: ${{ secrets.GITHUB_TOKEN }}
+          checkName: create frontend bundle
+          ref: ${{ github.event.pull_request.head.sha || github.sha }}
 
-      - name: webpack cache
-        uses: actions/cache@v2
+      - name: Download frontend dist
+        uses: actions/download-artifact@v2
         with:
-          path: ${{ steps.webpack-cache.outputs.path }}
-          key: ${{ runner.os }}-webpack-cache-${{ hashFiles('webpack.config.js') }}
-          restore-keys: |
-            ${{ runner.os }}-webpack-cache-
-
-      - name: Install Javascript Dependencies
-        run: |
-          yarn install --frozen-lockfile
+          name: frontend-dist
 
-      - name: webpack
-        env:
-          WEBPACK_CACHE_PATH: ${{ steps.webpack-cache.outputs.path }}
-          SENTRY_INSTRUMENTATION: 1
-          # this is fine to not have for forks, it shouldn't fail
-          SENTRY_WEBPACK_WEBHOOK_SECRET: ${{ secrets.SENTRY_WEBPACK_WEBHOOK_SECRET }}
+      - name: Extract dist
         run: |
-          yarn build-acceptance
+          tar xf dist.tar.gz
 
       - name: Run acceptance tests (#${{ steps.setup.outputs.matrix-instance-number }} of ${{ strategy.job-total }})
         if: always()