-
Notifications
You must be signed in to change notification settings - Fork 1
143 lines (119 loc) · 4.78 KB
/
pr-triage.yml
File metadata and controls
143 lines (119 loc) · 4.78 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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
name: PR Triage
on:
workflow_call:
inputs:
pr_number:
description: "PR number to triage (optional, auto-detected from event)"
required: false
type: number
secrets:
COPILOT_GITHUB_TOKEN:
required: true
description: "Fine-grained PAT from a GitHub user with a Copilot license and Copilot Requests permission"
# The following trigger is commented out since this is a reusable workflow.
# Uncomment it if you want to use this workflow directly in this repository.
# pull_request:
# types: [opened]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
triage-pr:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Copilot CLI
run: npm install -g @github/copilot
- name: Collect PR context
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ inputs.pr_number || github.event.pull_request.number }}
run: |
set -euo pipefail
gh label list \
--repo "$GITHUB_REPOSITORY" \
--limit 200 \
--json name,description \
> labels.json
gh pr view "$PR_NUMBER" \
--repo "$GITHUB_REPOSITORY" \
--json number,title,body,files,labels,author,baseRefName,headRefName,isDraft,state,url \
> pr.json
- name: Select labels with Copilot
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
run: |
set -euo pipefail
copilot -s \
--no-ask-user \
--allow-tool=read \
-p "$(cat <<'PROMPT'
You are a GitHub pull request label triage assistant.
Read ./pr.json and ./labels.json.
Select labels that accurately describe the PR. Use only label names that already exist in labels.json.
Do not invent labels. Do not comment on the PR. Do not ask questions.
Prefer this taxonomy when the labels exist:
- type: bug, type: feature, type: docs, type: build, type: ci, type: tests, type: maintenance, type: question
- area:* labels for affected subsystem
- platform:* labels only when the change is platform-specific
- priority:* only when priority is explicit in the PR metadata
- impact:* only for clear user-visible impact such as crash, memory leak, or visual diff
- status:* only if already present or explicitly justified by the PR metadata
Use the PR title, body, existing labels, and changed file paths.
If unsure, choose fewer labels.
Output only a JSON array of label names, for example:
["type: feature","area: rendering"]
PROMPT
)" > copilot-output.txt
python3 <<'PY'
import json
import re
from pathlib import Path
raw = Path("copilot-output.txt").read_text()
labels = {label["name"] for label in json.loads(Path("labels.json").read_text())}
pr = json.loads(Path("pr.json").read_text())
existing = {label["name"] for label in pr.get("labels", [])}
try:
parsed = json.loads(raw)
except json.JSONDecodeError:
match = re.search(r"```(?:json)?\s*(\[[\s\S]*?\])\s*```", raw)
if match is None:
match = re.search(r"(\[[\s\S]*\])", raw)
if match is None:
raise SystemExit(f"Copilot output did not contain a JSON array:\n{raw}")
parsed = json.loads(match.group(1))
if not isinstance(parsed, list):
raise SystemExit(f"Copilot output must be a JSON array, got: {type(parsed).__name__}")
selected = []
for label in parsed:
if not isinstance(label, str):
continue
if label in labels and label not in existing and label not in selected:
selected.append(label)
Path("selected-labels.json").write_text(json.dumps(selected, indent=2) + "\n")
print(json.dumps(selected))
PY
- name: Apply labels
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ inputs.pr_number || github.event.pull_request.number }}
run: |
set -euo pipefail
if [ "$(jq 'length' selected-labels.json)" -eq 0 ]; then
echo "No new labels selected."
exit 0
fi
labels="$(jq -c '{labels: .}' selected-labels.json)"
gh api \
--method POST \
"/repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" \
--input - <<< "$labels"