Skip to content

Commit f5793d4

Browse files
authored
Merge pull request #71 from Comfy-Org/easylabel-debug
feat: add EasyLabel workflow for automated PR labeling
2 parents e9d9c3c + a6f77eb commit f5793d4

File tree

3 files changed

+93
-22
lines changed

3 files changed

+93
-22
lines changed

.github/workflows/easylabel.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: "CorePing - Core PR Review Reminder"
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- easylabel-debug
8+
# paths:
9+
# - ".github/workflows/coreping.yaml"
10+
# - "app/tasks/coreping/**"
11+
12+
jobs:
13+
run_coreping:
14+
runs-on: ubuntu-latest
15+
timeout-minutes: 10
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: oven-sh/setup-bun@v2
19+
20+
# Install dependencies
21+
- run: bun i
22+
23+
# Run EasyLabel task
24+
- run: bun run/easylabel.tsx
25+
timeout-minutes: 10
26+
env:
27+
GH_TOKEN_COMFY_PR: ${{ secrets.GH_TOKEN_COMFY_PR_BOT }}
28+
MONGODB_URI: ${{ secrets.MONGODB_URI }}
29+
SLACK_BOT_CHANNEL: ${{ secrets.SLACK_BOT_CHANNEL }}
30+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

run/easylabel.tsx

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#!/usr/bin/env bun
12
import { tsmatch } from "@/packages/mongodb-pipeline-ts/Task";
23
import { db } from "@/src/db";
34
import { gh, type GH } from "@/src/gh";
@@ -20,15 +21,14 @@ import sflow, { pageFlow } from "sflow";
2021
* Add a label: Send a comment with "+label:[name]" (must have no space)
2122
* Remove a label: Send a comment with "-label:[name]" (must have no space)
2223
*
23-
* Bugcop:
2424
*/
2525

