name: Viewer.js vendor and compatibility on: pull_request: branches: [main] push: branches: [main] workflow_dispatch: permissions: contents: read # Superseded PR pushes cancel their older run. Every main push gets its own # group (run_id), so no main commit's run is ever cancelled or dropped as pending. concurrency: group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: frontend-coverage: name: frontend coverage (chromium and touch) runs-on: ubuntu-latest # Layout comparisons depend on the fonts each browser falls back to, so browser jobs run in the # same pinned Playwright image as local runs (tag = @playwright/test in tools/vendor/package-lock.json; # tests/vendor/browser-image.test.mjs checks it). Browsers and fonts come from the image. container: image: mcr.microsoft.com/playwright:v1.64.1-noble options: --user 1001 timeout-minutes: 25 steps: - uses: actions/checkout@v7 # The image's own Python 3.12 and Node 24: setup-python/setup-node install the runner's toolcache # builds, whose entry points name host paths that do not exist in the container. The image has no # ensurepip and the job has no root, so a checksum-pinned pip wheel bootstraps a user-space venv. - name: Python environment env: PIP_WHEEL: https://files.pythonhosted.org/packages/f3/6e/1736e5b4ae2b778ef2f81c47d797de9f891d4d8acb047a24ca37a60294dd/pip-26.2.1-py3-none-any.whl PIP_SHA256: 71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e run: | venv="$RUNNER_TEMP/venv" wheel="$RUNNER_TEMP/pip-26.2.1-py3-none-any.whl" python3 -m venv --without-pip "$venv" curl -fsSL --retry 3 -o "$wheel" "$PIP_WHEEL" echo "$PIP_SHA256 $wheel" | sha256sum -c - "$venv/bin/python" "$wheel/pip" install --no-index --no-cache-dir "$wheel" "$venv/bin/python" -m pip install --no-cache-dir -r requirements-dev.txt echo "$venv/bin" >> "$GITHUB_PATH" - run: python --version && node --version && node --version | grep -q '^v24\.' - run: npm ci --prefix tools/vendor --ignore-scripts - run: npm run --prefix tools/vendor check - run: npm run --prefix tools/vendor test - name: Frontend unit, viewer, workflow, and coverage checks run: npm run --prefix tools/vendor test:coverage - name: Upload frontend coverage and Chromium traces if: always() uses: actions/upload-artifact@v7 with: name: frontend-test-reports path: | tools/vendor/test-results/ coverage/js/ !coverage/js/raw/** retention-days: 14 browser-workflows: name: page workflows (${{ matrix.browser }}) runs-on: ubuntu-latest # Layout comparisons depend on the fonts each browser falls back to, so browser jobs run in the # same pinned Playwright image as local runs (tag = @playwright/test in tools/vendor/package-lock.json; # tests/vendor/browser-image.test.mjs checks it). Browsers and fonts come from the image. container: image: mcr.microsoft.com/playwright:v1.64.1-noble options: --user 1001 timeout-minutes: 25 strategy: fail-fast: false matrix: browser: [firefox, webkit] steps: - uses: actions/checkout@v7 # The image's own Python 3.12 and Node 24: setup-python/setup-node install the runner's toolcache # builds, whose entry points name host paths that do not exist in the container. The image has no # ensurepip and the job has no root, so a checksum-pinned pip wheel bootstraps a user-space venv. - name: Python environment env: PIP_WHEEL: https://files.pythonhosted.org/packages/f3/6e/1736e5b4ae2b778ef2f81c47d797de9f891d4d8acb047a24ca37a60294dd/pip-26.2.1-py3-none-any.whl PIP_SHA256: 71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e run: | venv="$RUNNER_TEMP/venv" wheel="$RUNNER_TEMP/pip-26.2.1-py3-none-any.whl" python3 -m venv --without-pip "$venv" curl -fsSL --retry 3 -o "$wheel" "$PIP_WHEEL" echo "$PIP_SHA256 $wheel" | sha256sum -c - "$venv/bin/python" "$wheel/pip" install --no-index --no-cache-dir "$wheel" "$venv/bin/python" -m pip install --no-cache-dir -r requirements-dev.txt echo "$venv/bin" >> "$GITHUB_PATH" - run: python --version && node --version && node --version | grep -q '^v24\.' - run: npm ci --prefix tools/vendor --ignore-scripts - name: Page workflows in ${{ matrix.browser }} run: npm run --prefix tools/vendor test:workflows -- --project ${{ matrix.browser }} - name: Upload browser traces if: always() uses: actions/upload-artifact@v7 with: name: browser-traces-${{ matrix.browser }} path: tools/vendor/test-results/ retention-days: 14 # Branch protection requires the exact context "viewerjs". This job keeps that # name and fails unless every frontend job above succeeded, including when one # was cancelled or skipped. viewerjs: needs: [frontend-coverage, browser-workflows] if: always() runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Require every frontend job to succeed env: COVERAGE_RESULT: ${{ needs.frontend-coverage.result }} WORKFLOWS_RESULT: ${{ needs.browser-workflows.result }} run: | echo "frontend-coverage: $COVERAGE_RESULT" echo "browser-workflows: $WORKFLOWS_RESULT" test "$COVERAGE_RESULT" = success && test "$WORKFLOWS_RESULT" = success