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.
Files changed (85) hide show
  1. package/README.md +247 -225
  2. package/index.ts +6 -0
  3. package/next-env.d.ts +5 -5
  4. package/package.json +52 -25
  5. package/src/Authors.ts +42 -48
  6. package/src/CMNodes.ts +60 -60
  7. package/src/CNRepos.ts +78 -74
  8. package/src/CRNodes.ts +27 -27
  9. package/src/CRPulls.ts +4 -4
  10. package/src/EmailTasks.ts +101 -0
  11. package/src/FORK_OWNER.ts +5 -5
  12. package/src/FORK_PREFIX.ts +5 -5
  13. package/src/FollowRules.ts +25 -25
  14. package/src/GIT_USEREMAIL.ts +5 -5
  15. package/src/GIT_USERNAME.ts +9 -9
  16. package/src/GithubIssueComments.ts +3 -3
  17. package/src/PushedBranch.ts +3 -3
  18. package/src/Totals.ts +24 -9
  19. package/src/TrackingPRs.ts +12 -12
  20. package/src/WorkerInstances.ts +89 -89
  21. package/src/addCommentAction.ts +73 -65
  22. package/src/analyzePullsStatus.ts +219 -170
  23. package/src/analyzeTotals.test.ts +5 -5
  24. package/src/analyzeTotals.ts +118 -118
  25. package/src/bypassRepos.spec.ts +10 -0
  26. package/src/bypassRepos.ts +8 -0
  27. package/src/checkComfyActivated.ts +39 -39
  28. package/src/checkPRsFailures.ts +18 -0
  29. package/src/cli.ts +40 -40
  30. package/src/clone_modify_push_Branches.ts +21 -21
  31. package/src/createComfyRegistryPRsFromCandidates.ts +55 -55
  32. package/src/createComfyRegistryPullRequests.ts +32 -22
  33. package/src/createGithubForkForRepo.ts +54 -37
  34. package/src/createGithubPullRequest.ts +157 -94
  35. package/src/createIssueComment.ts +34 -29
  36. package/src/fetchCMNodes.ts +22 -22
  37. package/src/fetchComfyRegistryNodes.ts +11 -11
  38. package/src/fetchCurrentGeoInfo.ts +6 -6
  39. package/src/fetchRelatedPullWithComments.ts +15 -15
  40. package/src/fetchRepoDescriptionMap.ts +15 -15
  41. package/src/followRuleSchema.ts +79 -76
  42. package/src/getActivatedShell.ts +18 -18
  43. package/src/getBranchWorkingDir.ts +16 -16
  44. package/src/getRepoWorkingDir.ts +5 -5
  45. package/src/ghUser.ts +9 -6
  46. package/src/index.ts +26 -22
  47. package/src/initializeFollowRules.ts +26 -26
  48. package/src/makePublishBranch.ts +58 -58
  49. package/src/makeTomlBranch.ts +53 -53
  50. package/src/makeUpdateTomlLicenseBranch.ts +245 -0
  51. package/src/matchRelatedPulls.ts +47 -60
  52. package/src/muteInstances.ts +16 -16
  53. package/src/parseIssueUrl.ts +6 -6
  54. package/src/parseOwnerRepo.ts +33 -33
  55. package/src/parsePullUrl.ts +6 -6
  56. package/src/parsePullsState.ts +6 -6
  57. package/src/parseTitleBodyOfMarkdown.ts +8 -8
  58. package/src/postSlackMessage.ts +21 -21
  59. package/src/preload.ts +30 -30
  60. package/src/pullStatusFollowSchema.ts +12 -12
  61. package/src/readTemplateTitle.ts +11 -11
  62. package/src/sendEmailAction.ts +56 -0
  63. package/src/sendGmail.ts +105 -0
  64. package/src/showFollowRuleSet.ts +12 -12
  65. package/src/summaryLastPullComment.ts +8 -8
  66. package/src/tomlFillDescription.ts +17 -17
  67. package/src/updateAuthors.ts +7 -7
  68. package/src/updateAuthorsForGithub.ts +54 -50
  69. package/src/updateAuthorsFromCNRepo.ts +30 -30
  70. package/src/updateCMNodesDuplicationWarnings.ts +56 -56
  71. package/src/updateCMRepos.ts +27 -27
  72. package/src/updateCNRepos.ts +58 -58
  73. package/src/updateCNReposCRPullsComments.ts +40 -40
  74. package/src/updateCNReposInfo.ts +58 -57
  75. package/src/updateCNReposPRCandidate.ts +85 -85
  76. package/src/updateCNReposPulls.ts +31 -28
  77. package/src/updateCNReposPullsDashboard.ts +49 -49
  78. package/src/updateCNReposRelatedPulls.ts +25 -25
  79. package/src/updateCRNodes.ts +50 -50
  80. package/src/updateCRRepos.ts +26 -26
  81. package/src/updateComfyTotals.ts +43 -43
  82. package/src/updateFollowRuleSet.ts +136 -127
  83. package/src/updateOutdatedPullsTemplates.ts +165 -160
  84. package/src/updateSlackMessages.ts +43 -43
  85. package/tailwind.config.ts +75 -20
