name: Player perf permissions: contents: read # Suppress hyperframes CLI telemetry from HeyGen's own CI runs. # External users' CI continues to emit telemetry unless they set this themselves. env: HYPERFRAMES_NO_TELEMETRY: "1" on: pull_request: push: branches: [main] concurrency: group: player-perf-${{ github.ref }} cancel-in-progress: true jobs: changes: name: Detect changes runs-on: ubuntu-latest timeout-minutes: 2 outputs: perf: ${{ steps.filter.outputs.perf }} steps: # Force git-based change detection instead of the pull_request REST API. # The API path can fail the perf workflow on transient listFiles timeouts. - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4 id: filter with: token: "" filters: | perf: - "packages/player/**" - "packages/core/**" - "package.json" - "bun.lock" - ".github/workflows/player-perf.yml" preflight: name: Preflight (lint + format) needs: changes if: needs.changes.outputs.perf == 'true' runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: ./.github/actions/preflight perf-shards: name: "Perf: ${{ matrix.shard }}" needs: [changes, preflight] if: needs.changes.outputs.perf == 'true' runs-on: ubuntu-latest timeout-minutes: 20 strategy: fail-fast: true matrix: include: - shard: load scenarios: load runs: "5" - shard: fps scenarios: fps runs: "3" - shard: scrub scenarios: scrub runs: "3" - shard: drift scenarios: drift runs: "3" - shard: parity scenarios: parity runs: "3" steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile # Player perf loads packages/player/dist/hyperframes-player.global.js # and packages/core/dist/hyperframe.runtime.iife.js, so a full build is required. - run: bun run build - name: Set up Chrome (headless shell) id: setup-chrome uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1 with: chrome-version: stable # The parity scenario shells out to `ffmpeg -lavfi ssim` to score the # live-playback frame against the sync-seek reference frame. ffmpeg is # not on the default ubuntu-latest runner image, and a missing binary # surfaces as ENOENT inside computeSsim() — informative, but cheaper # to just install it here so the shard never trips on infra. - name: Install ffmpeg (parity shard only) if: matrix.shard == 'parity' run: | sudo apt-get update sudo apt-get install -y --no-install-recommends ffmpeg ffmpeg -version | head -n 1 - name: Run player perf — ${{ matrix.shard }} (measure mode) working-directory: packages/player env: PUPPETEER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} run: | bun run perf \ --mode=measure \ --scenarios=${{ matrix.scenarios }} \ --runs=${{ matrix.runs }} - name: Upload perf results if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: player-perf-${{ matrix.shard }} path: packages/player/tests/perf/results/ if-no-files-found: warn retention-days: 30 # Summary job — matches the required check name in branch protection. # Logs an explicit "skipped" / "passed" / "failed" line both to stdout and to # $GITHUB_STEP_SUMMARY so a false skip is obvious in the Checks UI without # having to dig into the changes-job logs. player-perf: runs-on: ubuntu-latest needs: [changes, perf-shards] if: always() steps: - name: Check results env: PERF_FILTER_RESULT: ${{ needs.changes.outputs.perf }} PERF_SHARDS_RESULT: ${{ needs.perf-shards.result }} run: | { echo "## Player perf gate" echo "" echo "- paths-filter \`perf\` matched: \`${PERF_FILTER_RESULT}\`" echo "- perf-shards result: \`${PERF_SHARDS_RESULT}\`" echo "" } >> "$GITHUB_STEP_SUMMARY" if [ "${PERF_FILTER_RESULT}" != "true" ]; then echo "::notice title=Player perf::SKIPPED — no changes under packages/player/**, packages/core/**, package.json, bun.lock, or .github/workflows/player-perf.yml. Auto-pass." echo "**Status:** SKIPPED (no player/core changes — auto-pass)" >> "$GITHUB_STEP_SUMMARY" exit 0 fi if [ "${PERF_SHARDS_RESULT}" != "success" ]; then echo "::error title=Player perf::FAILED — perf-shards result was '${PERF_SHARDS_RESULT}'. See the per-shard logs above." echo "**Status:** FAILED (perf-shards result: \`${PERF_SHARDS_RESULT}\`)" >> "$GITHUB_STEP_SUMMARY" exit 1 fi echo "::notice title=Player perf::PASSED — all perf shards completed successfully." echo "**Status:** PASSED" >> "$GITHUB_STEP_SUMMARY"