Files
hyperframes/.github/workflows/regression.yml
T
ad11de698c feat(producer): auto-fallback screenshot capture for raf and iframes (#331)
* fix(core): drive adapter seeks when composition has no GSAP timeline

renderSeek returned early when deps.getTimeline() was null, skipping the
onDeterministicSeek call that drives all frame adapters (CSS, WAAPI,
Lottie, Three.js). That meant compositions using any non-GSAP animation
primitive froze on their initial frame during capture.

Now we still quantize the seek time and fire onDeterministicSeek even
without a timeline, so each adapter gets a chance to advance.

GSAP compositions are unaffected — timeline-driven seek still takes the
same path it did before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(producer): auto-fallback screenshot capture for raf and iframes

Co-Authored-By: Codex <codex@openai.com>

* test(producer): add render compatibility regression fixtures

Co-Authored-By: Codex <codex@openai.com>

* fix(core): scrub CSS animations via WAAPI currentTime

Co-Authored-By: Codex <codex@openai.com>

* test(producer): cover css keyframe renders

Co-Authored-By: Codex <codex@openai.com>

* fix(producer): propagate virtual time into iframe documents

Co-Authored-By: Codex <codex@openai.com>

* test(producer): refresh iframe docker golden

Co-Authored-By: Codex <codex@openai.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex <codex@openai.com>
2026-04-18 15:08:52 -07:00

123 lines
3.8 KiB
YAML

name: regression
on:
pull_request:
push:
branches:
- main
jobs:
changes:
name: Detect changes
runs-on: ubuntu-latest
timeout-minutes: 2
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- "packages/core/**"
- "packages/producer/**"
- "packages/engine/**"
- "Dockerfile*"
regression-shards:
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
include:
- shard: fast
args: "--sequential --exclude-tags slow,render-compat"
- shard: render-compat
args: "--sequential gsap-letters-render-compat css-spinner-render-compat raf-ball-render-compat iframe-render-compat"
- shard: styles-a
args: "style-1-prod style-2-prod style-3-prod"
- shard: styles-b
args: "style-4-prod style-5-prod style-6-prod"
- shard: styles-c
args: "style-7-prod style-8-prod style-9-prod"
- shard: styles-d
args: "style-10-prod style-11-prod style-12-prod"
- shard: styles-e
args: "style-13-prod style-15-prod style-16-prod"
- shard: styles-f
args: "style-17-prod style-18-prod"
- shard: styles-g
args: "overlay-montage-prod"
steps:
- name: Checkout (with LFS)
uses: actions/checkout@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@v3
- name: Build test Docker image (cached)
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.test
load: true
tags: hyperframes-producer:test
cache-from: type=gha,scope=regression-test-image
cache-to: type=gha,mode=max,scope=regression-test-image
- name: "Run regression shard: ${{ matrix.shard }}"
run: |
echo "Shard: ${{ matrix.shard }}"
echo "Args: ${{ matrix.args }}"
docker run --rm \
--security-opt seccomp=unconfined \
--shm-size=4g \
-v ${{ github.workspace }}/packages/producer/tests:/app/packages/producer/tests \
hyperframes-producer:test \
${{ matrix.args }}
- name: Upload failure artifacts
if: failure()
uses: actions/upload-artifact@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
run: |
if [ "${{ needs.changes.outputs.code }}" != "true" ]; then
echo "No code changes — skipping regression (auto-pass)"
exit 0
fi
if [ "${{ needs.regression-shards.result }}" != "success" ]; then
echo "One or more regression shards failed"
exit 1
fi