Skip to content

Commit e98b3c4

Browse files
snomiaoclaude
andcommitted
feat(workflows): add CorePing GitHub workflow for Core PR review reminders
Add scheduled workflow to run coreping task at 11am San Francisco time (19:00 UTC), Monday through Saturday. This service tracks Core/Core-Important PRs and sends reminder notifications to @comfyanonymous for unreviewed PRs. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 7849416 commit e98b3c4

File tree

2 files changed

+92
-3
lines changed

2 files changed

+92
-3
lines changed

.github/workflows/coreping.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: "CorePing - Core PR Review Reminder"
2+
3+
on:
4+
schedule:
5+
# Runs at 11am San Francisco time (19:00 UTC), Monday to Saturday
6+
# 0 19 * * 1-6 means: minute=0, hour=19 (7pm UTC), any day of month, any month, Mon-Sat (1-6)
7+
- cron: "0 19 * * 1-6"
8+
workflow_dispatch:
9+
push:
10+
branches:
11+
- main
12+
paths:
13+
- ".github/workflows/coreping.yaml"
14+
- "app/tasks/coreping/**"
15+
16+
jobs:
17+
run_coreping:
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 10
20+
steps:
21+
- uses: actions/checkout@v4
22+
- uses: oven-sh/setup-bun@v1
23+
24+
# Install dependencies
25+
- run: bun i
26+
27+
# Run CorePing task
28+
- run: bun app/tasks/coreping/index.tsx
29+
timeout-minutes: 8
30+
env:
31+
GH_TOKEN_COMFY_PR: ${{ secrets.GH_TOKEN_COMFY_PR_BOT }}
32+
MONGODB_URI: ${{ secrets.MONGODB_URI }}
33+
SLACK_BOT_CHANNEL: ${{ secrets.SLACK_BOT_CHANNEL }}
34+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

