-
Notifications
You must be signed in to change notification settings - Fork 61
225 lines (200 loc) · 9 KB
/
Copy pathcode-storybook.yml
File metadata and controls
225 lines (200 loc) · 9 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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
name: Storybook visual regression
on:
pull_request:
concurrency:
group: code-storybook-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
contents: read
outputs:
code: ${{ steps.filter.outputs.code }}
verify_only: "${{ startsWith(steps.head-commit.outputs.message, 'chore(storybook): update visual regression snapshots') }}"
steps:
- name: Detect relevant changes
id: filter
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
with:
predicate-quantifier: every
filters: |
# Anything that can change a rendered story. Snapshot baselines are
# excluded so a PR that only touches them (e.g. a manual refresh)
# skips the run. Note: dorny/paths-filter diffs the whole PR
# against its base, not just the latest commit, so this filter
# alone does NOT stop the auto-commit from re-triggering itself
# (the diff still includes the code changes from earlier commits).
# verify_only is what breaks the loop: the retriggered run
# executes in verify mode, which never commits.
code:
- "{apps/code/**,packages/**,pnpm-lock.yaml,.github/workflows/code-storybook.yml}"
- "!apps/code/.storybook/__snapshots__/**"
- "!**/*.md"
# The pull_request event payload has no head.commit.message, so fetch it
# via the API to power the verify_only switch below.
- name: Get head commit message
id: head-commit
env:
GH_TOKEN: ${{ github.token }}
run: |
message=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }} --jq '.commit.message')
echo "message<<EOF" >> "$GITHUB_OUTPUT"
echo "$message" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
visual-regression:
needs: changes
# Fail closed: if change detection itself failed, run instead of skipping.
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.code == 'true') }}
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Auto-commit targets the PR head branch, so test against it rather
# than the synthetic merge commit.
ref: ${{ github.event.pull_request.head.sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: "pnpm"
- name: Cache Playwright browsers
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-chromium-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
playwright-chromium-${{ runner.os }}-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Playwright Chromium
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: apps/code
run: pnpm exec playwright install --with-deps chromium
- name: Install Playwright system dependencies
# The cache restores browser binaries but not the OS packages they need.
if: steps.playwright-cache.outputs.cache-hit == 'true'
working-directory: apps/code
run: pnpm exec playwright install-deps chromium
- name: Build workspace packages
# Bare `wait` returns the exit status of only the last job passed to
# it, silently swallowing failures from the others. `wait_all` waits
# on each PID individually and checks its own status so any failed
# build fails the step.
run: |
wait_all() {
status=0
for pid in "$@"; do
wait "$pid" || status=$?
done
[ "$status" -eq 0 ]
}
pnpm --filter @posthog/electron-trpc build &
pid1=$!
(pnpm --filter @posthog/shared build && pnpm --filter @posthog/platform build) &
pid2=$!
wait_all "$pid1" "$pid2"
# @posthog/agent imports @posthog/git's dist, so git must finish
# before the last group starts.
pnpm --filter @posthog/git build
pnpm --filter @posthog/enricher build &
pid3=$!
pnpm --filter @posthog/agent build &
pid4=$!
wait_all "$pid3" "$pid4"
- name: Build Storybook
working-directory: apps/code
run: pnpm build-storybook
- name: Serve Storybook
working-directory: apps/code
run: |
pnpm exec http-server storybook-static --port 6006 --silent &
pnpm exec wait-on http://127.0.0.1:6006/iframe.html --timeout 30000
# When the head commit is itself a snapshot auto-commit, updating again
# would retrigger this workflow forever. Verify instead: the run still
# proves the committed baselines pass, but never commits, which breaks
# the loop while keeping the check green-because-it-ran (not
# green-because-it-skipped).
- name: Verify visual regression snapshots
if: needs.changes.outputs.verify_only == 'true'
working-directory: apps/code
run: pnpm test:visual:ci:verify
- name: Update visual regression snapshots
if: needs.changes.outputs.verify_only != 'true'
working-directory: apps/code
env:
# Tells jest-image-snapshot's outdated-snapshot-reporter to delete
# baseline PNGs that no story wrote this run, so renamed/removed
# stories don't leave orphaned snapshots behind.
JEST_IMAGE_SNAPSHOT_TRACK_OBSOLETE: "1"
run: pnpm test:visual:ci:update
- name: Detect snapshot changes
id: diff
if: needs.changes.outputs.verify_only != 'true'
env:
IS_FORK: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
run: |
git add -A apps/code/.storybook/__snapshots__
if git diff --staged --quiet -- apps/code/.storybook/__snapshots__; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "commit=false" >> "$GITHUB_OUTPUT"
echo "fail-fork=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "commit=$([ "$IS_FORK" = "true" ] && echo false || echo true)" >> "$GITHUB_OUTPUT"
echo "fail-fork=$IS_FORK" >> "$GITHUB_OUTPUT"
git diff --staged --stat -- apps/code/.storybook/__snapshots__
fi
- name: Get app token
id: app-token
if: steps.diff.outputs.commit == 'true'
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.GH_APP_ARRAY_RELEASER_APP_ID }}
private-key: ${{ secrets.GH_APP_ARRAY_RELEASER_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
- name: Commit updated snapshots to the PR branch
if: steps.diff.outputs.commit == 'true'
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
REPO: ${{ github.repository }}
BRANCH: ${{ github.event.pull_request.head.ref }}
EXPECTED_HEAD_OID: ${{ github.event.pull_request.head.sha }}
run: node scripts/commit-storybook-snapshots.mjs
- name: Fail on snapshot changes from a fork
if: steps.diff.outputs.fail-fork == 'true'
run: |
echo "Visual regression snapshots changed, but fork PRs cannot receive auto-commits."
echo "Run 'pnpm --filter code test:visual:update' against a Linux build and commit the results."
exit 1
- name: Upload failure screenshots
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v6.0.0
with:
name: storybook-visual-failures
path: |
apps/code/.storybook/__snapshots__/__diff_output__/
apps/code/.storybook/__snapshots__/__failures__/
if-no-files-found: ignore
retention-days: 7
- name: Upload test results to Trunk
# Run even when tests fail so flaky/failed results are still reported,
# but never let an upload problem fail the job.
if: ${{ !cancelled() }}
continue-on-error: true
uses: trunk-io/analytics-uploader@385f1ccdf345b4532dc4b6c665dd432b702b8e28 # v2.1.2
with:
junit-paths: "apps/code/junit.xml"
org-slug: posthog-inc
token: ${{ secrets.TRUNK_API_TOKEN }}