Skip to content

Commit 44c3d7a

Browse files
committed
Add benchmark workflow
1 parent 02cb81c commit 44c3d7a

2 files changed

Lines changed: 135 additions & 18 deletions

File tree

.github/workflows/check_pr.yaml

Lines changed: 133 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ on:
66
pr:
77
type: number
88
description: PR to check
9+
required: true
10+
action:
11+
type: choice
12+
description: Action to perform
13+
required: true
14+
default: check
15+
options: [check, bench]
916
left_rev:
1017
type: string
1118
description: Left (old) revision
@@ -35,9 +42,10 @@ jobs:
3542
permissions:
3643
issues: write
3744
outputs:
38-
pr-number: ${{ steps.pr-number.outputs.pr }}
45+
pr_number: ${{ steps.pr-number.outputs.pr }}
46+
action: ${{ steps.pr-number.outputs.action }}
3947
steps:
40-
- name: Get Issue
48+
- name: Get issue
4149
id: get-issue
4250
if: ${{ github.event_name == 'issues' || github.event_name == 'issue_comment' }}
4351
uses: actions-cool/issues-helper@v3
@@ -46,22 +54,35 @@ jobs:
4654
token: ${{ secrets.GITHUB_TOKEN }}
4755

4856
- name: Get PR number to check
49-
if: ${{ github.event_name == 'issues' || github.event_name == 'issue_comment' || inputs.pr != null }}
5057
id: pr-number
5158
run: |
52-
if [ -z "${INPUT_PR}" ]; then
53-
pr=$(sed -E 's/.*#([[:digit:]]+).*/\1/g' <<<"${ISSUE_TITLE}")
59+
if [ -z "${INPUT_PR}" ] || [ -z "$ACTION" ]; then
60+
case "${ISSUE_TITLE,,}" in
61+
'check #'*)
62+
pr=${ISSUE_TITLE##*#}
63+
action="check"
64+
;;
65+
'bench #'*)
66+
pr=${ISSUE_TITLE##*#}
67+
action="bench"
68+
;;
69+
*)
70+
pr="invalid"
71+
action="invalid"
72+
esac
5473
else
5574
pr=${INPUT_PR}
75+
action=${ACTION}
5676
fi
5777
5878
re='^[0-9]+$'
5979
if ! [[ "$pr" =~ $re ]]; then
60-
msg='No PR number found'
80+
msg="No PR number found"
6181
elif ! gh --repo python/mypy pr view "$pr"; then
6282
msg=$(printf "PR #%s not found in python/mypy" "$pr")
6383
else
64-
echo "pr=${pr}" >> "$GITHUB_OUTPUT"
84+
printf "pr=%s" "${pr}" >> "$GITHUB_OUTPUT"
85+
printf "action=%s" "${action}" >> "$GITHUB_OUTPUT"
6586
exit 0
6687
fi
6788
printf "%s\n" "$msg" >&2
@@ -70,6 +91,7 @@ jobs:
7091
env:
7192
GH_TOKEN: ${{ secrets.CUSTOM_GITHUB_PAT }}
7293
INPUT_PR: ${{ inputs.pr }}
94+
ACTION: ${{ inputs.action }}
7395
ISSUE_TITLE: ${{ steps.get-issue.outputs.issue-title }}
7496

7597
- name: Report failure
@@ -83,9 +105,15 @@ jobs:
83105
84106
Comment with any text to retry (feel free to edit the title beforehand).
85107
108+
Depending on the desider action, use the following issue titles:
109+
110+
* Check a PR against all open tickets: `Check #xxxxx`
111+
* Run a few benchmarks for a PR: `Bench #xxxxx` or `Benchmark #xxxx`
112+
86113
fetch:
87114
runs-on: ubuntu-latest
88-
if: ${{ !github.event.issue.pull_request }}
115+
needs: [get-target]
116+
if: ${{ !github.event.issue.pull_request && needs.get-target.outputs.action == 'check' }}
89117
steps:
90118
- uses: actions/cache/restore@v4
91119
id: restore-issues
@@ -120,7 +148,7 @@ jobs:
120148

121149
apply:
122150
runs-on: ubuntu-latest
123-
if: ${{ !github.event.issue.pull_request }}
151+
if: ${{ !github.event.issue.pull_request && needs.get-target.outputs.action == 'check' }}
124152
permissions:
125153
issues: write
126154
needs: [get-target, fetch]
@@ -152,7 +180,7 @@ jobs:
152180
--total-shards 2
153181
env:
154182
GH_ACCESS_TOKEN: ${{ secrets.CUSTOM_GITHUB_PAT }}
155-
PR: ${{ needs.get-target.outputs.pr-number }}
183+
PR: ${{ needs.get-target.outputs.pr_number }}
156184
TQDM_MININTERVAL: '5'
157185