app/tasks/coreping/index.tsx

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { tsmatch } from "@/packages/mongodb-pipeline-ts/Task";
44
import { db } from "@/src/db";
5+
import { TaskMetaCollection } from "@/src/db/TaskMeta";
56
import type { GH } from "@/src/gh";
67
import { ghc } from "@/src/ghc";
78
import { parseIssueUrl } from "@/src/parseIssueUrl";
@@ -10,6 +11,8 @@ import DIE from "@snomiao/die";
1011
import chalk from "chalk";
1112
import sflow, { pageFlow } from "sflow";
1213
import { P } from "ts-pattern";
14+
import z from "zod";
15+
import { upsertSlackMessage } from "../gh-desktop-release-notification/upsertSlackMessage";
1316
/**
1417
* [Comfy- CorePing] The Core/Important PR Review Reminder Service
1518
* This service reminders @comfyanonymous for unreviewed Core/Core-Important PRs every 24 hours in the morning 8am of california
@@ -41,6 +44,9 @@ export const coreReviewTrackerConfig = {
4144
],
4245
labels: ["Core", "CoreImportant"],
4346
minReminderInterval: "24h", // edit-existed-slack-message < this-interval < send-another-slack-message
47+
slackChannelName: "sno-test-channel", // develop channel, without notification
48+
49+
// github message
4450
messageUpdatePattern: "<!-- COMFY_PR_BOT_TRACKER -->",
4551
staleMessage: `<!-- COMFY_PR_BOT_TRACKER --> This PR has been waiting for a response for too long. A reminder is being sent to @comfyanonymous.`,
4652
reviewedMessage: `<!-- COMFY_PR_BOT_TRACKER --> This PR is reviewed! When it's ready for review again, please add a comment with **+label:Core-Ready-for-Review** to reminder @comfyanonymous to restart the review process.`,
@@ -71,6 +77,26 @@ type ComfyCorePRs = {
7177
task_updated_at: Date;
7278
};
7379
export const ComfyCorePRs = db.collection<ComfyCorePRs>("ComfyCorePRs");
80+
81+
/* only one */
82+
// type ComfyCorePRsLastMessage = {
83+
// url: string;
84+
// text: string;
85+
// };
86+
// export const ComfyCorePRsLastMessage = db.collection<ComfyCorePRsLastMessage>("ComfyCorePRsLastMessage");
87+
const Meta = TaskMetaCollection(
88+
"ComfyCorePRs",
89+
z.object({
90+
lastSlackMessage: z
91+
.object({
92+
url: z.string(),
93+
text: z.string(),
94+
sendAt: z.date(),
95+
})
96+
.optional(),
97+
}),
98+
);
99+
74100
const saveTask = async (pr: Partial<ComfyCorePRs> & { url: string }) => {
75101
return (
76102
(await ComfyCorePRs.findOneAndUpdate(
@@ -82,6 +108,9 @@ const saveTask = async (pr: Partial<ComfyCorePRs> & { url: string }) => {
82108
};
83109

84110
if (import.meta.main) {
111+
// Designed to be mon to sat, TIME CHECKING
112+
// Pacific Daylight Time
113+
85114
console.log("start", import.meta.file);
86115
let freshCount = 0;
87116

@@ -171,7 +200,8 @@ if (import.meta.main) {
171200
const status = isReviewed ? "reviewed" : isCommented ? "reviewed" : isFresh ? "fresh" : "stale";
172201

173202
const hours = Math.floor(diff / (60 * 60 * 1000));
174-
const statusMsg = `${corePrLabel.name} PR <${pr.html_url}|${pr.title.replace(/\W+/g, " ").trim()}> has been labeled for more than ${hours} hours.`;
203+
const santizedTitle = pr.title.replace(/\W+/g, " ").trim();
204+
const statusMsg = `@${pr.user?.login}'s ${corePrLabel.name} PR <${pr.html_url}|${santizedTitle}> is waiting for your feedback for more than ${hours} hours.`;
175205
console.log(statusMsg);
176206
console.log(pr.html_url + " " + pr.labels.map((e) => e.name));
177207

@@ -197,7 +227,7 @@ if (import.meta.main) {
197227
})
198228
.run();
199229

200-
const corePRs = await ComfyCorePRs.find({}).sort({ last_labeled_at: -1 }).toArray();
230+
const corePRs = await ComfyCorePRs.find({}).sort({ last_labeled_at: 1 }).toArray();
201231

202232
console.log("ready to send slack message to notify @comfy");
203233
const staleCorePRs = corePRs.filter((pr) => pr.status === "stale");
@@ -206,13 +236,38 @@ if (import.meta.main) {
206236
.join("\n");
207237
const freshCorePRs = corePRs.filter((pr) => pr.status === "fresh");
208238

209-
const notifyMessage = `Hey <@comfy>, Here's x${staleCorePRs.length} Core/Important PRs waiting your feedback!\n\n${staleCorePRsMessage}\n... and there are ${freshCorePRs.length} more fresh Core/Core-Important PRs.\n cc <@Yoland> <@snomiao>`;
239+
const freshMsg = !freshCorePRs ? "" : `and there are ${freshCorePRs.length} more fresh Core/Core-Important PRs.\n`;
240+
const notifyMessage = `Hey <@comfy>, Here's x${staleCorePRs.length} Core/Important PRs waiting your feedback!\n\n${staleCorePRsMessage}\n${freshMsg}\nSent from <CorePing> by <@snomiao> cc <@Yoland>`;
210241
console.log(chalk.bgBlue(notifyMessage));
211242

212243
// TODO: update message with delete line when it's reviewed
244+
// send or update slack message
245+
let meta = await Meta.$upsert({});
246+
if (meta.lastSlackMessage) {
247+
// if <24 h since last sent (not edit), update that msg
248+
if (
249+
meta.lastSlackMessage.sendAt &&
250+
new Date().getTime() - new Date(meta.lastSlackMessage.sendAt).getTime() < 24 * 60 * 60 * 1000
251+
) {
252+
const msg = await upsertSlackMessage({
253+
text: notifyMessage,
254+
channelName: cfg.slackChannelName,
255+
url: meta.lastSlackMessage.url,
256+
});
257+
meta = await Meta.$upsert({ lastSlackMessage: { text: msg.text, url: msg.url, sendAt: new Date() } });
258+
} else {
259+
// if >24h, deprecate last message and post a new msg
260+
const msg = await upsertSlackMessage({
261+
text: notifyMessage,
262+
channelName: cfg.slackChannelName,
263+
});
264+
meta = await Meta.$upsert({ lastSlackMessage: { text: msg.text, url: msg.url, sendAt: new Date() } });
265+
}
266+
}
213267

214268
console.log("done", import.meta.file);
215269
}
270+
216271
/**
217272
* get full timeline
218273
* - [Issue event types - GitHub Docs]( https://docs.github.com/en/rest/using-the-rest-api/issue-event-types?apiVersion=2022-11-28 )

0 commit comments

Comments
 (0)