88name : Roll to latest Playwright
99
1010on :
11- # Apply needs-roll to an issue to roll to the tip of main; re-apply it to trigger another roll.
12- issues :
13- types : [labeled]
11+ # Mon, Wed and Fri at 9:17 UTC: 2:17 at night Pacific time, 1:17 in winter. Not on the hour, when
12+ # GitHub delays scheduled runs. A scheduled roll skips while a roll pull request is open.
13+ schedule :
14+ - cron : " 17 9 * * 1,3,5"
1415 workflow_dispatch :
1516 inputs :
1617 ref :
2324permissions : {}
2425
2526jobs :
26- start :
27- name : Post the run link on the issue
28- if : github.repository == 'microsoft/playwright-python' && github.event.label.name == 'needs-roll'
29- runs-on : ubuntu-latest
30- permissions :
31- issues : write
32- outputs :
33- comment : ${{ steps.post.outputs.id }}
34- env :
35- ISSUE : ${{ github.event.issue.number }}
36- GH_TOKEN : ${{ github.token }}
37- GH_REPO : ${{ github.repository }}
38- WORKFLOW_URL : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
39- steps :
40- - name : Post the run link
41- id : post
42- run : |
43- body=$(printf "Hi, I'm the Playwright bot. I started to roll Playwright to the tip of main: [agent run](%s)\n<!-- playwright-roll-started -->" "$WORKFLOW_URL")
44- id=$(gh api "repos/$GH_REPO/issues/$ISSUE/comments" -f body="$body" --jq .node_id)
45- echo "id=$id" >> "$GITHUB_OUTPUT"
46-
4727 versions :
4828 name : Find the commit
49- if : >-
50- github.repository == 'microsoft/playwright-python' &&
51- (github.event_name == 'workflow_dispatch' || github.event.label.name == 'needs-roll')
29+ if : github.repository == 'microsoft/playwright-python'
5230 runs-on : ubuntu-24.04
5331 permissions :
5432 contents : read
33+ pull-requests : read
5534 outputs :
5635 old_commit : ${{ steps.versions.outputs.old_commit }}
5736 new_commit : ${{ steps.versions.outputs.new_commit }}
5837 new_short : ${{ steps.versions.outputs.new_short }}
38+ open_roll : ${{ steps.open.outputs.pr }}
5939 steps :
6040 - uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
6141 - name : Read the pinned and the new commit
@@ -71,16 +51,30 @@ jobs:
7151 echo "new_commit=${new_commit}"
7252 echo "new_short=${new_commit:0:10}"
7353 } >> "$GITHUB_OUTPUT"
54+ # A manual run rolls anyway: a maintainer asked for it.
55+ - name : Look for an open roll pull request
56+ id : open
57+ if : github.event_name == 'schedule'
58+ env :
59+ GH_TOKEN : ${{ github.token }}
60+ GH_REPO : ${{ github.repository }}
61+ run : |
62+ pr=$(gh pr list --state open --author app/microsoft-playwright-automation --json number,headRefName \
63+ --jq '[.[] | select(.headRefName | startswith("roll/")) | .number] | first // empty')
64+ if [[ -n "$pr" ]]; then
65+ echo "pr=$pr" >> "$GITHUB_OUTPUT"
66+ echo "Skipped: roll pull request #$pr is open." >> "$GITHUB_STEP_SUMMARY"
67+ fi
7468
7569 roll :
7670 name : Roll to ${{ needs.versions.outputs.new_short }}
7771 needs : versions
78- if : needs.versions.outputs.new_commit != needs.versions.outputs.old_commit
72+ if : >-
73+ needs.versions.outputs.new_commit != needs.versions.outputs.old_commit &&
74+ needs.versions.outputs.open_roll == ''
7975 # The runner of CI: the skill runs ./test.sh, both suites on all its cores.
8076 runs-on : playwright-x64-ubuntu24-64-core
8177 timeout-minutes : 240
82- # On the job and not on the workflow: every issue label starts this workflow, and a skipped
83- # run would replace a roll that waits in a group of the workflow.
8478 concurrency :
8579 group : roll
8680 cancel-in-progress : false
@@ -121,6 +115,8 @@ jobs:
121115 python scripts/upstream.py log "$OLD_COMMIT" > "$RUNNER_TEMP/commits.md"
122116 - name : Roll with Copilot CLI
123117 id : agent
118+ # No GitHub tools and no URL access: the agent reads upstream only from .upstream/, so text from
119+ # issues and PRs does not reach it.
124120 uses : microsoft/playwright/.github/actions/run-agent@main
125121 with :
126122 prompt : |
@@ -134,7 +130,6 @@ jobs:
134130 output-dir : ${{ env.OUTPUT_DIR }}
135131 result-file : summary.md
136132 artifact-name : roll
137- github-tools : true
138133 exec : ${{ env.CI_ENV_EXEC }}
139134 max-ai-credits : ${{ inputs.max_ai_credits || '3000' }}
140135 # The agent runs scripts/lint.sh last (step 5 of the skill); a roll that does
@@ -152,7 +147,6 @@ jobs:
152147 env :
153148 COMPLETE : ${{ steps.agent.outputs.outcome == 'success' && steps.check.outcome == 'success' }}
154149 TITLE : " chore: roll Playwright to ${{ steps.record.outputs.version }} (${{ needs.versions.outputs.new_short }})"
155- ISSUE_URL : ${{ github.event.issue.html_url }}
156150 COMPARE_URL : https://github.com/microsoft/playwright/compare/${{ needs.versions.outputs.old_commit }}...${{ needs.versions.outputs.new_commit }}
157151 RUN_URL : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
158152 run : |
@@ -186,8 +180,6 @@ jobs:
186180 commits.append(f"- … and {total - len(commits)} more: {env['COMPARE_URL']}")
187181 parts.append(f"<details>\n<summary>Upstream commits ({total})</summary>\n\n" + "\n".join(commits) + "\n\n</details>")
188182 parts.append(f"Upstream changes: {env['COMPARE_URL']}")
189- if env.get("ISSUE_URL"):
190- parts.append(f"Fixes {env['ISSUE_URL']}")
191183 Path(env["PATCH_DIR"], "pr-body.md").write_text("\n\n".join(parts) + "\n", encoding="utf-8")
192184 Path(env["PATCH_DIR"], "roll.json").write_text(json.dumps({"title": env["TITLE"]}) + "\n", encoding="utf-8")
193185 EOF
@@ -246,8 +238,10 @@ jobs:
246238 echo "The roll changes files outside DRIVER_VERSION, NODE_VERSION, README.md, playwright/, tests/ and python_rules.js." >&2
247239 exit 1
248240 fi
249- if git diff --cached --summary | grep ' mode 120000 '; then
250- echo "The roll adds a symbolic link." >&2
241+ # The new mode of each path, also when a file changes its type: 120000 is a symbolic link,
242+ # 160000 a submodule.
243+ if git diff --cached --raw --no-renames | awk '$2 ~ /^1[26]0000$/ { found = 1; print } END { exit !found }'; then
244+ echo "The roll adds a symbolic link or a submodule." >&2
251245 exit 1
252246 fi
253247 # Never execute code or scripts from the roll in the app job.
@@ -261,7 +255,6 @@ jobs:
261255 metadata : roll.json
262256 body-file : pr-body.md
263257 branch : roll/${{ needs.versions.outputs.new_short }}/${{ github.run_id }}-${{ github.run_attempt }}
264- commit-body : " ${{ github.event.issue.html_url && format('Fixes: {0}', github.event.issue.html_url) || '' }}"
265258 pull-request : true
266259 base : ${{ github.ref_name }}
267260 workflow-name : roll workflow
@@ -273,54 +266,3 @@ jobs:
273266 GH_REPO : ${{ github.repository }}
274267 PR : ${{ steps.publish.outputs.number }}
275268 run : gh pr ready "$PR"
276-
277- comment :
278- name : Comment on the issue
279- needs : [start, versions, roll, publish]
280- # Runs after every run that the label started, including failed ones, and whatever publish did.
281- if : ${{ !cancelled() && needs.start.result != 'skipped' }}
282- runs-on : ubuntu-latest
283- permissions :
284- issues : write
285- steps :
286- - name : Post the result and hide the run link
287- env :
288- GH_TOKEN : ${{ github.token }}
289- GH_REPO : ${{ github.repository }}
290- ISSUE : ${{ github.event.issue.number }}
291- START_COMMENT : ${{ needs.start.outputs.comment }}
292- VERSIONS_RESULT : ${{ needs.versions.result }}
293- OLD_COMMIT : ${{ needs.versions.outputs.old_commit }}
294- NEW_COMMIT : ${{ needs.versions.outputs.new_commit }}
295- ROLL_RESULT : ${{ needs.roll.result }}
296- SETUP_OUTCOME : ${{ needs.roll.outputs.setup }}
297- VERSION : ${{ needs.roll.outputs.version }}
298- COMPLETE : ${{ needs.roll.outputs.complete }}
299- PR_URL : ${{ needs.publish.outputs.pr }}
300- PUBLISH_RESULT : ${{ needs.publish.result }}
301- RUN_URL : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
302- run : |
303- commit="microsoft/playwright@${NEW_COMMIT:0:10}"
304- if [[ "$VERSIONS_RESULT" != "success" ]]; then
305- text="I couldn't roll Playwright: finding the commit to roll to failed."
306- elif [[ "$OLD_COMMIT" == "$NEW_COMMIT" ]]; then
307- text="Nothing to roll: \`DRIVER_VERSION\` is at the tip of main already, $commit."
308- elif [[ -n "$PR_URL" && "$COMPLETE" == "true" ]]; then
309- text="I rolled Playwright to $VERSION, $commit: $PR_URL"
310- elif [[ -n "$PR_URL" ]]; then
311- text="I rolled Playwright to $VERSION, $commit, but the roll is not complete: the agent or the checks failed. Draft PR: $PR_URL"
312- elif [[ "$PUBLISH_RESULT" == "failure" ]]; then
313- text="I rolled Playwright to $VERSION, $commit, but opening the pull request failed."
314- elif [[ "$SETUP_OUTCOME" == "failure" ]]; then
315- text="I couldn't roll Playwright to $commit: pinning, generating the API, building the driver or installing the browsers failed."
316- elif [[ "$ROLL_RESULT" == "success" ]]; then
317- text="I couldn't roll Playwright to $commit: the roll changed no file."
318- else
319- text="I couldn't roll Playwright to $commit: the roll job ended with result \`$ROLL_RESULT\`, for example after a timeout."
320- fi
321- printf "Hi, I'm the Playwright bot. %s\n\n<sub>Rolled by the Playwright bot - [agent run](%s)</sub>\n<!-- playwright-roll -->\n" "$text" "$RUN_URL" > "$RUNNER_TEMP/comment.md"
322- gh issue comment "$ISSUE" --body-file "$RUNNER_TEMP/comment.md"
323- if [[ -n "$START_COMMENT" ]]; then
324- gh api graphql -f query='mutation($id: ID!) { minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) { clientMutationId } }' -f id="$START_COMMENT" \
325- || echo "::warning::Could not hide the comment with the run link"
326- fi
0 commit comments