@@ -1,170 +1,219 @@
1
- import { $pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
2
- import prettyMs from "pretty-ms";
3
- import { snoflow } from "snoflow";
4
- import type { z } from "zod";
5
- import type { Task } from "../packages/mongodb-pipeline-ts/Task";
6
- import type { Author } from "./Authors";
7
- import { CNRepos, type CRPull } from "./CNRepos";
8
- import type { GithubIssueComment } from "./GithubIssueComments";
9
- import { db } from "./db";
10
- import type { zPullStatus } from "./zod/zPullsStatus";
11
- // import { $pipeline } from "./db/$pipeline";
12
- // in case of dump production in local environment:
13
- // bun --env-file .env.production.local src/dump.ts > dump.csv
14
- export const DashboardDetails = db.collection<any>("DashboardDetails");
15
- if (import.meta.main) {
16
- // const r = peekYaml(await analyzePullsStatus());
17
-
18
- // await mkdir(".cache").catch(() => null);
19
- // await writeFile(".cache/dump.yaml", YAML.stringify(r));
20
- // await writeFile(".cache/dump.csv", csvFormat(r));
21
- // console.log("done");
22
- // generate zod schema
23
- // await writeFile("src/zPullsStatus.ts", jsonToZod(await analyzePullsStatus({ limit: 1 }), "zPullsStatus", true));
24
-
25
- // analyzePullsStatusPipeline
26
- await snoflow(analyzePullsStatusPipeline().aggregate())
27
- // .filter(e=>e.email)
28
- .peek(console.log)
29
- .done();
30
- }
31
-
32
- export type PullStatus = z.infer<typeof zPullStatus>;
33
- export type PullsStatus = PullStatus[];
34
- export type PullStatusShown = Awaited<ReturnType<typeof analyzePullsStatus>>[number];
35
- export async function analyzePullsStatus({ skip = 0, limit = 0, pipeline = analyzePullsStatusPipeline() } = {}) {
36
- "use server";
37
- return await pipeline
38
- .skip(skip)
39
- .limit(limit || 2 ** 31 - 1)
40
- .aggregate()
41
- .map(({ updated_at, created_at, actived_at, on_registry_at, ...pull }) => {
42
- const pull_updated = prettyMs(+new Date() - +new Date(updated_at), { compact: true }) + " ago";
43
- const repo_updated = prettyMs(+new Date() - +new Date(actived_at), { compact: true }) + " ago";
44
- return {
45
- updated: pull_updated, // @deprecated
46
- pull_updated,
47
- repo_updated,
48
- ...pull,
49
- lastwords: pull.lastwords?.replace(/\s+/g, " ").replace(/\*\*\*.*/g, "..."),
50
- };
51
- })
52
- .toArray();
53
- }
54
- export function baseCRPullStatusPipeline() {
55
- return (
56
- $pipeline(CNRepos)
57
- // get latest pr comments time
58
- .set({ "crPulls.data.pull.latest_comment_at": { $max: { $max: "$crPulls.data.comments.data.updated_at" } } })
59
- // unwind
60
- .stage({ $unwind: "$crPulls.data" })
61
- .match({ "crPulls.data.comments.data": { $exists: true } })
62
- // repo infos
63
- .set({ "crPulls.data.pull.actived_at": { $toDate: "$info.data.updated_at" } })
64
- .set({ "crPulls.data.pull.repo": "$repository" })
65
- .set({ "crPulls.data.pull.email": "$email" })
66
- .set({ "crPulls.data.pull.on_registry": "$on_registry" })
67
- // pull info
68
- .set({ "crPulls.data.pull.type": "$crPulls.data.type" })
69
- .set({ "crPulls.data.pull": "$crPulls.data.pull" })
70
- .set({ "crPulls.data.pull.comments": "$crPulls.data.comments.data" })
71
- // replace root as pull
72
- .replaceRoot({ newRoot: "$crPulls.data.pull" })
73
- .as<
74
- CRPull & {
75
- repo: string;
76
- on_registry: Task<boolean>;
77
- type: string;
78
- comments: GithubIssueComment[];
79
- }
80
- >()
81
- );
82
- }
83
- export function analyzePullsStatusPipeline() {
84
- return (
85
- baseCRPullStatusPipeline()
86
- // fetch author email from Authors collection
87
- .lookup({
88
- from: "Authors",
89
- as: "authors",
90
- // let: { <var_1>: <expression>, …, <var_n>: <expression> },
91
- localField: "base.user.login",
92
- foreignField: "githubId",
93
- pipeline: [{ $project: { email: 1 } }],
94
- })
95
- .with<{ authors: Author[] }>()
96
- .set({ author: { $arrayElemAt: ["$authors", 0] } })
97
- .project({ authors: 0 })
98
-
99
- .set({ lastwords: { $arrayElemAt: ["$comments", -1] } })
100
- .set({ lastwords: { $ifNull: [{ $concat: ["$lastwords.user.login", ": ", "$lastwords.body"] }, ""] } })
101
-
102
- // calculate update_at max( )
103
- // date format convert
104
- .set({ created_at: { $toDate: "$created_at" } })
105
- .set({ updated_at: { $toDate: "$updated_at" } })
106
- .set({ latest_comment_at: { $toDate: "$latest_comment_at" } })
107
- .set({ updated_at: { $max: ["$latest_comment_at", "$updated_at"] } })
108
-
109
- // // projecting
110
- .project({
111
- created_at: 1,
112
- updated_at: 1,
113
- repository: 1,
114
- on_registry: "$on_registry.data",
115
- on_registry_at: "$on_registry.mtime",
116
- state: { $toUpper: `$prState` },
117
- url: "$html_url",
118
- ownername: "$base.user.login",
119
- nickName: "$base.user.name",
120
- head: { $concat: ["$user.login", ":", "$type"] },
121
- comments: { $size: "$comments" },
122
- comments_author: {
123
- $trim: {
124
- input: {
125
- $reduce: {
126
- input: "$comments.user.login",
127
- initialValue: "",
128
- in: { $concat: ["$$value", " ", "$$this"] },
129
- },
130
- },
131
- chars: " ",
132
- },
133
- },
134
- lastwords: 1,
135
- actived_at: 1,
136
-
137
- instagramId: "$author.instagramId",
138
- discordId: "$author.discordId",
139
- twitterId: "$author.twitterId",
140
- email: { $ifNull: ["$author.email", ""] },
141
- })
142
- // .project({ latest_comment_at: {$toDate: '$latest_comment_at'} })
143
- .project({ latest_comment_at: 0 })
144
- .set({
145
- CLOSED: { $eq: ["$state", "CLOSED"] },
146
- MERGED: { $eq: ["$state", "MERGED"] },
147
- OPEN: { $eq: ["$state", "OPEN"] },
148
- })
149
- .sort({ ownername: 1 })
150
- .sort({ OPEN: -1, MERGED: -1, CLOSED: -1, updated_at: 1 })
151
- .unset(["CLOSED", "MERGED", "OPEN"])
152
- .as<{
153
- actived_at: Date;
154
- email: string | "";
155
- comments: number;
156
- created_at: Date;
157
- head: string;
158
- lastwords: string;
159
- on_registry_at: Date;
160
- on_registry: boolean;
161
- comments_author: string;
162
- ownername: string;
163
- nickName: string;
164
- repository: string;
165
- state: "OPEN" | "MERGED" | "CLOSED";
166
- updated_at: Date;
167
- url: string;
168
- }>()
169
- );
170
- }
1
+ import { $pipeline, type Pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
2
+ import type { ObjectId } from "mongodb";
3
+ import prettyMs from "pretty-ms";
4
+ import { snoflow } from "snoflow";
5
+ import type { z } from "zod";
6
+ import type { Task } from "../packages/mongodb-pipeline-ts/Task";
7
+ import type { Author } from "./Authors";
8
+ import { CNRepos, type CRPull } from "./CNRepos";
9
+ import type { EmailTask } from "./EmailTasks";
10
+ import type { GithubIssueComment } from "./GithubIssueComments";
11
+ import { db } from "./db";
12
+ import { yaml } from "./utils/yaml";
13
+ import type { zPullStatus } from "./zod/zPullsStatus";
14
+ // import { $pipeline } from "./db/$pipeline";
15
+ // in case of dump production in local environment:
16
+ // bun --env-file .env.production.local src/dump.ts > dump.csv
17
+ export const DashboardDetails = db.collection<any>("DashboardDetails");
18
+ if (import.meta.main) {
19
+ // const r = peekYaml(await analyzePullsStatus());
20
+
21
+ // await mkdir(".cache").catch(() => null);
22
+ // await writeFile(".cache/dump.yaml", YAML.stringify(r));
23
+ // await writeFile(".cache/dump.csv", csvFormat(r));
24
+ // console.log("done");
25
+ // generate zod schema
26
+ // await writeFile("src/zPullsStatus.ts", jsonToZod(await analyzePullsStatus({ limit: 1 }), "zPullsStatus", true));
27
+
28
+ // analyzePullsStatusPipeline
29
+ await snoflow(analyzePullsStatusPipeline().aggregate())
30
+ .filter((e) => e.email)
31
+ .limit(2)
32
+ .map((e) => yaml.stringify({ e }))
33
+ .log()
34
+ .chunk()
35
+ .map((e) => e.length)
36
+ .toLog();
37
+ }
38
+
39
+ export type PullStatus = z.infer<typeof zPullStatus>;
40
+ export type PullsStatus = PullStatus[];
41
+ export type PullStatusShown = Awaited<ReturnType<typeof analyzePullsStatus>>[number];
42
+
43
+ export async function analyzePullsStatus({ skip = 0, limit = 0, pipeline = analyzePullsStatusPipeline() } = {}) {
44
+ "use server";
45
+ return await pipeline
46
+ .skip(skip)
47
+ .limit(limit || 2 ** 31 - 1)
48
+ .aggregate()
49
+ .map(({ updated_at, created_at, actived_at, on_registry_at, ...pull }) => {
50
+ const pull_updated = prettyMs(+new Date() - +new Date(updated_at), { compact: true }) + " ago";
51
+ const repo_updated = prettyMs(+new Date() - +new Date(actived_at), { compact: true }) + " ago";
52
+ return {
53
+ updated: pull_updated, // @deprecated
54
+ pull_updated,
55
+ repo_updated,
56
+ ...pull,
57
+ lastcomment: pull.lastcomment?.replace(/\s+/g, " ").replace(/\*\*\*.*/g, "..."),
58
+ };
59
+ })
60
+ .toArray();
61
+ }
62
+ export function baseCRPullStatusPipeline(): Pipeline<
63
+ CRPull & {
64
+ repo: string;
65
+ on_registry: Task<boolean>;
66
+ type: string;
67
+ comments: GithubIssueComment[];
68
+ emailTask_id?: ObjectId;
69
+ }
70
+ > {
71
+ return (
72
+ $pipeline(CNRepos)
73
+ // get latest pr comments time
74
+ .set({ "crPulls.data.pull.latest_comment_at": { $max: { $max: "$crPulls.data.comments.data.updated_at" } } })
75
+ // unwind
76
+ .stage({ $unwind: "$crPulls.data" })
77
+ .match({ "crPulls.data.comments.data": { $exists: true } })
78
+ // repo infos
79
+ .set({ "crPulls.data.pull.actived_at": { $toDate: "$info.data.updated_at" } })
80
+ .set({ "crPulls.data.pull.repo": "$repository" })
81
+ .set({ "crPulls.data.pull.email": "$email" })
82
+ .set({ "crPulls.data.pull.on_registry": "$on_registry" })
83
+ // pull info
84
+ .set({ "crPulls.data.pull.type": "$crPulls.data.type" })
85
+ .set({ "crPulls.data.pull": "$crPulls.data.pull" })
86
+ .set({ "crPulls.data.pull.comments": "$crPulls.data.comments.data" })
87
+ .set({ "crPulls.data.pull.emailTask_id": "$crPulls.data.emailTask_id" })
88
+ // replace root as pull
89
+ .replaceRoot({ newRoot: "$crPulls.data.pull" })
90
+ .as<
91
+ CRPull & {
92
+ repo: string;
93
+ on_registry: Task<boolean>;
94
+ type: string;
95
+ comments: GithubIssueComment[];
96
+ emailTask_id?: ObjectId;
97
+ }
98
+ >()
99
+ );
100
+ }
101
+ export function analyzePullsStatusPipeline(): Pipeline<{
102
+ actived_at: Date;
103
+ email: string | "";
104
+ comments: number;
105
+ created_at: Date;
106
+ head: string;
107
+ lastcomment: string;
108
+ on_registry_at: Date;
109
+ on_registry: boolean;
110
+ comments_author: string;
111
+ ownername: string;
112
+ nickName: string;
113
+ repository: string;
114
+ state: "OPEN" | "MERGED" | "CLOSED";
115
+ updated_at: Date;
116
+ emailState: EmailTask["state"] | "";
117
+ url: string;
118
+ }> {
119
+ return (
120
+ baseCRPullStatusPipeline()
121
+ // fetch author email from Authors collection
122
+ .set({ ownername: "$base.user.login" })
123
+ .lookup({
124
+ from: "Authors",
125
+ // let: { <var_1>: <expression>, …, <var_n>: <expression> },
126
+ localField: "ownername",
127
+ foreignField: "githubId",
128
+ as: "author",
129
+ pipeline: [{ $project: { email: 1 } }],
130
+ })
131
+ .unwind({ path: "$author", preserveNullAndEmptyArrays: true })
132
+ .with<{ author: Author }>()
133
+ .lookup({
134
+ from: "EmailTasks",
135
+ // let: { <var_1>: <expression>, …, <var_n>: <expression> },
136
+ localField: "emailTask_id",
137
+ foreignField: "_id",
138
+ as: "emailTask",
139
+ })
140
+ .unwind({ path: "$emailTask", preserveNullAndEmptyArrays: true })
141
+ .set({ emailState: { $ifNull: ["$emailTask.state", ""] } }) // output could be "" | "waiting" | "sending" | "sent" | "error";
142
+ .with<{ emailState: EmailTask["state"] }>()
143
+
144
+ // .set({ author: { $first: ["$author"] } })
145
+ .project({ authors: 0 })
146
+
147
+ .set({ lastcomment: { $arrayElemAt: ["$comments", -1] } })
148
+ .set({ lastcomment: { $ifNull: [{ $concat: ["$lastcomment.user.login", ": ", "$lastcomment.body"] }, ""] } })
149
+
150
+ // calculate update_at max( )
151
+ // date format convert
152
+ .set({ created_at: { $toDate: "$created_at" } })
153
+ .set({ updated_at: { $toDate: "$updated_at" } })
154
+ .set({ latest_comment_at: { $toDate: "$latest_comment_at" } })
155
+ .set({ updated_at: { $max: ["$latest_comment_at", "$updated_at"] } })
156
+
157
+ // // projecting
158
+ .project({
159
+ created_at: 1,
160
+ updated_at: 1,
161
+ repository: 1,
162
+ on_registry: "$on_registry.data",
163
+ on_registry_at: "$on_registry.mtime",
164
+ state: { $toUpper: `$prState` },
165
+ url: "$html_url",
166
+ ownername: "$base.user.login",
167
+ nickName: "$base.user.name",
168
+ head: { $concat: ["$user.login", ":", "$type"] },
169
+ comments: { $size: "$comments" },
170
+ comments_author: {
171
+ $trim: {
172
+ input: {
173
+ $reduce: {
174
+ input: "$comments.user.login",
175
+ initialValue: "",
176
+ in: { $concat: ["$$value", " ", "$$this"] },
177
+ },
178
+ },
179
+ chars: " ",
180
+ },
181
+ },
182
+ actived_at: 1,
183
+ lastcomment: 1,
184
+
185
+ instagramId: "$author.instagramId",
186
+ discordId: "$author.discordId",
187
+ twitterId: "$author.twitterId",
188
+ email: { $ifNull: ["$author.email", ""] },
189
+ emailState: 1,
190
+ })
191
+ .unset("latest_comment_at")
192
+ .set({
193
+ CLOSED: { $eq: ["$state", "CLOSED"] },
194
+ MERGED: { $eq: ["$state", "MERGED"] },
195
+ OPEN: { $eq: ["$state", "OPEN"] },
196
+ })
197
+ .sort({ ownername: 1 })
198
+ .sort({ OPEN: -1, MERGED: -1, CLOSED: -1, updated_at: 1 })
199
+ .unset(["CLOSED", "MERGED", "OPEN"])
200
+ .as<{
201
+ actived_at: Date;
202
+ email: string | "";
203
+ comments: number;
204
+ created_at: Date;
205
+ head: string;
206
+ lastcomment: string;
207
+ on_registry_at: Date;
208
+ on_registry: boolean;
209
+ comments_author: string;
210
+ ownername: string;
211
+ nickName: string;
212
+ repository: string;
213
+ state: "OPEN" | "MERGED" | "CLOSED";
214
+ updated_at: Date;
215
+ emailState: EmailTask["state"] | "";
216
+ url: string;
217
+ }>()
218
+ );
219
+ }
@@ -1,5 +1,5 @@
1
- import { analyzeTotals } from "./analyzeTotals";
2
-
3
- it("analyze totals", async () => {
4
- expect(await analyzeTotals()).toBeTruthy();
5
- });
1
+ import { analyzeTotals } from "./analyzeTotals";
2
+
3
+ it("analyze totals", async () => {
4
+ expect(await analyzeTotals()).toBeTruthy();
5
+ });
@@ -1,118 +1,118 @@
1
- "use server";
2
- import { $pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
3
- import promiseAllProperties from "promise-all-properties";
4
- import YAML from "yaml";
5
- import { CMNodes } from "./CMNodes";
6
- import { CNRepos } from "./CNRepos";
7
- import { CRNodes } from "./CRNodes";
8
- import { $filaten } from "./db";
9
- import { tLog } from "./utils/tLog";
10
-
11
- if (import.meta.main) {
12
- await tLog("analyzeTotals", async () => {
13
- console.log(YAML.stringify(await analyzeTotals()));
14
- return [];
15
- });
16
- }
17
- /**
18
- * @warning this function is heavy, TODO: split into small chunk
19
- */
20
- export async function analyzeTotals() {
21
- "use server";
22
- const totals = await promiseAllProperties({
23
- // Now: new Date().toISOString(),
24
- "Total Nodes": promiseAllProperties({
25
- "on ComfyUI Manager": CMNodes.estimatedDocumentCount(),
26
- "on Registry": CRNodes.estimatedDocumentCount(),
27
- }),
28
- "Total Repos": $pipeline(CNRepos)
29
- .group({
30
- _id: null,
31
- "on Comfy Manager List": { $sum: { $cond: [{ $eq: [{ $type: "$cm" }, "missing"] }, 0, 1] } },
32
- "on Registry": { $sum: { $cond: [{ $eq: [{ $type: "$cr" }, "missing"] }, 0, 1] } },
33
- Archived: { $sum: { $cond: ["$info.data.archived", 1, 0] } },
34
- All: { $sum: 1 },
35
- // Candidates: { $sum: { $cond: ["$candidate.data", 1, 0] } },
36
- "Got ERROR on creating PR": { $sum: { $cond: [{ $eq: ["$createdPulls.state", "error"] }, 1, 0] } },
37
- })
38
- .project({ _id: 0 })
39
- .aggregate()
40
- // .map((e: any) => e.pairs)
41
- .next(),
42
- "Total Authors": $pipeline(CNRepos)
43
- .match($filaten({ info: { data: { owner: { login: { $exists: true } } } } }))
44
- .group({
45
- _id: "$info.data.owner.login",
46
- // author: "$info.data.owner.login",
47
- cm: { $sum: { $cond: [{ $eq: [{ $type: "$cm" }, "missing"] }, 0, 1] } },
48
- cr: { $sum: { $cond: [{ $eq: [{ $type: "$cr" }, "missing"] }, 0, 1] } },
49
- All: { $sum: 1 },
50
- })
51
- .set({ author: "$_id" })
52
- .group({
53
- _id: null,
54
- "on Comfy Manager List": { $sum: { $cond: [{ $eq: ["$cm", 0] }, 0, 1] } },
55
- "on Registry": { $sum: { $cond: [{ $eq: ["$cr", 0] }, 0, 1] } },
56
- All: { $sum: 1 },
57
- })
58
- .project({ _id: 0 })
59
- .aggregate()
60
- // .map((e: any) => e.pairs)
61
- .next(),
62
- "Total PRs Made": $pipeline(CNRepos)
63
- .unwind("$crPulls.data")
64
- .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
65
- .sort({ _id: 1 })
66
- .set({ id_total: [["$_id", "$total"]] })
67
- .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
68
- .aggregate()
69
- .map((e: any) => e.pairs)
70
- .next(),
71
- "Total Open": $pipeline(CNRepos)
72
- .unwind("$crPulls.data")
73
- .match({ "crPulls.data.pull.prState": "open" })
74
- .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
75
- .sort({ _id: 1 })
76
- .set({ id_total: [["$_id", "$total"]] })
77
- .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
78
- .aggregate()
79
- .map((e: any) => e.pairs)
80
- .next(),
81
- "Total Merged (on Registry)": $pipeline(CNRepos)
82
- .unwind("$crPulls.data")
83
- .match({ cr: { $exists: true }, "crPulls.data.pull.prState": "merged" })
84
- .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
85
- .sort({ _id: 1 })
86
- .set({ id_total: [["$_id", "$total"]] })
87
- .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
88
- .aggregate()
89
- .map((e: any) => e.pairs)
90
- .next(),
91
- "Total Merged (not on Registry)": $pipeline(CNRepos)
92
- .unwind("$crPulls.data")
93
- .match({ cr: { $exists: false }, "crPulls.data.pull.prState": "merged" })
94
- .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
95
- .sort({ _id: 1 })
96
- .set({ id_total: [["$_id", "$total"]] })
97
- .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
98
- .aggregate()
99
- .map((e: any) => e.pairs)
100
- .next(),
101
- "Total Closed": $pipeline(CNRepos)
102
- .unwind("$crPulls.data")
103
- .match({ "crPulls.data.pull.prState": "closed" })
104
- .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
105
- .sort({ _id: 1 })
106
- .set({ id_total: [["$_id", "$total"]] })
107
- .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
108
- .aggregate()
109
- .map((e: any) => e.pairs)
110
- .next(),
111
-
112
- // // Follow Rules
113
- // "Follow Up Rules": (async function () {
114
- // return TaskDataOrNull(await showFollowRuleSet({ name: "default" }));
115
- // })(),
116
- });
117
- return totals;
118
- }
1
+ "use server";
2
+ import { $pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
3
+ import promiseAllProperties from "promise-all-properties";
4
+ import YAML from "yaml";
5
+ import { CMNodes } from "./CMNodes";
6
+ import { CNRepos } from "./CNRepos";
7
+ import { CRNodes } from "./CRNodes";
8
+ import { $filaten } from "./db";
9
+ import { tLog } from "./utils/tLog";
10
+
11
+ if (import.meta.main) {
12
+ await tLog("analyzeTotals", async () => {
13
+ console.log(YAML.stringify(await analyzeTotals()));
14
+ return [];
15
+ });
16
+ }
17
+ /**
18
+ * @warning this function is heavy, TODO: split into small chunk
19
+ */
20
+ export async function analyzeTotals() {
21
+ "use server";
22
+ const totals = await promiseAllProperties({
23
+ // Now: new Date().toISOString(),
24
+ "Total Nodes": promiseAllProperties({
25
+ "on ComfyUI Manager": CMNodes.estimatedDocumentCount(),
26
+ "on Registry": CRNodes.estimatedDocumentCount(),
27
+ }),
28
+ "Total Repos": $pipeline(CNRepos)
29
+ .group({
30
+ _id: null,
31
+ "on Comfy Manager List": { $sum: { $cond: [{ $eq: [{ $type: "$cm" }, "missing"] }, 0, 1] } },
32
+ "on Registry": { $sum: { $cond: [{ $eq: [{ $type: "$cr" }, "missing"] }, 0, 1] } },
33
+ Archived: { $sum: { $cond: ["$info.data.archived", 1, 0] } },
34
+ All: { $sum: 1 },
35
+ // Candidates: { $sum: { $cond: ["$candidate.data", 1, 0] } },
36
+ "Got ERROR on creating PR": { $sum: { $cond: [{ $eq: ["$createdPulls.state", "error"] }, 1, 0] } },
37
+ })
38
+ .project({ _id: 0 })
39
+ .aggregate()
40
+ // .map((e: any) => e.pairs)
41
+ .next(),
42
+ "Total Authors": $pipeline(CNRepos)
43
+ .match($filaten({ info: { data: { owner: { login: { $exists: true } } } } }))
44
+ .group({
45
+ _id: "$info.data.owner.login",
46
+ // author: "$info.data.owner.login",
47
+ cm: { $sum: { $cond: [{ $eq: [{ $type: "$cm" }, "missing"] }, 0, 1] } },
48
+ cr: { $sum: { $cond: [{ $eq: [{ $type: "$cr" }, "missing"] }, 0, 1] } },
49
+ All: { $sum: 1 },
50
+ })
51
+ .set({ author: "$_id" })
52
+ .group({
53
+ _id: null,
54
+ "on Comfy Manager List": { $sum: { $cond: [{ $eq: ["$cm", 0] }, 0, 1] } },
55
+ "on Registry": { $sum: { $cond: [{ $eq: ["$cr", 0] }, 0, 1] } },
56
+ All: { $sum: 1 },
57
+ })
58
+ .project({ _id: 0 })
59
+ .aggregate()
60
+ // .map((e: any) => e.pairs)
61
+ .next(),
62
+ "Total PRs Made": $pipeline(CNRepos)
63
+ .unwind("$crPulls.data")
64
+ .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
65
+ .sort({ _id: 1 })
66
+ .set({ id_total: [["$_id", "$total"]] })
67
+ .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
68
+ .aggregate()
69
+ .map((e: any) => e.pairs)
70
+ .next(),
71
+ "Total Open": $pipeline(CNRepos)
72
+ .unwind("$crPulls.data")
73
+ .match({ "crPulls.data.pull.prState": "open" })
74
+ .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
75
+ .sort({ _id: 1 })
76
+ .set({ id_total: [["$_id", "$total"]] })
77
+ .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
78
+ .aggregate()
79
+ .map((e: any) => e.pairs)
80
+ .next(),
81
+ "Total Merged (on Registry)": $pipeline(CNRepos)
82
+ .unwind("$crPulls.data")
83
+ .match({ cr: { $exists: true }, "crPulls.data.pull.prState": "merged" })
84
+ .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
85
+ .sort({ _id: 1 })
86
+ .set({ id_total: [["$_id", "$total"]] })
87
+ .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
88
+ .aggregate()
89
+ .map((e: any) => e.pairs)
90
+ .next(),
91
+ "Total Merged (not on Registry)": $pipeline(CNRepos)
92
+ .unwind("$crPulls.data")
93
+ .match({ cr: { $exists: false }, "crPulls.data.pull.prState": "merged" })
94
+ .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
95
+ .sort({ _id: 1 })
96
+ .set({ id_total: [["$_id", "$total"]] })
97
+ .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
98
+ .aggregate()
99
+ .map((e: any) => e.pairs)
100
+ .next(),
101
+ "Total Closed": $pipeline(CNRepos)
102
+ .unwind("$crPulls.data")
103
+ .match({ "crPulls.data.pull.prState": "closed" })
104
+ .group({ _id: "$crPulls.data.type", total: { $sum: 1 } })
105
+ .sort({ _id: 1 })
106
+ .set({ id_total: [["$_id", "$total"]] })
107
+ .group({ _id: null, pairs: { $mergeObjects: { $arrayToObject: "$id_total" } } })
108
+ .aggregate()
109
+ .map((e: any) => e.pairs)
110
+ .next(),
111
+
112
+ // // Follow Rules
113
+ // "Follow Up Rules": (async function () {
114
+ // return TaskDataOrNull(await showFollowRuleSet({ name: "default" }));
115
+ // })(),
116
+ });
117
+ return totals;
118
+ }