@andwhy/e2e-pipeline 0.12.2 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/init.js
CHANGED
|
@@ -117,8 +117,10 @@ const run = async () => {
|
|
|
117
117
|
" deployment protection",
|
|
118
118
|
" SLACK_WEBHOOK_URL — auto-heal notifications",
|
|
119
119
|
"(ANTHROPIC_API_KEY is an org-level secret inherited by all repos —",
|
|
120
|
-
"nothing to add
|
|
121
|
-
"
|
|
120
|
+
"nothing to add; if the heal agent fails to authenticate, a repo",
|
|
121
|
+
"secret of the same name overrides it.) The auto-heal workflow stays",
|
|
122
|
+
"inert until a Checkly webhook alert channel dispatches to it — the",
|
|
123
|
+
"skill walks through that.",
|
|
122
124
|
].join("\n"));
|
|
123
125
|
}
|
|
124
126
|
console.log("Next steps:");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andwhy/e2e-pipeline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Scaffolds the full e2e testing pipeline: agent-assisted Playwright tests, CI runs against Vercel previews, and Checkly monitors that follow production deploys",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -92,8 +92,13 @@ The scaffold writes templates, not a working setup. Walk these with the user:
|
|
|
92
92
|
value from 1Password ("e2e Slack webhook"). Same value in every repo;
|
|
93
93
|
do not walk the user through creating a Slack app or webhook — routing
|
|
94
94
|
to the project channel happens via a Slack rule in Phase 5.
|
|
95
|
-
- `ANTHROPIC_API_KEY` needs **no action**: it is an
|
|
96
|
-
secret inherited by every repo
|
|
95
|
+
- `ANTHROPIC_API_KEY` usually needs **no action**: it is an
|
|
96
|
+
organization-level secret inherited by every repo — do not walk the
|
|
97
|
+
user through adding it up front. But it can fail to reach a repo
|
|
98
|
+
(org-secret scoping, or a stale stored value): if a heal run's agent
|
|
99
|
+
step fails to authenticate, have the user add a repository-level
|
|
100
|
+
`ANTHROPIC_API_KEY` — a repo secret with the same name overrides the
|
|
101
|
+
organization one.
|
|
97
102
|
5. **Existing tests under `tests/`** (unit, a11y — the scaffold lists them as
|
|
98
103
|
"outside tests/e2e"): leave `testDir` at `./tests/e2e` and give that suite
|
|
99
104
|
its own Playwright project with its own `testDir` if it should run under
|
|
@@ -181,7 +186,9 @@ overwritten):
|
|
|
181
186
|
`CHECKLY_API_KEY` and `CHECKLY_ACCOUNT_ID` for the deploy and auto-heal,
|
|
182
187
|
`VERCEL_AUTOMATION_BYPASS_SECRET` for the PR run through deployment
|
|
183
188
|
protection, `SLACK_WEBHOOK_URL` for auto-heal notifications
|
|
184
|
-
(`ANTHROPIC_API_KEY` is inherited from the organization — nothing to add
|
|
189
|
+
(`ANTHROPIC_API_KEY` is inherited from the organization — nothing to add
|
|
190
|
+
unless a heal run fails to authenticate; then a repo-level secret of the
|
|
191
|
+
same name overrides it, see Phase 0).
|
|
185
192
|
If the scaffold just created the workflows, say so explicitly and list the
|
|
186
193
|
secrets — a merge without them fails CI and looks like a pipeline bug.
|
|
187
194
|
|
|
@@ -201,7 +208,9 @@ Set up once per project:
|
|
|
201
208
|
|
|
202
209
|
1. Confirm the `SLACK_WEBHOOK_URL` repository secret from Phase 0 exists —
|
|
203
210
|
the workflow escalates nothing without it. (`ANTHROPIC_API_KEY` comes
|
|
204
|
-
from the organization automatically
|
|
211
|
+
from the organization automatically — but if the dry run in step 6 ends
|
|
212
|
+
agent-failed with an authentication error, override it with a repo-level
|
|
213
|
+
secret of the same name, per Phase 0.)
|
|
205
214
|
2. The shared `GH_DISPATCH_TOKEN` secret exists in Checkly and covers this
|
|
206
215
|
repo. This is **one-time organization setup, not yours to perform**: the
|
|
207
216
|
token (`checkly-heal-dispatch`, a fine-grained PAT) is created once and
|
|
@@ -11,7 +11,9 @@ name: Checkly auto-heal
|
|
|
11
11
|
# commit, PR, and Slack are workflow steps.
|
|
12
12
|
# Needs repo secrets CHECKLY_API_KEY, CHECKLY_ACCOUNT_ID, SLACK_WEBHOOK_URL
|
|
13
13
|
# (the org-shared e2e-channel webhook; values in 1Password); ANTHROPIC_API_KEY
|
|
14
|
-
# is inherited from the organization
|
|
14
|
+
# is inherited from the organization (a repo secret of the same name
|
|
15
|
+
# overrides it if the org value fails to authenticate). Slack messages
|
|
16
|
+
# carry an [e2e:<repo>]
|
|
15
17
|
# tag so Slack Workflow Builder rules route them from the shared channel to
|
|
16
18
|
# project channels. Setup docs: the playwright-test-pipeline skill walks
|
|
17
19
|
# through the Checkly webhook channel and the Slack rule.
|
|
@@ -259,7 +261,12 @@ jobs:
|
|
|
259
261
|
git config user.name "github-actions[bot]"
|
|
260
262
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
261
263
|
git checkout -b "$branch"
|
|
262
|
-
|
|
264
|
+
# Stage everything, then unstage the agent's scratch dir. An
|
|
265
|
+
# ':(exclude).checkly-heal' pathspec looks equivalent but exits 1
|
|
266
|
+
# when the path is gitignored (as init makes it), which killed
|
|
267
|
+
# every PR step before a commit existed.
|
|
268
|
+
git add -A
|
|
269
|
+
git reset -q -- .checkly-heal
|
|
263
270
|
git commit -m "Heal Checkly check: $CHECK_NAME"
|
|
264
271
|
git push -u origin "$branch"
|
|
265
272
|
|
|
@@ -307,31 +314,65 @@ jobs:
|
|
|
307
314
|
APP_CHANGE: ${{ steps.outcome.outputs.app_change }}
|
|
308
315
|
PR_URL: ${{ steps.pr.outputs.url }}
|
|
309
316
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
317
|
+
BRANCH: checkly-heal/${{ steps.guard.outputs.slug }}-${{ github.run_id }}
|
|
310
318
|
run: |
|
|
311
|
-
|
|
319
|
+
# A fix only reaches review through a PR. When the PR step failed,
|
|
320
|
+
# "fix ready for review" would be false: report the failure and
|
|
321
|
+
# offer the re-run instead.
|
|
322
|
+
outcome="$CLASSIFICATION"
|
|
323
|
+
if { [ "$CLASSIFICATION" = "healed" ] || [ "$CLASSIFICATION" = "flaky" ]; } && [ -z "$PR_URL" ]; then
|
|
324
|
+
outcome="pr-failed"
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
case "${MODE}:${outcome}" in
|
|
312
328
|
repeat:*)
|
|
313
|
-
|
|
329
|
+
title=":rotating_light: *\`$CHECK_NAME\` is failing again*"
|
|
330
|
+
body="A heal PR for this check merged within the last $REPEAT_WINDOW_DAYS days, so no second automatic fix was attempted. This needs a developer." ;;
|
|
331
|
+
*:pr-failed)
|
|
332
|
+
title=":rotating_light: *\`$CHECK_NAME\` failed — fix made, but the PR could not be opened*"
|
|
333
|
+
body="The agent classified this as $CLASSIFICATION and made a fix, then opening the PR failed, so nothing reached review. If branch \`$BRANCH\` exists, open the PR from it; otherwise check the run logs and re-run the heal. Agent diagnosis: $SUMMARY" ;;
|
|
314
334
|
*:healed)
|
|
315
|
-
|
|
335
|
+
title=":wrench: *\`$CHECK_NAME\` failed — fix ready for review*"
|
|
336
|
+
body="$SUMMARY" ;;
|
|
316
337
|
*:flaky)
|
|
317
|
-
|
|
338
|
+
title=":wrench: *\`$CHECK_NAME\` was flaky — test hardened, fix ready for review*"
|
|
339
|
+
body="$SUMMARY" ;;
|
|
318
340
|
*:regression)
|
|
319
|
-
|
|
341
|
+
title=":rotating_light: *\`$CHECK_NAME\` failed — production regression*"
|
|
342
|
+
body="The test is correct; the site is broken. $SUMMARY" ;;
|
|
320
343
|
*:needs-app-change)
|
|
321
|
-
|
|
344
|
+
title=":warning: *\`$CHECK_NAME\` failed — fix needs an app code change*"
|
|
345
|
+
body="$SUMMARY" ;;
|
|
322
346
|
*:not-reproducible)
|
|
323
347
|
# Transient blip, nothing to act on — summary only, no ping.
|
|
324
348
|
echo "Not reproducible — no Slack notification." >> "$GITHUB_STEP_SUMMARY"
|
|
325
349
|
exit 0 ;;
|
|
326
350
|
*)
|
|
327
|
-
|
|
351
|
+
title=":rotating_light: *\`$CHECK_NAME\` failed and the auto-heal run did not finish cleanly*"
|
|
352
|
+
body="${SUMMARY:-Check the run logs.} This needs a developer." ;;
|
|
328
353
|
esac
|
|
329
|
-
|
|
330
|
-
#
|
|
331
|
-
#
|
|
332
|
-
|
|
333
|
-
[ "$
|
|
334
|
-
|
|
354
|
+
|
|
355
|
+
# Repeat mode skips the agent, so there is no outcome classification;
|
|
356
|
+
# label it as what it is rather than defaulting to agent-failed.
|
|
357
|
+
label="${CLASSIFICATION:-agent-failed}"
|
|
358
|
+
[ "$MODE" = "repeat" ] && label="repeat-offender"
|
|
359
|
+
# agent-failed also renders the Re-run heal button.
|
|
360
|
+
[ "$outcome" = "pr-failed" ] && label="agent-failed"
|
|
361
|
+
|
|
362
|
+
# Failing test titles, best effort from the Checkly result's embedded
|
|
363
|
+
# Playwright report — the recursive search tolerates schema changes,
|
|
364
|
+
# and an empty result simply omits the field.
|
|
365
|
+
failed_tests=""
|
|
366
|
+
if [ -f .checkly-heal/result.json ]; then
|
|
367
|
+
failed_tests=$(jq -r '[.. | objects | select((.status? == "failed") or (.outcome? == "unexpected")) | .title? // empty] | unique | .[0:3] | join(", ")' .checkly-heal/result.json 2>/dev/null || true)
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
# Plain-text fallback: what notifications, search, and the Slack
|
|
371
|
+
# routing rule see — the Workflow Builder rule matches the [e2e:<repo>]
|
|
372
|
+
# tag here and forwards this text, so it stays a complete message.
|
|
373
|
+
repo="${GITHUB_REPOSITORY##*/}"
|
|
374
|
+
text="[e2e:$repo] $title — $body"
|
|
375
|
+
[ -n "$PR_URL" ] && text="$text\nPR: $PR_URL"
|
|
335
376
|
text="$text\nRun: $RUN_URL"
|
|
336
377
|
|
|
337
378
|
if [ -z "$SLACK_WEBHOOK_URL" ]; then
|
|
@@ -339,7 +380,51 @@ jobs:
|
|
|
339
380
|
printf '%b\n' "$text" >> "$GITHUB_STEP_SUMMARY"
|
|
340
381
|
exit 0
|
|
341
382
|
fi
|
|
342
|
-
|
|
383
|
+
|
|
384
|
+
# Block Kit body: title, classification/repo fields, failing tests
|
|
385
|
+
# when known, the diagnosis, and link buttons assembled per outcome —
|
|
386
|
+
# a button never renders without its target.
|
|
387
|
+
jq -n \
|
|
388
|
+
--arg text "$(printf '%b' "$text")" \
|
|
389
|
+
--arg title "$title" \
|
|
390
|
+
--arg body "$body" \
|
|
391
|
+
--arg classification "$label" \
|
|
392
|
+
--arg repo "$repo" \
|
|
393
|
+
--arg failed "$failed_tests" \
|
|
394
|
+
--arg app_change "$APP_CHANGE" \
|
|
395
|
+
--arg pr "$PR_URL" \
|
|
396
|
+
--arg run "$RUN_URL" \
|
|
397
|
+
--arg result "$RESULT_LINK" \
|
|
398
|
+
--arg rerun "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/workflows/checkly-heal.yml" \
|
|
399
|
+
'
|
|
400
|
+
def btn($label; $url): {type: "button", text: {type: "plain_text", text: $label}, url: $url};
|
|
401
|
+
{
|
|
402
|
+
text: $text,
|
|
403
|
+
blocks: (
|
|
404
|
+
[
|
|
405
|
+
{type: "section", text: {type: "mrkdwn", text: $title}},
|
|
406
|
+
{type: "section", fields: ([
|
|
407
|
+
{type: "mrkdwn", text: ("*Classification*\n" + $classification)},
|
|
408
|
+
{type: "mrkdwn", text: ("*Repository*\n" + $repo)}
|
|
409
|
+
] + (if $failed != "" then
|
|
410
|
+
[{type: "mrkdwn", text: ("*Failed test*\n" + $failed)}]
|
|
411
|
+
else [] end))}
|
|
412
|
+
]
|
|
413
|
+
+ (if $body != "" then
|
|
414
|
+
[{type: "section", text: {type: "mrkdwn", text: $body}}]
|
|
415
|
+
else [] end)
|
|
416
|
+
+ (if $app_change == "true" then
|
|
417
|
+
[{type: "context", elements: [{type: "mrkdwn", text: "Includes app-side test hooks — the PR'\''s preview run validates them."}]}]
|
|
418
|
+
else [] end)
|
|
419
|
+
+ [{type: "actions", elements: (
|
|
420
|
+
(if $pr != "" then [btn("Review PR"; $pr)] else [] end)
|
|
421
|
+
+ [btn("View run"; $run)]
|
|
422
|
+
+ (if $result != "" then [btn("Checkly result"; $result)] else [] end)
|
|
423
|
+
+ (if $classification == "agent-failed" then [btn("Re-run heal"; $rerun)] else [] end)
|
|
424
|
+
)}]
|
|
425
|
+
+ [{type: "context", elements: [{type: "mrkdwn", text: ("[e2e:" + $repo + "]")}]}]
|
|
426
|
+
)
|
|
427
|
+
}' \
|
|
343
428
|
| curl -sf --max-time 15 -X POST -H "Content-Type: application/json" -d @- "$SLACK_WEBHOOK_URL" \
|
|
344
429
|
|| echo "Slack notification failed — see summary." >> "$GITHUB_STEP_SUMMARY"
|
|
345
430
|
|