158186
- name: Apply mypy (two versions)
@@ -190,7 +218,7 @@ jobs:
190218
191219
diff:
192220
runs-on: ubuntu-latest
193-
if: ${{ !github.event.issue.pull_request }}
221+
if: ${{ !github.event.issue.pull_request && needs.get-target.outputs.action == 'check' }}
194222
needs: [apply, get-target]
195223
permissions:
196224
issues: write
@@ -218,9 +246,9 @@ jobs:
218246
run: |
219247
uv run diff --no-snippets --diff-originals | tee out.txt
220248
{
221-
echo 'diff-text<<EOF';
222-
sed -e 's/\x1b\[1;3.m//g' -e 's/\x1b\[0m//g' out.txt;
223-
echo 'EOF';
249+
echo 'diff_text<<EOF'
250+
sed -e 's/\x1b\[1;3.m//g' -e 's/\x1b\[0m//g' out.txt
251+
echo 'EOF'
224252
} >> "$GITHUB_OUTPUT"
225253
env:
226254
GH_ACCESS_TOKEN: ${{ secrets.CUSTOM_GITHUB_PAT }}
@@ -232,12 +260,12 @@ jobs:
232260
actions: create-comment
233261
token: ${{ secrets.GITHUB_TOKEN }}
234262
body: |
235-
Results are ready!
263+
Check results are ready!
236264
237-
PR link: https://github.com/python/mypy/pull/${{ needs.get-target.outputs.pr-number }}
265+
PR link: https://github.com/python/mypy/pull/${{ needs.get-target.outputs.pr_number }}
238266
239267
```diff
240-
${{ steps.compare.outputs.diff-text }}
268+
${{ steps.compare.outputs.diff_text }}
241269
```
242270
243271
- name: Report failure
@@ -248,3 +276,91 @@ jobs:
248276
token: ${{ secrets.GITHUB_TOKEN }}
249277
body: |
250278
Sorry, something went wrong during diff generation.
279+
280+
bench:
281+
runs-on: ubuntu-latest
282+
if: ${{ !github.event.issue.pull_request && needs.get-target.outputs.action == 'bench' }}
283+
needs: [get-target]
284+
285+
strategy:
286+
matrix:
287+
iter: [1, 2, 3]
288+
outputs:
289+
result_run_1: ${{ steps.run-bench.outputs.result_run_1 }}
290+
result_run_2: ${{ steps.run-bench.outputs.result_run_2 }}
291+
result_run_3: ${{ steps.run-bench.outputs.result_run_3 }}
292+
293+
steps:
294+
- uses: actions/checkout@v4
295+
with:
296+
persist-credentials: false
297+
repository: python/mypy
298+
token: ${{ secrets.CUSTOM_GITHUB_PAT }}
299+
- uses: astral-sh/setup-uv@v6
300+
with:
301+
python-version: '3.12'
302+
303+
- name: Checkout PR
304+
id: get-hash
305+
run: |
306+
gh pr checkout "$PR_NUMBER"
307+
hash=$(git rev-parse HEAD)
308+
printf 'target_hash=%s' "$hash" >>"$GITHUB_OUTPUT"
309+
env:
310+
PR_NUMBER: ${{ needs.get-target.outputs.pr_number }}
311+
312+
- name: Run benchmark
313+
id: run-bench
314+
run: |
315+
uv pip install -e .
316+
python ./misc/perf_compare.py master "$PR_HEAD_HASH" | tee results.txt
317+
{
318+
printf 'result_run_%s<<EOF' "$SEQUENCE_NO"
319+
sed -ne '/===/,$ p' results.txt
320+
echo EOF
321+
} >>"$GITHUB_OUTPUT"
322+
env:
323+
PR_HEAD_HASH: ${{ steps.get-hash.outputs.target_hash }}
324+
SEQUENCE_NO: ${{ matrix.iter }}
325+
326+
- name: Report failure
327+
if: ${{ failure() && (github.event_name == 'issues' || github.event_name == 'issue_comment') }}
328+
uses: actions-cool/issues-helper@v3
329+
with:
330+
actions: create-comment
331+
token: ${{ secrets.GITHUB_TOKEN }}
332+
body: |
333+
Sorry, something went wrong during benchmark execution.
334+
335+
bench-report:
336+
runs-on: ubuntu-latest
337+
if: ${{ !github.event.issue.pull_request && needs.get-target.outputs.action == 'bench' }}
338+
needs: [get-target, bench]
339+
permissions:
340+
issues: write
341+
342+
steps:
343+
- name: Post results
344+
if: ${{ github.event_name == 'issues' || github.event_name == 'issue_comment' }}
345+
uses: actions-cool/issues-helper@v3
346+
with:
347+
actions: create-comment
348+
token: ${{ secrets.GITHUB_TOKEN }}
349+
body: |
350+
Benchmark results are ready!
351+
352+
PR link: https://github.com/python/mypy/pull/${{ needs.get-target.outputs.pr_number }}
353+
354+
Results over three rounds for selfcheck (N=15):
355+
356+
```
357+
${{ needs.bench.outputs.result_run_1 }}
358+
```
359+
360+
```
361+
${{ needs.bench.outputs.result_run_2 }}
362+
```
363+
364+
```
365+
${{ needs.bench.outputs.result_run_3 }}
366+
```

src/mypy_issues/issues.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ async def download_snippets( # noqa: C901
6060
inventory: list[InventoryItem] = []
6161
issues: dict[int, IssueWithComments] = {}
6262
seen: set[str] = set()
63+
last_known_issues: set[int] = set()
6364
removed_count = 0
6465
if INVENTORY_FILE.is_file() and ISSUES_FILE.is_file():
6566
inventory = load_inventory()
@@ -83,11 +84,11 @@ async def download_snippets( # noqa: C901
8384
comments = await _get_comments(gh, org, repo, since)
8485
# Just sync issues with new comments from scratch, that should be cheap.
8586
removed.update(comments.keys())
87+
last_known_issues = set(issues.keys())
8688
inventory, issues = _incremental_update(inventory, issues, removed)
8789
seen = {snip["filename"] for snip in inventory}
8890

8991
event = asyncio.Event()
90-
last_known_issues = set(issues.keys())
9192
new_issues: set[int] = set()
9293
async for batch in abatch(_get_issues(gh, event, org, repo, since), size=64):
9394
blocks = await asyncio.gather(*[

0 commit comments

Comments
 (0)