Skip to content

Commit fb78091

Browse files
authored
Merge pull request #813 from Pangjiping/feat/label-robot
chore: pr label check
2 parents d6fe24e + df16b74 commit fb78091

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
name: PR Label Check
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, reopened, labeled, unlabeled, synchronize]
6+
branches: [main]
7+
8+
permissions:
9+
pull-requests: write
10+
11+
jobs:
12+
check-labels:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/github-script@v7
16+
with:
17+
script: |
18+
const pr = context.payload.pull_request;
19+
const labels = pr.labels;
20+
const prNumber = pr.number;
21+
const owner = context.repo.owner;
22+
const repo = context.repo.repo;
23+
const marker = "<!-- LABEL_CHECK_BOT -->";
24+
25+
function suggestLabels(files) {
26+
const dirs = new Set();
27+
for (const f of files) {
28+
const p = f.filename.split("/");
29+
dirs.add(p[0]);
30+
if (p.length >= 2) dirs.add(p[0] + "/" + p[1]);
31+
}
32+
const s = [];
33+
34+
if (dirs.has("docs") || dirs.has("oseps") || dirs.has("specs") ||
35+
dirs.has("examples")) {
36+
s.push("documentation");
37+
}
38+
39+
if (dirs.has("components/egress")) s.push("component/egress");
40+
if (dirs.has("components/ingress")) s.push("component/ingress");
41+
if (dirs.has("components/execd")) s.push("component/execd");
42+
if (dirs.has("components/code-interpreter")) s.push("component/code-interpreter");
43+
if (dirs.has("components/internal")) {
44+
s.push("component/egress", "component/ingress");
45+
}
46+
47+
// k8s / server
48+
if (dirs.has("kubernetes")) s.push("component/k8s");
49+
if (dirs.has("server")) s.push("component/server");
50+
51+
// SDK
52+
if (dirs.has("sdks")) {
53+
s.push("sdks");
54+
if (dirs.has("sdks/go")) s.push("sdk/go");
55+
if (dirs.has("sdks/java")) s.push("sdk/java");
56+
if (dirs.has("sdks/python")) s.push("sdk/python");
57+
if (dirs.has("sdks/js")) s.push("sdk/js");
58+
if (dirs.has("sdks/csharp")) s.push("sdk/c#");
59+
}
60+
61+
return [...new Set(s)].sort();
62+
}
63+
64+
if (labels.length === 0) {
65+
const { data: files } = await github.rest.pulls.listFiles({
66+
owner, repo, pull_number: prNumber,
67+
});
68+
const suggested = suggestLabels(files);
69+
70+
const { data: allLabels } = await github.rest.issues.listLabelsForRepo({
71+
owner, repo,
72+
});
73+
74+
let tip = "";
75+
const suggestedSet = new Set(suggested);
76+
const allow = ["bug", "documentation", "feature", "dependencies", "packages"];
77+
const otherLabels = allLabels.filter(l =>
78+
!suggestedSet.has(l.name) && allow.includes(l.name)
79+
);
80+
if (suggested.length > 0) {
81+
tip = `\n\n📋 **Recommended labels** (based on changed files):\n`;
82+
for (const name of suggested) {
83+
tip += `- \`${name}\` ⬅️\n`;
84+
}
85+
if (otherLabels.length > 0) {
86+
tip += `\nOther available labels:\n`;
87+
for (const lab of otherLabels) {
88+
const desc = lab.description ? ` - ${lab.description}` : "";
89+
tip += `- \`${lab.name}\`${desc}\n`;
90+
}
91+
}
92+
}
93+
94+
const touchedDirs = [...new Set(files.map(f => f.filename.split("/")[0]))].join("、");
95+
const hint = `\n\n💡 Tip: Use \`feature\` for new functionality or improvements, \`bug\` for fixes.`;
96+
const { data: comments } = await github.rest.issues.listComments({
97+
owner, repo, issue_number: prNumber,
98+
});
99+
const existing = comments.filter(
100+
c => c.user?.type === "Bot" && c.body?.includes(marker)
101+
);
102+
if (existing.length === 0) {
103+
await github.rest.issues.createComment({
104+
owner, repo, issue_number: prNumber,
105+
body: `${marker}
106+
⚠️ This PR has no labels. Please add one based on the changes.
107+
108+
Changed directories: ${touchedDirs}.${tip}${hint}
109+
110+
cc @${pr.user.login}`,
111+
});
112+
}
113+
} else {
114+
const { data: comments } = await github.rest.issues.listComments({
115+
owner, repo, issue_number: prNumber,
116+
});
117+
const botComments = comments.filter(
118+
c => c.user?.type === "Bot" && c.body?.includes(marker)
119+
);
120+
for (const c of botComments) {
121+
await github.rest.issues.deleteComment({
122+
owner, repo, comment_id: c.id,
123+
});
124+
}
125+
}

0 commit comments

Comments
 (0)