Skip to content

Commit 201a60c

Browse files
committed
ci(apollo-vertex): add PR size labeling workflow
1 parent 40e19a2 commit 201a60c

1 file changed

Lines changed: 202 additions & 0 deletions

File tree

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
name: Apollo Vertex PR Size
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- reopened
8+
- synchronize
9+
- ready_for_review
10+
- converted_to_draft
11+
branches: [main]
12+
paths:
13+
- "apps/apollo-vertex/**"
14+
15+
permissions:
16+
contents: read
17+
pull-requests: read
18+
19+
jobs:
20+
prepare-config:
21+
name: Prepare PR size config
22+
runs-on: ubuntu-24.04
23+
outputs:
24+
labels_json: ${{ steps.config.outputs.labels_json }}
25+
vertex_only: ${{ steps.scope.outputs.vertex_only }}
26+
steps:
27+
- name: Check for changes outside apollo-vertex
28+
id: scope
29+
env:
30+
GH_TOKEN: ${{ github.token }}
31+
GH_REPO: ${{ github.repository }}
32+
PR_URL: ${{ github.event.pull_request.html_url }}
33+
run: |
34+
FILES_OUTSIDE=$(gh pr diff "$PR_URL" --name-only | grep -v '^apps/apollo-vertex/' || true)
35+
if [ -n "$FILES_OUTSIDE" ]; then
36+
echo "vertex_only=false" >> "$GITHUB_OUTPUT"
37+
echo "Skipping PR size labeling — PR touches files outside apps/apollo-vertex/:"
38+
echo "$FILES_OUTSIDE"
39+
else
40+
echo "vertex_only=true" >> "$GITHUB_OUTPUT"
41+
fi
42+
- id: config
43+
name: Build PR size label config
44+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
45+
with:
46+
result-encoding: string
47+
script: |
48+
const managedLabels = [
49+
{ name: "size:XS", color: "0e8a16", description: "0-9 changed lines." },
50+
{ name: "size:S", color: "5ebd3e", description: "10-29 changed lines." },
51+
{ name: "size:M", color: "fbca04", description: "30-99 changed lines." },
52+
{ name: "size:L", color: "fe7d37", description: "100-499 changed lines." },
53+
{ name: "size:XL", color: "d93f0b", description: "500-999 changed lines." },
54+
{ name: "size:XXL", color: "b60205", description: "1,000+ changed lines." },
55+
];
56+
57+
core.setOutput("labels_json", JSON.stringify(managedLabels));
58+
sync-label-definitions:
59+
name: Sync PR size label definitions
60+
needs: prepare-config
61+
if: needs.prepare-config.outputs.vertex_only == 'true'
62+
runs-on: ubuntu-24.04
63+
permissions:
64+
contents: read
65+
issues: write
66+
steps:
67+
- name: Ensure PR size labels exist
68+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
69+
env:
70+
PR_SIZE_LABELS_JSON: ${{ needs.prepare-config.outputs.labels_json }}
71+
with:
72+
script: |
73+
const managedLabels = JSON.parse(process.env.PR_SIZE_LABELS_JSON ?? "[]");
74+
75+
for (const label of managedLabels) {
76+
try {
77+
const { data: existing } = await github.rest.issues.getLabel({
78+
owner: context.repo.owner,
79+
repo: context.repo.repo,
80+
name: label.name,
81+
});
82+
83+
if (
84+
existing.color !== label.color ||
85+
(existing.description ?? "") !== label.description
86+
) {
87+
await github.rest.issues.updateLabel({
88+
owner: context.repo.owner,
89+
repo: context.repo.repo,
90+
name: label.name,
91+
color: label.color,
92+
description: label.description,
93+
});
94+
}
95+
} catch (error) {
96+
if (error.status !== 404) {
97+
throw error;
98+
}
99+
100+
try {
101+
await github.rest.issues.createLabel({
102+
owner: context.repo.owner,
103+
repo: context.repo.repo,
104+
name: label.name,
105+
color: label.color,
106+
description: label.description,
107+
});
108+
} catch (createError) {
109+
if (createError.status !== 422) {
110+
throw createError;
111+
}
112+
}
113+
}
114+
}
115+
label:
116+
name: Label PR size
117+
needs: [prepare-config, sync-label-definitions]
118+
if: needs.prepare-config.outputs.vertex_only == 'true'
119+
runs-on: ubuntu-24.04
120+
permissions:
121+
contents: read
122+
issues: write
123+
concurrency:
124+
group: pr-size-${{ github.event.pull_request.number }}
125+
cancel-in-progress: true
126+
steps:
127+
- name: Sync PR size label
128+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
129+
env:
130+
PR_SIZE_LABELS_JSON: ${{ needs.prepare-config.outputs.labels_json }}
131+
with:
132+
script: |
133+
const issueNumber = context.payload.pull_request.number;
134+
const additions = context.payload.pull_request.additions ?? 0;
135+
const deletions = context.payload.pull_request.deletions ?? 0;
136+
const changedLines = additions + deletions;
137+
const managedLabels = JSON.parse(process.env.PR_SIZE_LABELS_JSON ?? "[]");
138+
139+
const managedLabelNames = new Set(managedLabels.map((label) => label.name));
140+
141+
const resolveSizeLabel = (totalChangedLines) => {
142+
if (totalChangedLines < 10) {
143+
return "size:XS";
144+
}
145+
146+
if (totalChangedLines < 30) {
147+
return "size:S";
148+
}
149+
150+
if (totalChangedLines < 100) {
151+
return "size:M";
152+
}
153+
154+
if (totalChangedLines < 500) {
155+
return "size:L";
156+
}
157+
158+
if (totalChangedLines < 1000) {
159+
return "size:XL";
160+
}
161+
162+
return "size:XXL";
163+
};
164+
165+
const nextLabelName = resolveSizeLabel(changedLines);
166+
167+
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
168+
owner: context.repo.owner,
169+
repo: context.repo.repo,
170+
issue_number: issueNumber,
171+
per_page: 100,
172+
});
173+
174+
for (const label of currentLabels) {
175+
if (!managedLabelNames.has(label.name) || label.name === nextLabelName) {
176+
continue;
177+
}
178+
179+
try {
180+
await github.rest.issues.removeLabel({
181+
owner: context.repo.owner,
182+
repo: context.repo.repo,
183+
issue_number: issueNumber,
184+
name: label.name,
185+
});
186+
} catch (removeError) {
187+
if (removeError.status !== 404) {
188+
throw removeError;
189+
}
190+
}
191+
}
192+
193+
if (!currentLabels.some((label) => label.name === nextLabelName)) {
194+
await github.rest.issues.addLabels({
195+
owner: context.repo.owner,
196+
repo: context.repo.repo,
197+
issue_number: issueNumber,
198+
labels: [nextLabelName],
199+
});
200+
}
201+
202+
core.info(`PR #${issueNumber}: ${changedLines} changed lines -> ${nextLabelName}`);

0 commit comments

Comments
 (0)