mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-01 19:26:52 +00:00
* test(producer): run the late-host pip and dogs-captions fixtures in CI The pip fixture wrote its video start in root time without the global basis marker that PR 3732 made the contract, so it rendered the empty host. Mark it global and schedule both fixtures that never ran in CI. * ci(producer): split regression fixtures across nine shards dogs-captions runs about eight minutes on its own; a ninth shard keeps the other shards near their previous wall time. * ci(producer): run dogs-captions in a nightly regression job instead of on every PR * ci(producer): base the dogs-captions timing and nightly reason on two CI runs
185 lines
7.2 KiB
YAML
185 lines
7.2 KiB
YAML
name: regression
|
|
run-name: ${{ github.event_name == 'workflow_dispatch' && format('Checks (catalog_publish={0})', inputs.catalog_publish) || '' }}
|
|
|
|
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"
|
|
|
|
# Graphite can update a branch and its PR base separately for the same head
|
|
# SHA. Keep only the newest expensive regression run for each PR/ref.
|
|
concurrency:
|
|
group: regression-${{ github.event.pull_request.number || github.ref }}${{ github.event_name == 'schedule' && '-nightly' || '' }}
|
|
# A body or title edit queues behind running checks instead of cancelling them.
|
|
cancel-in-progress: ${{ github.event.action != 'edited' || github.event.changes.base != null }}
|
|
|
|
on:
|
|
merge_group:
|
|
types: [checks_requested]
|
|
workflow_dispatch:
|
|
inputs:
|
|
catalog_publish:
|
|
description: "Run required checks for a generated catalog publication."
|
|
type: boolean
|
|
default: false
|
|
pull_request:
|
|
# Re-run when Graphite changes only the PR base for the same head SHA.
|
|
types: [opened, synchronize, reopened, edited]
|
|
push:
|
|
branches:
|
|
- main
|
|
schedule:
|
|
# Daily at 06:17 UTC: the full suite, including fixtures too slow for every PR.
|
|
- cron: "17 6 * * *"
|
|
|
|
jobs:
|
|
changes:
|
|
name: Detect changes
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 2
|
|
outputs:
|
|
code: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.catalog_publish)) && 'true' || steps.filter.outputs.code }}
|
|
matrix: ${{ steps.shards.outputs.matrix }}
|
|
steps:
|
|
# Force git-based change detection instead of the pull_request REST API.
|
|
# The API path can fail the whole workflow on transient listFiles
|
|
# timeouts before any regression shard even starts.
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
fetch-depth: 0
|
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
|
id: filter
|
|
if: github.event_name != 'schedule'
|
|
with:
|
|
token: ""
|
|
filters: |
|
|
code:
|
|
- "packages/core/**"
|
|
- "packages/producer/**"
|
|
- "packages/engine/**"
|
|
- "Dockerfile*"
|
|
# Bin-pack the shard matrix from recorded per-fixture timings rather than
|
|
# a hand-written list. Fails if any fixture on disk is neither scheduled
|
|
# nor explicitly excluded, so a new fixture cannot silently never run.
|
|
- name: Plan regression shards
|
|
id: shards
|
|
env:
|
|
NIGHTLY: ${{ github.event_name == 'schedule' && '--nightly' || '' }}
|
|
run: |
|
|
echo "matrix=$(node packages/producer/scripts/plan-regression-shards.mjs $NIGHTLY)" >> "$GITHUB_OUTPUT"
|
|
node packages/producer/scripts/plan-regression-shards.mjs $NIGHTLY --pretty
|
|
|
|
preflight:
|
|
name: Preflight (lint + format)
|
|
needs: changes
|
|
if: needs.changes.outputs.code == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
- uses: ./.github/actions/preflight
|
|
|
|
regression-shards:
|
|
needs: [changes, preflight]
|
|
if: needs.changes.outputs.code == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
strategy:
|
|
fail-fast: true
|
|
# Bin-packed at run time from packages/producer/tests/shard-schedule.json.
|
|
# To rebalance, refresh the timings in that file — no YAML edit needed.
|
|
# To change shard count, set "shardCount" there.
|
|
matrix: ${{ fromJSON(needs.changes.outputs.matrix) }}
|
|
steps:
|
|
- name: Checkout (with LFS)
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
lfs: true
|
|
|
|
- name: Validate LFS files
|
|
run: |
|
|
echo "Checking golden baseline MP4s are real files (not LFS pointers)..."
|
|
for mp4 in packages/producer/tests/*/output/output.mp4; do
|
|
if [ -f "$mp4" ]; then
|
|
size=$(stat --format=%s "$mp4")
|
|
if [ "$size" -lt 1000 ]; then
|
|
echo "ERROR: $mp4 appears to be an LFS pointer ($size bytes)"
|
|
exit 1
|
|
fi
|
|
echo "OK: $mp4 ($size bytes)"
|
|
fi
|
|
done
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
|
|
|
- name: Build test Docker image (cached)
|
|
# Normal duration is ~3 min; a bun install that errors and hangs
|
|
# instead of exiting (run 35468046055) otherwise runs unbounded until
|
|
# someone notices and cancels it. Fail fast so a shard fails, not stalls.
|
|
timeout-minutes: 20
|
|
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
|
with:
|
|
context: .
|
|
file: Dockerfile.test
|
|
load: true
|
|
tags: hyperframes-producer:test
|
|
cache-from: type=gha,scope=regression-test-image
|
|
# PR matrices can fan out across many stacked branches at once. Let
|
|
# them consume the shared cache, but keep a single writer on main so
|
|
# concurrent exports cannot exhaust the Actions cache service.
|
|
cache-to: ${{ github.event_name == 'push' && 'type=gha,mode=max,scope=regression-test-image' || '' }}
|
|
|
|
- name: "Run regression shard: ${{ matrix.shard }} (${{ matrix.mode }})"
|
|
run: |
|
|
echo "Shard: ${{ matrix.shard }}"
|
|
echo "Mode: ${{ matrix.mode }}"
|
|
echo "Args: ${{ matrix.args }}"
|
|
docker run --rm \
|
|
-e HYPERFRAMES_NO_TELEMETRY=1 \
|
|
--security-opt seccomp=unconfined \
|
|
--shm-size=4g \
|
|
-v ${{ github.workspace }}/packages/producer/tests:/app/packages/producer/tests \
|
|
hyperframes-producer:test \
|
|
--mode=${{ matrix.mode }} \
|
|
${{ matrix.args }}
|
|
|
|
- name: Upload failure artifacts
|
|
if: failure()
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
with:
|
|
name: regression-failures-${{ matrix.shard }}
|
|
path: packages/producer/tests/*/failures/
|
|
if-no-files-found: ignore
|
|
|
|
# Summary job — matches the required check name in branch protection
|
|
regression:
|
|
runs-on: ubuntu-latest
|
|
needs: [changes, regression-shards]
|
|
if: always()
|
|
steps:
|
|
- name: Check results
|
|
env:
|
|
CHANGES_RESULT: ${{ needs.changes.result }}
|
|
CODE_CHANGED: ${{ needs.changes.outputs.code }}
|
|
SHARDS_RESULT: ${{ needs.regression-shards.result }}
|
|
run: |
|
|
if [ "$CHANGES_RESULT" != "success" ]; then
|
|
echo "::error::Change detection did not succeed."
|
|
exit 1
|
|
fi
|
|
case "$CODE_CHANGED" in
|
|
false) echo "No regression code changes." ;;
|
|
true)
|
|
if [ "$SHARDS_RESULT" != "success" ]; then
|
|
echo "::error::Regression shards did not succeed."
|
|
exit 1
|
|
fi
|
|
echo "All regression shards succeeded."
|
|
;;
|
|
*) echo "::error::Change detection returned no valid decision."; exit 1 ;;
|
|
esac
|