diff --git a/.claude/skills/dev/roll.md b/.claude/skills/dev/roll.md index 13a7d179..6e4ce4d9 100644 --- a/.claude/skills/dev/roll.md +++ b/.claude/skills/dev/roll.md @@ -41,11 +41,12 @@ Nothing is written when blocked: the merges with conflict markers go to `.roll/c ## Automation -- `.github/workflows/upstream-roll.yml` runs daily: detects a newer, old-enough `patchright-core`, rolls it on `roll_`, runs `ci.yml` on that branch and waits for it (`.github/actions/ci-on-branch`), and opens the PR with the report. `safe` + green CI is merged automatically; `review` waits for a human (label `needs-review`); `blocked` opens an issue (label `upstream-blocked`) with the report and the conflicted merges and writes nothing; scheduled runs skip that version while the issue is open. Manual runs take a version, `dry_run` (report only) and `force`. +- `.github/workflows/upstream-roll.yml` runs daily: detects a newer, old-enough `patchright-core`, rolls it on `roll_`, runs `ci.yml` on that branch and waits for it (`.github/actions/ci-on-branch`), and opens the PR with the report, closing any older `roll_*` PR it supersedes. `safe` + green CI is merged automatically; `review` waits for a human (label `needs-review`); `blocked` opens an issue (label `upstream-blocked`) with the report and the conflicted merges and writes nothing; scheduled runs skip that version while the issue is open. Manual runs take a version, `dry_run` (report only) and `force`. - `.github/workflows/upstream-playwright-cli.yml` runs weekly with the same verdicts for `microsoft/playwright-cli` (`npm run watch:playwright-cli`, `--apply` to take a clean merge). - Both workflows need Issues enabled on the repository (a fork has them off by default) for the `blocked` verdict to land anywhere; without them the lookup only warns, but a blocked roll fails the job with the report in the summary and the artifact. - The automatic merge uses the workflow token: keep the repository setting "Allow GitHub Actions to create and approve pull requests" on, and do not require reviews in the `main` ruleset, or the merge step only leaves a comment and the PR waits. - The `main` ruleset requires the CI job names (` / node `) on the PR head. A PR opened with the workflow token starts no CI, and a reusable `ci.yml` call would put its checks on the caller's commit under `test / ...`, so the workflows dispatch `ci.yml` on the branch instead: `workflow_dispatch` is the one event the workflow token may start, and its checks land on the branch head under the plain names. Change the ruleset's required checks together with the matrix in `ci.yml`, or every PR stays blocked. +- The dispatched run decides the verdict but does not unblock the merge: the ruleset counts only the PR's own `pull_request` run, and GitHub holds that run in `action_required` when the workflow token pushed the branch. Until a human approves it (Actions, or `gh api -X POST repos///actions/runs//approve`), the merge step only comments. Each daily re-roll force-pushes the branch and needs a fresh approval; fully automatic merges would need a GitHub App or PAT for the push. ## Start of a session diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a7da1e4..04d3ffdb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,18 @@ jobs: - name: Environment report run: node bin/patchright-cli.js doctor || echo "doctor reported issues (see above)" - run: npm run test:unit + # A fresh runner reads the preinstalled Chrome from a cold disk: its first launch has taken + # up to a minute, which landed in the 60 s budget of whichever integration tests ran first + # and in the 10 s `chrome --version` probe (headless-user-agent-unknown instead of the + # headless-user-agent note). Pay that cost once here, outside any test. + - name: Warm up Chrome + timeout-minutes: 5 + continue-on-error: true + env: + PATCHRIGHT_CLI_HOME: ${{ runner.temp }}/warmup + run: | + node bin/patchright-cli.js -s=warmup open about:blank + node bin/patchright-cli.js -s=warmup close - run: npm run test:integration - name: Stealth tests (headed Chrome) if: runner.os == 'Linux' diff --git a/.github/workflows/upstream-roll.yml b/.github/workflows/upstream-roll.yml index dba246dd..eb53d71c 100644 --- a/.github/workflows/upstream-roll.yml +++ b/.github/workflows/upstream-roll.yml @@ -192,11 +192,25 @@ jobs: gh pr edit "$number" --body-file body.md --add-label "$labels" fi echo "number=$number" >> "$GITHUB_OUTPUT" + # Each roll starts from main, so an older roll still open is only noise: close it in favour + # of this one. A manual run for an older version leaves newer rolls alone. + - name: Close older roll pull requests + env: + NUMBER: ${{ steps.pr.outputs.number }} + run: | + for old in $(gh pr list --state open --json headRefName --jq '.[].headRefName | select(startswith("roll_"))'); do + [ "$old" = "$BRANCH" ] && continue + [ "$(printf '%s\n%s\n' "${old#roll_}" "$TARGET" | sort -V | tail -n 1)" = "$TARGET" ] || continue + gh pr close "$old" --delete-branch --comment "Superseded by #$NUMBER (patchright-core $TARGET)." \ + || echo "::warning::Could not close $old, superseded by #$NUMBER." + done + # A push by this workflow's token gets its pull_request CI run held for approval, and the + # ruleset only counts checks from that run, so the merge below fails until someone approves it. - name: Merge automatically (safe roll, green CI) if: env.CLASSIFICATION == 'safe' && steps.ci.outputs.result == 'success' run: | gh pr merge "${{ steps.pr.outputs.number }}" --squash --delete-branch \ - || gh pr comment "${{ steps.pr.outputs.number }}" --body "The roll is safe and CI is green, but the workflow could not merge (the \`main\` ruleset or repository settings). Merge by hand." + || gh pr comment "${{ steps.pr.outputs.number }}" --body "The roll is safe and CI is green, but the workflow could not merge: the \`main\` ruleset counts only the pull request's own CI run, which GitHub holds for approval on a push by the workflow token. Approve that run (Actions, the \`CI\` run marked *action required* on this branch), wait for it to pass, then merge." - name: Explain why the pull request stays open if: env.CLASSIFICATION != 'safe' || steps.ci.outputs.result != 'success' env: