comfy-pr 0.2.24 → 0.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -225
- package/index.ts +6 -0
- package/next-env.d.ts +5 -5
- package/package.json +52 -25
- package/src/Authors.ts +42 -48
- package/src/CMNodes.ts +60 -60
- package/src/CNRepos.ts +78 -74
- package/src/CRNodes.ts +27 -27
- package/src/CRPulls.ts +4 -4
- package/src/EmailTasks.ts +101 -0
- package/src/FORK_OWNER.ts +5 -5
- package/src/FORK_PREFIX.ts +5 -5
- package/src/FollowRules.ts +25 -25
- package/src/GIT_USEREMAIL.ts +5 -5
- package/src/GIT_USERNAME.ts +9 -9
- package/src/GithubIssueComments.ts +3 -3
- package/src/PushedBranch.ts +3 -3
- package/src/Totals.ts +24 -9
- package/src/TrackingPRs.ts +12 -12
- package/src/WorkerInstances.ts +89 -89
- package/src/addCommentAction.ts +73 -65
- package/src/analyzePullsStatus.ts +219 -170
- package/src/analyzeTotals.test.ts +5 -5
- package/src/analyzeTotals.ts +118 -118
- package/src/bypassRepos.spec.ts +10 -0
- package/src/bypassRepos.ts +8 -0
- package/src/checkComfyActivated.ts +39 -39
- package/src/checkPRsFailures.ts +18 -0
- package/src/cli.ts +40 -40
- package/src/clone_modify_push_Branches.ts +21 -21
- package/src/createComfyRegistryPRsFromCandidates.ts +55 -55
- package/src/createComfyRegistryPullRequests.ts +32 -22
- package/src/createGithubForkForRepo.ts +54 -37
- package/src/createGithubPullRequest.ts +157 -94
- package/src/createIssueComment.ts +34 -29
- package/src/fetchCMNodes.ts +22 -22
- package/src/fetchComfyRegistryNodes.ts +11 -11
- package/src/fetchCurrentGeoInfo.ts +6 -6
- package/src/fetchRelatedPullWithComments.ts +15 -15
- package/src/fetchRepoDescriptionMap.ts +15 -15
- package/src/followRuleSchema.ts +79 -76
- package/src/getActivatedShell.ts +18 -18
- package/src/getBranchWorkingDir.ts +16 -16
- package/src/getRepoWorkingDir.ts +5 -5
- package/src/ghUser.ts +9 -6
- package/src/index.ts +26 -22
- package/src/initializeFollowRules.ts +26 -26
- package/src/makePublishBranch.ts +58 -58
- package/src/makeTomlBranch.ts +53 -53
- package/src/makeUpdateTomlLicenseBranch.ts +245 -0
- package/src/matchRelatedPulls.ts +47 -60
- package/src/muteInstances.ts +16 -16
- package/src/parseIssueUrl.ts +6 -6
- package/src/parseOwnerRepo.ts +33 -33
- package/src/parsePullUrl.ts +6 -6
- package/src/parsePullsState.ts +6 -6
- package/src/parseTitleBodyOfMarkdown.ts +8 -8
- package/src/postSlackMessage.ts +21 -21
- package/src/preload.ts +30 -30
- package/src/pullStatusFollowSchema.ts +12 -12
- package/src/readTemplateTitle.ts +11 -11
- package/src/sendEmailAction.ts +56 -0
- package/src/sendGmail.ts +105 -0
- package/src/showFollowRuleSet.ts +12 -12
- package/src/summaryLastPullComment.ts +8 -8
- package/src/tomlFillDescription.ts +17 -17
- package/src/updateAuthors.ts +7 -7
- package/src/updateAuthorsForGithub.ts +54 -50
- package/src/updateAuthorsFromCNRepo.ts +30 -30
- package/src/updateCMNodesDuplicationWarnings.ts +56 -56
- package/src/updateCMRepos.ts +27 -27
- package/src/updateCNRepos.ts +58 -58
- package/src/updateCNReposCRPullsComments.ts +40 -40
- package/src/updateCNReposInfo.ts +58 -57
- package/src/updateCNReposPRCandidate.ts +85 -85
- package/src/updateCNReposPulls.ts +31 -28
- package/src/updateCNReposPullsDashboard.ts +49 -49
- package/src/updateCNReposRelatedPulls.ts +25 -25
- package/src/updateCRNodes.ts +50 -50
- package/src/updateCRRepos.ts +26 -26
- package/src/updateComfyTotals.ts +43 -43
- package/src/updateFollowRuleSet.ts +136 -127
- package/src/updateOutdatedPullsTemplates.ts +165 -160
- package/src/updateSlackMessages.ts +43 -43
- package/tailwind.config.ts +75 -20
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import DIE from "@snomiao/die";
|
|
2
|
-
import pMap from "p-map";
|
|
3
|
-
import { match } from "ts-pattern";
|
|
4
|
-
import { $OK, TaskError, TaskOK } from "../packages/mongodb-pipeline-ts/Task";
|
|
5
|
-
import { CNRepos } from "./CNRepos";
|
|
6
|
-
import { $filaten, $stale } from "./db";
|
|
7
|
-
import { matchRelatedPulls } from "./matchRelatedPulls";
|
|
8
|
-
import { tLog } from "./utils/tLog";
|
|
9
|
-
if (import.meta.main) {
|
|
10
|
-
await tLog("updateCNReposRelatedPulls", updateCNReposRelatedPulls);
|
|
11
|
-
}
|
|
12
|
-
export async function updateCNReposRelatedPulls() {
|
|
13
|
-
await CNRepos.createIndex({ "pulls.state": 1, "crPulls.mtime": 1 });
|
|
14
|
-
return await pMap(
|
|
15
|
-
CNRepos.find($filaten({ pulls: { state: "ok" }, crPulls: { mtime: $stale("1d") } })),
|
|
16
|
-
async (repo, i) => {
|
|
17
|
-
const { repository } = repo;
|
|
18
|
-
const pulls = match(repo.pulls)
|
|
19
|
-
.with($OK, (e) => e.data)
|
|
20
|
-
.otherwise(() => DIE("Pulls not found"));
|
|
21
|
-
const crPulls = await matchRelatedPulls(pulls).then(TaskOK).catch(TaskError);
|
|
22
|
-
return await CNRepos.updateOne({ repository }, { $set: { crPulls } });
|
|
23
|
-
},
|
|
24
|
-
);
|
|
25
|
-
}
|
|
1
|
+
import DIE from "@snomiao/die";
|
|
2
|
+
import pMap from "p-map";
|
|
3
|
+
import { match } from "ts-pattern";
|
|
4
|
+
import { $OK, TaskError, TaskOK } from "../packages/mongodb-pipeline-ts/Task";
|
|
5
|
+
import { CNRepos } from "./CNRepos";
|
|
6
|
+
import { $filaten, $stale } from "./db";
|
|
7
|
+
import { matchRelatedPulls } from "./matchRelatedPulls";
|
|
8
|
+
import { tLog } from "./utils/tLog";
|
|
9
|
+
if (import.meta.main) {
|
|
10
|
+
await tLog("updateCNReposRelatedPulls", updateCNReposRelatedPulls);
|
|
11
|
+
}
|
|
12
|
+
export async function updateCNReposRelatedPulls() {
|
|
13
|
+
await CNRepos.createIndex({ "pulls.state": 1, "crPulls.mtime": 1 });
|
|
14
|
+
return await pMap(
|
|
15
|
+
CNRepos.find($filaten({ pulls: { state: "ok" }, crPulls: { mtime: $stale("1d") } })),
|
|
16
|
+
async (repo, i) => {
|
|
17
|
+
const { repository } = repo;
|
|
18
|
+
const pulls = match(repo.pulls)
|
|
19
|
+
.with($OK, (e) => e.data)
|
|
20
|
+
.otherwise(() => DIE("Pulls not found"));
|
|
21
|
+
const crPulls = await matchRelatedPulls(pulls).then(TaskOK).catch(TaskError);
|
|
22
|
+
return await CNRepos.updateOne({ repository }, { $set: { crPulls } });
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
}
|
package/src/updateCRNodes.ts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { $pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
|
|
2
|
-
import { peekYaml } from "peek-log";
|
|
3
|
-
import { filter, groupBy, values } from "rambda";
|
|
4
|
-
import YAML from "yaml";
|
|
5
|
-
import { TaskOK } from "../packages/mongodb-pipeline-ts/Task";
|
|
6
|
-
import { CNRepos } from "./CNRepos";
|
|
7
|
-
import { CRNodes } from "./CRNodes";
|
|
8
|
-
import { fetchCRNodes } from "./fetchComfyRegistryNodes";
|
|
9
|
-
import { notifySlack } from "./slack/notifySlack";
|
|
10
|
-
import { tLog } from "./utils/tLog";
|
|
11
|
-
|
|
12
|
-
if (import.meta.main) {
|
|
13
|
-
peekYaml(await tLog(updateCRNodes));
|
|
14
|
-
console.log("CRNodes updated");
|
|
15
|
-
|
|
16
|
-
peekYaml(
|
|
17
|
-
await $pipeline(CNRepos).project({ repository: 1, on_registry: 1 }).sample({ size: 8 }).aggregate().toArray(),
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
export async function updateCRNodes() {
|
|
21
|
-
const nodes = await fetchCRNodes();
|
|
22
|
-
|
|
23
|
-
// check src duplicated
|
|
24
|
-
const group = groupBy((e) => e.repository, nodes);
|
|
25
|
-
const duplicates = filter((e) => e.length > 1, group);
|
|
26
|
-
if (values(duplicates).length) {
|
|
27
|
-
const msg =
|
|
28
|
-
"[WARN] Same repo but different ids found in comfyregistry:\n" + "```\n" + YAML.stringify(duplicates) + "\n```";
|
|
29
|
-
await notifySlack(msg, { unique: true });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return [
|
|
33
|
-
await $pipeline(CNRepos)
|
|
34
|
-
.project({ repository: 1 })
|
|
35
|
-
.set({ on_registry: TaskOK({ $in: ["$repository", nodes.map(({ repository }) => repository).filter(Boolean)] }) })
|
|
36
|
-
.merge({ into: "CNRepos", on: "repository", whenMatched: "merge", whenNotMatched: "insert" })
|
|
37
|
-
.aggregate()
|
|
38
|
-
.next(),
|
|
39
|
-
await CRNodes.bulkWrite(
|
|
40
|
-
nodes.map((node) => ({
|
|
41
|
-
updateOne: {
|
|
42
|
-
filter: { id: node.id },
|
|
43
|
-
update: { $set: node },
|
|
44
|
-
upsert: true,
|
|
45
|
-
},
|
|
46
|
-
})),
|
|
47
|
-
{ ordered: false },
|
|
48
|
-
),
|
|
49
|
-
];
|
|
50
|
-
}
|
|
1
|
+
import { $pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
|
|
2
|
+
import { peekYaml } from "peek-log";
|
|
3
|
+
import { filter, groupBy, values } from "rambda";
|
|
4
|
+
import YAML from "yaml";
|
|
5
|
+
import { TaskOK } from "../packages/mongodb-pipeline-ts/Task";
|
|
6
|
+
import { CNRepos } from "./CNRepos";
|
|
7
|
+
import { CRNodes } from "./CRNodes";
|
|
8
|
+
import { fetchCRNodes } from "./fetchComfyRegistryNodes";
|
|
9
|
+
import { notifySlack } from "./slack/notifySlack";
|
|
10
|
+
import { tLog } from "./utils/tLog";
|
|
11
|
+
|
|
12
|
+
if (import.meta.main) {
|
|
13
|
+
peekYaml(await tLog(updateCRNodes));
|
|
14
|
+
console.log("CRNodes updated");
|
|
15
|
+
|
|
16
|
+
peekYaml(
|
|
17
|
+
await $pipeline(CNRepos).project({ repository: 1, on_registry: 1 }).sample({ size: 8 }).aggregate().toArray(),
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
export async function updateCRNodes() {
|
|
21
|
+
const nodes = await fetchCRNodes();
|
|
22
|
+
|
|
23
|
+
// check src duplicated
|
|
24
|
+
const group = groupBy((e) => e.repository, nodes);
|
|
25
|
+
const duplicates = filter((e) => e.length > 1, group);
|
|
26
|
+
if (values(duplicates).length) {
|
|
27
|
+
const msg =
|
|
28
|
+
"[WARN] Same repo but different ids found in comfyregistry:\n" + "```\n" + YAML.stringify(duplicates) + "\n```";
|
|
29
|
+
await notifySlack(msg, { unique: true });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return [
|
|
33
|
+
await $pipeline(CNRepos)
|
|
34
|
+
.project({ repository: 1 })
|
|
35
|
+
.set({ on_registry: TaskOK({ $in: ["$repository", nodes.map(({ repository }) => repository).filter(Boolean)] }) })
|
|
36
|
+
.merge({ into: "CNRepos", on: "repository", whenMatched: "merge", whenNotMatched: "insert" })
|
|
37
|
+
.aggregate()
|
|
38
|
+
.next(),
|
|
39
|
+
await CRNodes.bulkWrite(
|
|
40
|
+
nodes.map((node) => ({
|
|
41
|
+
updateOne: {
|
|
42
|
+
filter: { id: node.id },
|
|
43
|
+
update: { $set: node },
|
|
44
|
+
upsert: true,
|
|
45
|
+
},
|
|
46
|
+
})),
|
|
47
|
+
{ ordered: false },
|
|
48
|
+
),
|
|
49
|
+
];
|
|
50
|
+
}
|
package/src/updateCRRepos.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import pMap from "p-map";
|
|
2
|
-
import { CNRepos } from "./CNRepos";
|
|
3
|
-
import { CRNodes } from "./CRNodes";
|
|
4
|
-
import { tLog } from "./utils/tLog";
|
|
5
|
-
if (import.meta.main) {
|
|
6
|
-
await tLog("updateCRRepos", updateCRRepos);
|
|
7
|
-
}
|
|
8
|
-
export async function updateCRRepos() {
|
|
9
|
-
await CRNodes.createIndex({ repo_id: 1 });
|
|
10
|
-
return await pMap(CRNodes.find({ repo_id: { $exists: false } }), async (cr, i) => {
|
|
11
|
-
const { repository, _id } = cr;
|
|
12
|
-
await CNRepos.updateOne(
|
|
13
|
-
{ repository },
|
|
14
|
-
{
|
|
15
|
-
$set: {
|
|
16
|
-
cr: (await CRNodes.findOneAndUpdate(
|
|
17
|
-
{ _id },
|
|
18
|
-
{ $set: { repo_id: cr._id } },
|
|
19
|
-
{ upsert: true, returnDocument: "after" },
|
|
20
|
-
))!,
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
{ upsert: true },
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
1
|
+
import pMap from "p-map";
|
|
2
|
+
import { CNRepos } from "./CNRepos";
|
|
3
|
+
import { CRNodes } from "./CRNodes";
|
|
4
|
+
import { tLog } from "./utils/tLog";
|
|
5
|
+
if (import.meta.main) {
|
|
6
|
+
await tLog("updateCRRepos", updateCRRepos);
|
|
7
|
+
}
|
|
8
|
+
export async function updateCRRepos() {
|
|
9
|
+
await CRNodes.createIndex({ repo_id: 1 });
|
|
10
|
+
return await pMap(CRNodes.find({ repo_id: { $exists: false } }), async (cr, i) => {
|
|
11
|
+
const { repository, _id } = cr;
|
|
12
|
+
await CNRepos.updateOne(
|
|
13
|
+
{ repository },
|
|
14
|
+
{
|
|
15
|
+
$set: {
|
|
16
|
+
cr: (await CRNodes.findOneAndUpdate(
|
|
17
|
+
{ _id },
|
|
18
|
+
{ $set: { repo_id: cr._id } },
|
|
19
|
+
{ upsert: true, returnDocument: "after" },
|
|
20
|
+
))!,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{ upsert: true },
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
}
|
package/src/updateComfyTotals.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { match } from "ts-pattern";
|
|
2
|
-
import YAML from "yaml";
|
|
3
|
-
import { $OK, TaskError, TaskOK, tsmatch } from "../packages/mongodb-pipeline-ts/Task";
|
|
4
|
-
import { Totals } from "./Totals";
|
|
5
|
-
import { analyzeTotals } from "./analyzeTotals";
|
|
6
|
-
import { $filaten, $fresh } from "./db";
|
|
7
|
-
import { notifySlack } from "./slack/notifySlack";
|
|
8
|
-
|
|
9
|
-
if (import.meta.main) {
|
|
10
|
-
await updateComfyTotals();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function updateComfyTotals({ notify = true, fresh = "30m" } = {}) {
|
|
14
|
-
await Totals.createIndex({ today: 1, "totals.mtime": 1, "totals.state": 1 });
|
|
15
|
-
const today = new Date().toISOString().split("T")[0];
|
|
16
|
-
const cached = await Totals.findOne($filaten({ today, totals: { mtime: $fresh(fresh), ...$OK } }));
|
|
17
|
-
if (cached?.totals?.state === "ok")
|
|
18
|
-
return [
|
|
19
|
-
tsmatch(cached.totals)
|
|
20
|
-
.with($OK, ({ data }) => data)
|
|
21
|
-
.otherwise(() => null),
|
|
22
|
-
].flatMap((e) => (e ? [e] : []));
|
|
23
|
-
const totals = await analyzeTotals().then(TaskOK).catch(TaskError);
|
|
24
|
-
|
|
25
|
-
// notify if today is not already notify
|
|
26
|
-
if (notify) {
|
|
27
|
-
if (!(await Totals.findOne($filaten({ today, totals: { mtime: $fresh("1d"), ...$OK } }))))
|
|
28
|
-
// ignore today
|
|
29
|
-
await match(totals)
|
|
30
|
-
.with($OK, async (totals) => {
|
|
31
|
-
const msg = `Totals: \n${"```"}\n${YAML.stringify(totals)}\n${"```"}`;
|
|
32
|
-
await notifySlack(msg, { unique: true });
|
|
33
|
-
})
|
|
34
|
-
.otherwise(() => null);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const insertResult = await Totals.insertOne({ totals });
|
|
38
|
-
return [
|
|
39
|
-
tsmatch(totals)
|
|
40
|
-
.with($OK, ({ data }) => data)
|
|
41
|
-
.otherwise(() => null),
|
|
42
|
-
].flatMap((e) => (e ? [e] : []));
|
|
43
|
-
}
|
|
1
|
+
import { match } from "ts-pattern";
|
|
2
|
+
import YAML from "yaml";
|
|
3
|
+
import { $OK, TaskError, TaskOK, tsmatch } from "../packages/mongodb-pipeline-ts/Task";
|
|
4
|
+
import { Totals } from "./Totals";
|
|
5
|
+
import { analyzeTotals } from "./analyzeTotals";
|
|
6
|
+
import { $filaten, $fresh } from "./db";
|
|
7
|
+
import { notifySlack } from "./slack/notifySlack";
|
|
8
|
+
|
|
9
|
+
if (import.meta.main) {
|
|
10
|
+
await updateComfyTotals();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function updateComfyTotals({ notify = true, fresh = "30m" } = {}) {
|
|
14
|
+
await Totals.createIndex({ today: 1, "totals.mtime": 1, "totals.state": 1 });
|
|
15
|
+
const today = new Date().toISOString().split("T")[0];
|
|
16
|
+
const cached = await Totals.findOne($filaten({ today, totals: { mtime: $fresh(fresh), ...$OK } }));
|
|
17
|
+
if (cached?.totals?.state === "ok")
|
|
18
|
+
return [
|
|
19
|
+
tsmatch(cached.totals)
|
|
20
|
+
.with($OK, ({ data }) => data)
|
|
21
|
+
.otherwise(() => null),
|
|
22
|
+
].flatMap((e) => (e ? [e] : []));
|
|
23
|
+
const totals = await analyzeTotals().then(TaskOK).catch(TaskError);
|
|
24
|
+
|
|
25
|
+
// notify if today is not already notify
|
|
26
|
+
if (notify) {
|
|
27
|
+
if (!(await Totals.findOne($filaten({ today, totals: { mtime: $fresh("1d"), ...$OK } }))))
|
|
28
|
+
// ignore today
|
|
29
|
+
await match(totals)
|
|
30
|
+
.with($OK, async (totals) => {
|
|
31
|
+
const msg = `Totals: \n${"```"}\n${YAML.stringify(totals)}\n${"```"}`;
|
|
32
|
+
await notifySlack(msg, { unique: true });
|
|
33
|
+
})
|
|
34
|
+
.otherwise(() => null);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const insertResult = await Totals.insertOne({ totals });
|
|
38
|
+
return [
|
|
39
|
+
tsmatch(totals)
|
|
40
|
+
.with($OK, ({ data }) => data)
|
|
41
|
+
.otherwise(() => null),
|
|
42
|
+
].flatMap((e) => (e ? [e] : []));
|
|
43
|
+
}
|
|
@@ -1,127 +1,136 @@
|
|
|
1
|
-
"use server";
|
|
2
|
-
import { TaskDataOrNull } from "@/packages/mongodb-pipeline-ts/Task";
|
|
3
|
-
import DIE from "@snomiao/die";
|
|
4
|
-
import pMap from "p-map";
|
|
5
|
-
import { peekYaml } from "peek-log";
|
|
6
|
-
import { TaskError, TaskOK } from "../packages/mongodb-pipeline-ts/Task";
|
|
7
|
-
import { CNRepos } from "./CNRepos";
|
|
8
|
-
import { FollowRuleSets } from "./FollowRules";
|
|
9
|
-
import { addCommentAction } from "./addCommentAction";
|
|
10
|
-
import { analyzePullsStatus, analyzePullsStatusPipeline } from "./analyzePullsStatus";
|
|
11
|
-
import { $filaten } from "./db";
|
|
12
|
-
import { zAddCommentAction, zFollowUpRules } from "./followRuleSchema";
|
|
13
|
-
import { fetchIssueComments } from "./gh/fetchIssueComments";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { yaml } from "./utils/yaml";
|
|
18
|
-
|
|
19
|
-
if (import.meta.main) {
|
|
20
|
-
//
|
|
21
|
-
await
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return peekYaml(
|
|
31
|
-
await updateFollowRuleSet({
|
|
32
|
-
name: ruleset.name,
|
|
33
|
-
enable: ruleset.enabled
|
|
34
|
-
yaml: ruleset.yamlWhenEnabled
|
|
35
|
-
runAction: true,
|
|
36
|
-
}),
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
export type updateFollowRuleSet = typeof updateFollowRuleSet;
|
|
40
|
-
export async function updateFollowRuleSet({
|
|
41
|
-
name,
|
|
42
|
-
yaml: code,
|
|
43
|
-
enable,
|
|
44
|
-
runAction = false,
|
|
45
|
-
}: {
|
|
46
|
-
/** 'default' */
|
|
47
|
-
name: string;
|
|
48
|
-
/** update yaml if provided, unchange if undefined */
|
|
49
|
-
yaml?: string;
|
|
50
|
-
/** update enable if provided, unchange if undefined */
|
|
51
|
-
enable?: boolean | undefined;
|
|
52
|
-
/** run action if true */
|
|
53
|
-
runAction?: boolean;
|
|
54
|
-
}) {
|
|
55
|
-
"use server";
|
|
56
|
-
return await (async function () {
|
|
57
|
-
if (enable === false) {
|
|
58
|
-
await FollowRuleSets.updateOne({ name }, { $set: { enabled: false, yamlWhenEnabled: "" } });
|
|
59
|
-
DIE`ruleset is disabled, no need to run`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// must parse while run, because the date in code is dynamic generated
|
|
63
|
-
const rules = zFollowUpRules.parse(yaml.parse(code || DIE`yaml is empty`));
|
|
64
|
-
// save if parse succ
|
|
65
|
-
// await FollowRuleSets.updateOne({ name }, { $set: { yaml: code, rules } });
|
|
66
|
-
const parseResult = await pMap(
|
|
67
|
-
rules,
|
|
68
|
-
async (rule) => {
|
|
69
|
-
if (runAction) {
|
|
70
|
-
// pre-fetch comments before run a rule -> match -> action, to prevent comment on a outdated pull state
|
|
71
|
-
const preMatched = await analyzePullsStatus({ pipeline: analyzePullsStatusPipeline().match(rule.$match) })
|
|
72
|
-
.then(TaskOK)
|
|
73
|
-
.catch(TaskError);
|
|
74
|
-
|
|
75
|
-
// update comments before run action
|
|
76
|
-
const matchedData = TaskDataOrNull(preMatched) ?? DIE("NO-PAYLOAD-AVAILABLE");
|
|
77
|
-
await pMap(matchedData, async (payload) => {
|
|
78
|
-
const html_url = payload.url;
|
|
79
|
-
const { owner, repo, pull_number } = parsePullUrl(payload.url);
|
|
80
|
-
const repository = stringifyGithubRepoUrl({ owner, repo });
|
|
81
|
-
|
|
82
|
-
const comments = await fetchIssueComments(repository, { number: pull_number })
|
|
83
|
-
.then(TaskOK)
|
|
84
|
-
.catch(TaskError);
|
|
85
|
-
(
|
|
86
|
-
await CNRepos.updateOne($filaten({ repository, crPulls: { data: { pull: { html_url } } } }), {
|
|
87
|
-
$set: { "crPulls.data.$.comments": comments },
|
|
88
|
-
})
|
|
89
|
-
).matchedCount ?? DIE("pre-matched comments is not found");
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const matched = await analyzePullsStatus({ pipeline: analyzePullsStatusPipeline().match(rule.$match) })
|
|
94
|
-
.then(TaskOK)
|
|
95
|
-
.catch(TaskError);
|
|
96
|
-
|
|
97
|
-
const actions = await (async function () {
|
|
98
|
-
return await pMap(
|
|
99
|
-
Object.entries(rule.action),
|
|
100
|
-
async ([name, _action]) => {
|
|
101
|
-
if (name === "add-comment") {
|
|
102
|
-
const action = zAddCommentAction.parse(_action);
|
|
103
|
-
return await addCommentAction({ matched, action, runAction, rule });
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
1
|
+
"use server";
|
|
2
|
+
import { TaskDataOrNull } from "@/packages/mongodb-pipeline-ts/Task";
|
|
3
|
+
import DIE from "@snomiao/die";
|
|
4
|
+
import pMap from "p-map";
|
|
5
|
+
import { peekYaml } from "peek-log";
|
|
6
|
+
import { TaskError, TaskOK } from "../packages/mongodb-pipeline-ts/Task";
|
|
7
|
+
import { CNRepos } from "./CNRepos";
|
|
8
|
+
import { FollowRuleSets } from "./FollowRules";
|
|
9
|
+
import { addCommentAction } from "./addCommentAction";
|
|
10
|
+
import { analyzePullsStatus, analyzePullsStatusPipeline } from "./analyzePullsStatus";
|
|
11
|
+
import { $filaten } from "./db";
|
|
12
|
+
import { zAddCommentAction, zFollowUpRules, zSendEmailAction } from "./followRuleSchema";
|
|
13
|
+
import { fetchIssueComments } from "./gh/fetchIssueComments";
|
|
14
|
+
import { stringifyGithubRepoUrl } from "./parseOwnerRepo";
|
|
15
|
+
import { parsePullUrl } from "./parsePullUrl";
|
|
16
|
+
import { sendEmailAction } from "./sendEmailAction";
|
|
17
|
+
import { yaml } from "./utils/yaml";
|
|
18
|
+
|
|
19
|
+
if (import.meta.main) {
|
|
20
|
+
// const defaultRuleSet = await initializeFollowRules();
|
|
21
|
+
// await updateFollowRuleSet({ name: "default", enable: true, yaml: defaultRuleSet.yaml });
|
|
22
|
+
// await runFollowRuleSet();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function runFollowRuleSet({ name = "default" } = {}) {
|
|
26
|
+
const ruleset = (await FollowRuleSets.findOne({ name })) ?? DIE("default ruleset not found");
|
|
27
|
+
|
|
28
|
+
console.log("RUNNING ruleset:");
|
|
29
|
+
console.log(ruleset.yamlWhenEnabled);
|
|
30
|
+
return peekYaml(
|
|
31
|
+
await updateFollowRuleSet({
|
|
32
|
+
name: ruleset.name,
|
|
33
|
+
enable: ruleset.enabled || DIE(new Error("Ruleset is not enabled")),
|
|
34
|
+
yaml: ruleset.yamlWhenEnabled || DIE("Enabled yaml is not found"),
|
|
35
|
+
runAction: true,
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
export type updateFollowRuleSet = typeof updateFollowRuleSet;
|
|
40
|
+
export async function updateFollowRuleSet({
|
|
41
|
+
name,
|
|
42
|
+
yaml: code,
|
|
43
|
+
enable,
|
|
44
|
+
runAction = false,
|
|
45
|
+
}: {
|
|
46
|
+
/** 'default' */
|
|
47
|
+
name: string;
|
|
48
|
+
/** update yaml if provided, unchange if undefined */
|
|
49
|
+
yaml?: string;
|
|
50
|
+
/** update enable if provided, unchange if undefined */
|
|
51
|
+
enable?: boolean | undefined;
|
|
52
|
+
/** run action if true */
|
|
53
|
+
runAction?: boolean;
|
|
54
|
+
}) {
|
|
55
|
+
"use server";
|
|
56
|
+
return await (async function () {
|
|
57
|
+
if (enable === false) {
|
|
58
|
+
await FollowRuleSets.updateOne({ name }, { $set: { enabled: false, yamlWhenEnabled: "" } });
|
|
59
|
+
DIE`ruleset is disabled, no need to run`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// must parse while run, because the date in code is dynamic generated
|
|
63
|
+
const rules = zFollowUpRules.parse(yaml.parse(code || DIE`yaml is empty`));
|
|
64
|
+
// save if parse succ
|
|
65
|
+
// await FollowRuleSets.updateOne({ name }, { $set: { yaml: code, rules } });
|
|
66
|
+
const parseResult = await pMap(
|
|
67
|
+
rules,
|
|
68
|
+
async (rule) => {
|
|
69
|
+
if (runAction) {
|
|
70
|
+
// pre-fetch comments before run a rule -> match -> action, to prevent comment on a outdated pull state
|
|
71
|
+
const preMatched = await analyzePullsStatus({ pipeline: analyzePullsStatusPipeline().match(rule.$match) })
|
|
72
|
+
.then(TaskOK)
|
|
73
|
+
.catch(TaskError);
|
|
74
|
+
|
|
75
|
+
// update comments before run action
|
|
76
|
+
const matchedData = TaskDataOrNull(preMatched) ?? DIE("NO-PAYLOAD-AVAILABLE");
|
|
77
|
+
await pMap(matchedData, async (payload) => {
|
|
78
|
+
const html_url = payload.url;
|
|
79
|
+
const { owner, repo, pull_number } = parsePullUrl(payload.url);
|
|
80
|
+
const repository = stringifyGithubRepoUrl({ owner, repo });
|
|
81
|
+
|
|
82
|
+
const comments = await fetchIssueComments(repository, { number: pull_number })
|
|
83
|
+
.then(TaskOK)
|
|
84
|
+
.catch(TaskError);
|
|
85
|
+
(
|
|
86
|
+
await CNRepos.updateOne($filaten({ repository, crPulls: { data: { pull: { html_url } } } }), {
|
|
87
|
+
$set: { "crPulls.data.$.comments": comments },
|
|
88
|
+
})
|
|
89
|
+
).matchedCount ?? DIE("pre-matched comments is not found");
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const matched = await analyzePullsStatus({ pipeline: analyzePullsStatusPipeline().match(rule.$match) })
|
|
94
|
+
.then(TaskOK)
|
|
95
|
+
.catch(TaskError);
|
|
96
|
+
|
|
97
|
+
const actions = await (async function () {
|
|
98
|
+
return await pMap(
|
|
99
|
+
Object.entries(rule.action),
|
|
100
|
+
async ([name, _action]) => {
|
|
101
|
+
if (name === "add-comment") {
|
|
102
|
+
const action = zAddCommentAction.parse(_action);
|
|
103
|
+
return await addCommentAction({ matched, action, runAction, rule });
|
|
104
|
+
}
|
|
105
|
+
if (name === "send-email") {
|
|
106
|
+
const action = zSendEmailAction.parse(_action);
|
|
107
|
+
return await sendEmailAction({ matched, action, runAction, rule });
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{ concurrency: 1 },
|
|
111
|
+
);
|
|
112
|
+
})()
|
|
113
|
+
.then(TaskOK)
|
|
114
|
+
.catch(TaskError);
|
|
115
|
+
|
|
116
|
+
return { name: rule.name, matched, actions };
|
|
117
|
+
},
|
|
118
|
+
{ concurrency: 1 },
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (enable === true) {
|
|
122
|
+
await FollowRuleSets.updateOne(
|
|
123
|
+
{ name },
|
|
124
|
+
{
|
|
125
|
+
$set: { enabled: true, yamlWhenEnabled: code, yaml: code },
|
|
126
|
+
$push: { enableHistory: { mtime: new Date(), yaml: code } },
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
await FollowRuleSets.updateOne({ name }, { $set: { yaml: code } });
|
|
131
|
+
}
|
|
132
|
+
return parseResult;
|
|
133
|
+
})()
|
|
134
|
+
.then(TaskOK)
|
|
135
|
+
.catch(TaskError);
|
|
136
|
+
}
|