Repository navigation
194 lines (181 loc) · 7.75 KB
/
Copy pathregression.yml
File metadata and controls
194 lines (181 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
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@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
# HEAD is the PR merge ref; its first parent is the current base tip, unlike the payload's
# base.sha, which goes stale and would count the base's newer commits as the PR's changes.
- name: Find the pull request's current base
id: base
if: github.event_name == 'pull_request'
run: |
git rev-parse --verify -q HEAD^2 > /dev/null || { echo "::error::HEAD is not the pull request merge commit"; exit 1; }
sha="$(git rev-parse --verify HEAD^1)"
echo "sha=$sha" >> "$GITHUB_OUTPUT"
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4
id: filter
if: github.event_name != 'schedule'
with:
token: ""
base: ${{ steps.base.outputs.sha }}
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@11d5960a326750d5838078e36cf38b85af677262 # 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@11d5960a326750d5838078e36cf38b85af677262 # 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