Skip to main content

check-pr-failures

Work through the failing CI checks on a pull request: classify each failure as caused by the PR, pre-existing, flaky or environmental, and iterate until the board is green or every remaining failure is evidenced as unrelated. Use when the user asks why CI is failing, to check or watch a PR's checks, or to work through test failures on a pull request (e.g. "why is CI failing on #12345", "check the failures on my PR", "/check-pr-failures 12345").

소스 정보

저장소
google/site-kit-wp
최근 소스 활동
2026년 10월 13일 19:17
감지된 SKILL.md 언어
영어
스타
1,403
포크
388

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
check-pr-failures
description
Work through the failing CI checks on a pull request: classify each failure as caused by the PR, pre-existing, flaky or environmental, and iterate until the board is green or every remaining failure is evidenced as unrelated. Use when the user asks why CI is failing, to check or watch a PR's checks, or to work through test failures on a pull request (e.g. "why is CI failing on #12345", "check the failures on my PR", "/check-pr-failures 12345").
argument-hint
[pr-number]
allowed-tools
Bash, Read, Grep, Glob, Edit, Write
# Check a pull request's CI failures Work through the CI checks on pull request **#$ARGUMENTS**. If no number was given, ask for one. The goal is not "make CI green". It is **to know why each check fails**, and to fix only what this PR caused. --- ## Step 0 — Watching the checks land (optional) When the PR has just been pushed, the checks take a while to complete and arrive in no useful order. Don't guess how long they will take. Estimate it from recent passing runs of the same workflow, using the workflow's file name from `.github/workflows/`: ``` gh run list --workflow <workflow-file> --status success --limit 5 --json databaseId,createdAt,updatedAt \ --jq '.[] | "\(.databaseId)\t\(((.updatedAt | fromdate) - (.createdAt | fromdate)) / 60 | floor) min"' ``` A run's time includes any time it spent queued. For the time of each job on its own, use one of those run IDs: ``` gh run view <run-id> --json jobs \ --jq '.jobs[] | select(.conclusion == "success") | "\(((.completedAt | fromdate) - (.startedAt | fromdate)) / 60 | floor) min\t\(.name)"' ``` Tell the user when to expect the slowest check. Rather than polling by hand, watch the checks and report each one as it lands: ``` gh api "repos/google/site-kit-wp/commits/$(gh pr view <number> --json headRefOid --jq .headRefOid)/check-runs?per_page=100" \ --jq '.check_runs[]? | select(.status=="completed") | select(.conclusion!="skipped") | "\(.conclusion|ascii_upcase): \(.name)"' ``` Poll every 45s, emitting only newly-completed checks, and stop once none are `in_progress`. Two things to get right while reporting: - **Say what is still pending**, not just what failed. "E2E failed" reads as a broken board when VRT and JS Tests have not reported yet. - **Job names can mislead.** Job names don't always say which suite they run. For example, the Playwright jobs are named after the WordPress version alone (`WordPress <version>`), while the E2E jobs are named `E2E (WordPress …)`. Check which workflow in `.github/workflows/` a job belongs to before attributing a failure. Set expectations up front where you can: if a check is known to be red for a reason already established, say so before it reports, so a red mark does not restart an investigation that is already settled. ## Step 1 — Collect the check results ``` gh pr checks <number> gh api "repos/google/site-kit-wp/commits/$(gh pr view <number> --json headRefOid --jq .headRefOid)/check-runs?per_page=100" \ --jq '.check_runs[] | select(.conclusion=="failure" or .status!="completed") | "\(.status)\t\(.conclusion // "-")\t\(.name)"' ``` **Stop and ask the user** if the PR can't be found or no checks have run. Record which checks fail and which pass. A workflow shows as failed when any one of its jobs fails, so "Code Linting and JS Tests failed" may mean only JS Tests failed — check job level, not workflow level, before telling anyone what broke. ## Step 2 — Get the failure detail ``` gh run view <run-id> --log-failed ``` Check-run **annotations are usually useless** (`Process completed with exit code 1`). The job log is what carries the failing test names and assertions. For VRT, the report linked from the PR comment shows reference/test/diff images side by side, which is often the fastest way to see what actually changed. If `gh` is unavailable, ask the user to install and authenticate it (`brew install gh && gh auth login`) rather than working from pasted log archives — job logs need auth and cannot be fetched anonymously. ## Step 3 — Classify every failure Classify **before** changing anything. Each class has a test that settles it: | Class | Test | Evidence it produces | | --- | --- | --- | | **Order-dependent / flaky** | First check whether CI already retried the test (see below). For a suite that CI does not retry, run the test alone (`npm run test:e2e -- --testPathPattern "<spec>"`), run it several times on the same commit, and check the job's recent runs on `develop` for the same failure (see Step 4). | Passes in isolation, fails in a full run. Or passes on some runs of the same commit and fails on others. Often a *different* subset each run — that variation is itself the evidence. | | **Pre-existing** | Check out the merge base (`git merge-base HEAD origin/develop`) in a worktree or detached HEAD, reproduce there | Fails without any of this PR's changes | | **Environmental** | Compare local against CI for the same commit | Fails locally, passes in CI (or vice versa) | | **Caused by this PR** | Everything else, once the above are excluded | Fails on every run here, and passes on every run at the merge base | **Most suites already retry in CI.** Check the job's workflow in `.github/workflows/` and the suite's test config to see how. For example, the JS Tests job reruns failed tests, and the VRT and Playwright suites retry failed tests. A test that failed every retry is very unlikely to be flaky, so don't spend time re-running it locally to prove otherwise. A VRT screenshot that failed and then passed on retry is not a failure: CI lists it as flaky in the PR comment and in the **VRT: flaky screenshots** check. Flakiness matters most for a suite with no retries, such as the `E2E (WordPress …)` jobs. Two further checks worth running before concluding anything: - **Search the issue tracker.** `gh issue list --repo google/site-kit-wp --state all --search "<area>"`. A test that looks broken is sometimes obsolete by design — a shipped decision removed the scenario it covers. Equally, a "new" bug may already be filed. - **Compare against other PRs.** If another open PR's run fails the same scenario, it is shared flakiness, not yours. This is especially useful for VRT. ## Step 4 — Apply the distinction that matters most **"The behaviour is pre-existing" and "the failure is unrelated to this PR" are different claims.** Once Step 3 has ruled out flakiness, a test that passes on `develop` and fails here is this PR's to resolve, even when the behaviour it trips over is older than the PR. For a suite that CI does not retry, one green run on `develop` does not rule out flakiness. A flaky test can pass there by chance and fail here by chance. Before you call such a failure the PR's, make sure the result repeats: the test fails on every run here and passes on every run at the merge base. Then check whether the same job has recently failed on `develop`: ``` gh run list --workflow <workflow-file> --branch develop --status failure --limit 10 gh run view <run-id> --log-failed ``` If any of those runs failed the same test, the test is flaky. Report it as flaky, with links to those runs. The common case: a suite runs against a different code path than production. For example, E2E sets feature flags through `tests/e2e/mu-plugins/e2e-rest-feature-flag.php`, which filters `googlesitekit_is_feature_enabled` at a late priority. It overrides any other code that enables a flag through the same filter, so E2E can exercise a path no user has taken for several releases. Removing a flag switches E2E onto the real path for the first time, and the resulting failures are in scope even though nothing about the underlying behaviour changed. Check the issue's **Test Coverage** section before arguing scope. "Ensure the remaining suites pass" makes the suites part of the deliverable. ## Step 5 — Decide an action per class - **Caused by this PR** — fix it. If a shared component genuinely misbehaves, fix the component rather than the assertion, and say so in the PR description. - **Obsolete** — remove the test, but only with evidence that the scenario can no longer occur (a linked issue, the code path, and ideally a manual check). Cite that evidence in the commit message. - **Flaky / pre-existing / environmental** — leave it, and report it with the evidence. Re-run the job if a green board is worth more than the caveat, but do not present a re-run as a fix. - **Someone else's broken fixture** — do not regenerate it. Report it so its owner can. ## Step 6 — Verify locally before pushing Reproduce locally first. A CI round trip takes as long as the slowest workflow the change triggers, which you can estimate as in Step 0. - **E2E needs `npm run build:test`**, not `npm run build` — a production build omits the E2E bundle and every spec then dies in `setupSiteKit()` waiting for `window._e2eApiFetch`. - **VRT runs in Docker** against a Storybook build made with `VRT=1`. Follow `tests/vrt/README.md` to run it: it covers when the build is made or reused, how to run only some stories, and the viewports. - After merging `develop`, re-run `npm install` — a merge can bring new dependencies. - Re-run the full suite after any fix. Semantic merge conflicts are common: `develop` can add a test asserting copy this PR renamed, and git merges both cleanly with no conflict markers. ## Step 7 — Report Produce a table, one row per failing check, and nothing that the evidence does not support: | Check | Failure | Class | Evidence | Action | | --- | --- | --- | --- | --- | | E2E (WordPress latest) | `write-scope-requests` ×2 | Obsolete | #11372 made the scope part of the initial request; confirmed in `get_refined_scopes()` and on a real site | Remove, citing #11372 | | JS Tests | `WelcomeModal` | Flaky | Passes in isolation; failing subset differs per run | Leave; note in PR | Then state plainly what is left failing and why, so the reviewer can check the reasoning rather than take it on trust. --- ## Guardrails - **Never mask a failure.** Do not suppress a console error, loosen an assertion, delete a test or approve a reference image to turn a check green. Every one of those hides a defect that will resurface later, usually for someone else. - **Do not touch artifacts this PR does not own** — another scenario's VRT references, another module's specs. A green board bought with scope creep is a worse PR. - **A test that fails is not automatically wrong.** Establish that its scenario is obsolete before removing it; "it's flaky" and "it's broken" are different findings. - **Do not claim a fix is verified until it has been run.** Say which suites were run and which were not. - **Ask before pushing, re-running jobs, or editing the PR.**
GitHub에서 보기