Repository navigation
87 lines (82 loc) · 4.32 KB
/
Copy pathtriage-gate.yml
File metadata and controls
87 lines (82 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
name: Triage gate
# Every issue starts with `needs-triage`, and only a maintainer takes it off. The rules live in
# tools/triage_gate.py (documented in CONTRIBUTING.md, "Issue triage"):
# - an opened issue gets the label, however it was created (the issue forms add it themselves; the API and the
# `gh` CLI do not), unless a maintainer has already removed it;
# - an issue reopened by anyone but a maintainer goes back to triage;
# - the label removed by anyone but a maintainer is put back, with one comment;
# - hourly, the `sweep` job gives every open issue created since TRIAGE_SWEEP_SINCE that lacks the label the same
# decision, which repairs what an event run could not: a failed API call, a disabled workflow, an issue that a
# workflow created with its own GITHUB_TOKEN (such events start no other workflow).
# The script never removes the label: completing triage is the maintainer's decision.
#
# TRIAGE_SWEEP_SINCE is the day the gate went live. Issues created before it were classified by hand and are not
# swept; set it to the merge date of the pull request that introduced this workflow.
#
# This workflow runs on events anyone can cause (opening an issue), with permission to write to issues. Keep it
# that way on purpose; tests/test_triage_gate.py pins each of these properties:
# - the event triggers are `issues` / `opened`, `reopened` and `unlabeled` only (an edit cannot start a run);
# - the job `if:` reads event data only, never a shell: no `${{ }}` appears in a `run:` line, and the script
# reads the event file itself and never reads the issue's title or body;
# - the token holds `contents: read` and `issues: write` and nothing else;
# - the checkout action is pinned to a full commit SHA and takes one file of the default branch (what `issues`
# and `schedule` run on), with no stored credentials;
# - runs on one issue are queued, never run side by side, but a *pending* run may be replaced by a newer one.
# That drops nothing: the script decides from the issue's state (its labels and label history), not from the
# event that woke it, so the run that remains reaches the same answer.
#
# Events caused by a workflow's own GITHUB_TOKEN start no other workflow, so an issue that a workflow creates
# (nightly.yml opens the nightly-failure issue) carries the label from the start, and the sweep is the backstop.
#
# Maintainers: to switch the gate off at once, open Actions > "Triage gate" > the "..." menu > "Disable workflow".
# Labels already set stay as they are.
on:
issues:
types: [opened, reopened, unlabeled]
schedule:
- cron: "41 * * * *"
workflow_dispatch:
permissions: {}
jobs:
gate:
# Event data only. A removal of any other label is none of this workflow's business.
if: ${{ github.event_name == 'issues' && (github.event.action != 'unlabeled' || github.event.label.name == 'needs-triage') }}
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: triage-gate-${{ github.event.issue.number }}
cancel-in-progress: false
permissions:
contents: read # the checkout reads one script from the default branch
issues: write # add the label, and post the notice
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: tools/triage_gate.py
sparse-checkout-cone-mode: false
- name: Keep needs-triage until a maintainer removes it
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python3 tools/triage_gate.py
sweep:
if: ${{ github.event_name != 'issues' }}
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: triage-sweep
cancel-in-progress: false
permissions:
contents: read # the checkout reads one script from the default branch
issues: write # add the label, and post the notice
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: tools/triage_gate.py
sparse-checkout-cone-mode: false
- name: Label every recent issue that lacks needs-triage
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TRIAGE_SWEEP_SINCE: "2026-10-21T00:00:00Z"
run: python3 tools/triage_gate.py sweep