2626
const cfg = {
2727
REPOLIST: [
28-
"https://github.com/Comfy-Org/Comfy-PR",
2928
"https://github.com/comfyanonymous/ComfyUI",
30-
"https://github.com/Comfy-Org/ComfyUI_frontend",
31-
"https://github.com/Comfy-Org/desktop",
29+
// "https://github.com/Comfy-Org/Comfy-PR", // handled by webhook
30+
// "https://github.com/Comfy-Org/ComfyUI_frontend", // handled by webhook
31+
// "https://github.com/Comfy-Org/desktop", // handled by webhook
3232
],
3333
// allow all users to edit bugcop:*, area:*, Core-*, labels
3434
allow: [/^(?:Core|Core-.*)$/, /^(?:bug-cop|area):.*$/],
@@ -54,6 +54,35 @@ const saveTask = async (task: Partial<GithubIssueLabelOps> & { target_url: strin
5454

5555
if (import.meta.main) {
5656
await runLabelOpInitializeScan();
57+
await runLabelOpPolling();
58+
}
59+
async function runLabelOpPolling() {
60+
console.log(chalk.bgBlue("Start Label Ops Polling..."));
61+
// every 5s, check recent new comments for repo for 1min
62+
while (true) {
63+
await sflow(cfg.REPOLIST)
64+
.map((repoUrl) =>
65+
pageFlow(1, async (page, per_page = 100) => {
66+
console.log(`Listing issue comments for recent 5min`);
67+
const { data } = await gh.issues.listCommentsForRepo({
68+
...parseGithubRepoUrl(repoUrl),
69+
page,
70+
per_page,
71+
since: new Date(Date.now() - 5 * 60 * 1000).toISOString(),
72+
});
73+
return { data, next: data.length >= per_page ? page + 1 : null };
74+
}).flat(),
75+
)
76+
.confluenceByParallel()
77+
.forEach(async (comment) => {
78+
console.log(comment.html_url);
79+
const issue = await ghc.issues.get({ ...parseIssueUrl(comment.html_url) });
80+
await processIssueCommentForLableops({ issue: issue.data, comment });
81+
})
82+
.run();
83+
console.log(chalk.blue("Sleep 5s"));
84+
await new Promise((r) => setTimeout(r, 5000));
85+
}
5786
}
5887
/**
5988
* Scan all issues/prs and it's comments, and process them for label operations.
@@ -64,26 +93,35 @@ if (import.meta.main) {
6493
*
6594
*/
6695
async function runLabelOpInitializeScan() {
96+
console.log(chalk.bgBlue("Start Label Ops Initialization Scan..."));
6797
await sflow(cfg.REPOLIST)
68-
.flatMap((repoUrl) => [
98+
.map((repoUrl) =>
6999
pageFlow(1, async (page, per_page = 100) => {
70-
const { data } = await ghc.issues.list({ ...parseGithubRepoUrl(repoUrl), page, per_page, state: "open" });
100+
console.log(`Listing issues for ${repoUrl} page ${page}`);
101+
const { data } = await ghc.issues.listForRepo({
102+
...parseGithubRepoUrl(repoUrl),
103+
page,
104+
per_page,
105+
state: "open",
106+
});
107+
console.log(`Fetched ${data.length} issues from ${repoUrl} page ${page}`);
108+
return { data, next: data.length >= per_page ? page + 1 : null };
109+
}).flat(),
110+
)
111+
.confluenceByParallel()
112+
.map(async (issue) => {
113+
console.log(`+issue ${issue.html_url} with ${issue.comments} comments`);
114+
if (!issue.comments) return;
115+
await pageFlow(1, async (page, per_page = 100) => {
116+
const { data } = await ghc.issues.listComments({ ...parseIssueUrl(issue.html_url), page, per_page });
71117
return { data, next: data.length >= per_page ? page + 1 : null };
72118
})
73119
.flat()
74-
.map(async (issue) => {
75-
// processIssueComment({issue});
76-
if (!issue.comments) return;
77-
await pageFlow(1, async (page, per_page = 100) => {
78-
const { data } = await ghc.issues.listComments({ ...parseIssueUrl(issue.html_url), page, per_page });
79-
return { data, next: data.length >= per_page ? page + 1 : null };
80-
})
81-
.flat()
82-
.forEach((comment) => processIssueCommentForLableops({ issue, comment }))
83-
.run();
84-
}),
85-
])
120+
.forEach((comment) => processIssueCommentForLableops({ issue, comment }))
121+
.run();
122+
})
86123
.run();
124+
console.log(chalk.bgBlue("Label Ops Polling Done."));
87125
}
88126

89127
/**
@@ -94,15 +132,15 @@ export async function processIssueCommentForLableops({
94132
comment,
95133
}: {
96134
issue: GH["issue"];
97-
comment: GH["issue-comment"] | null;
135+
comment?: GH["issue-comment"] | null;
98136
}) {
99137
const target = comment || issue;
138+
console.log(" +COMMENT " + target.html_url + " len:" + target.body?.length);
100139
let task = await saveTask({
101140
target_url: target.html_url,
102141
issue_url: issue.html_url,
103142
type: comment ? "issue-comment" : "issue",
104143
});
105-
console.log(issue.html_url, target.body?.length);
106144
if (task?.processed_at && +new Date(target.updated_at) <= +task.processed_at) return null; // skip if processed
107145
if (!target.body) return task;
108146

@@ -121,7 +159,10 @@ export async function processIssueCommentForLableops({
121159

122160
if (!labelOps.length) return saveTask({ target_url: target.html_url, processed_at: new Date() });
123161

124-
console.log("Adding reaction");
162+
console.log("Found a matched Target URL:", target.html_url, labelOps.map((e) => e.op + e.name).join(", "));
163+
164+
// return task;
165+
console.log(chalk.blue("Adding reaction"));
125166
if (comment === target) {
126167
await gh.reactions.createForIssueComment({
127168
...parseIssueUrl(issue.html_url),

src/parseIssueUrl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
export function parseIssueUrl(issueUrl: string) {
55
const [owner, repo, strNumber] = issueUrl
6-
.match(/^https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(?:pull|issues)\/(\d+)$/)!
6+
.match(/^https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(?:pull|issues)\/(\d+)(?:#.*)?$/)!
77
.slice(1);
88
if (!owner || !repo || !strNumber) {
99
throw new Error(`Invalid issue URL: ${issueUrl}`);

0 commit comments

Comments
 (0)