comfy-pr 0.2.24 → 0.2.25

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 (81) hide show
  1. package/CHANGELOG.md +385 -0
  2. package/README.md +225 -225
  3. package/next-env.d.ts +5 -5
  4. package/package.json +12 -2
  5. package/src/Authors.ts +48 -48
  6. package/src/CMNodes.ts +60 -60
  7. package/src/CNRepos.ts +75 -74
  8. package/src/CRNodes.ts +27 -27
  9. package/src/CRPulls.ts +4 -4
  10. package/src/EmailTasks.ts +100 -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 +193 -170
  23. package/src/analyzeTotals.test.ts +5 -5
  24. package/src/analyzeTotals.ts +118 -118
  25. package/src/checkComfyActivated.ts +39 -39
  26. package/src/cli.ts +40 -40
  27. package/src/clone_modify_push_Branches.ts +21 -21
  28. package/src/createComfyRegistryPRsFromCandidates.ts +55 -55
  29. package/src/createComfyRegistryPullRequests.ts +22 -22
  30. package/src/createGithubForkForRepo.ts +40 -37
  31. package/src/createGithubPullRequest.ts +94 -94
  32. package/src/createIssueComment.ts +29 -29
  33. package/src/fetchCMNodes.ts +22 -22
  34. package/src/fetchComfyRegistryNodes.ts +11 -11
  35. package/src/fetchCurrentGeoInfo.ts +6 -6
  36. package/src/fetchRelatedPullWithComments.ts +15 -15
  37. package/src/fetchRepoDescriptionMap.ts +15 -15
  38. package/src/followRuleSchema.ts +78 -76
  39. package/src/getActivatedShell.ts +18 -18
  40. package/src/getBranchWorkingDir.ts +16 -16
  41. package/src/getRepoWorkingDir.ts +5 -5
  42. package/src/ghUser.ts +6 -6
  43. package/src/index.ts +24 -22
  44. package/src/initializeFollowRules.ts +26 -26
  45. package/src/makePublishBranch.ts +58 -58
  46. package/src/makeTomlBranch.ts +53 -53
  47. package/src/matchRelatedPulls.ts +60 -60
  48. package/src/muteInstances.ts +16 -16
  49. package/src/parseIssueUrl.ts +6 -6
  50. package/src/parseOwnerRepo.ts +33 -33
  51. package/src/parsePullUrl.ts +6 -6
  52. package/src/parsePullsState.ts +6 -6
  53. package/src/parseTitleBodyOfMarkdown.ts +8 -8
  54. package/src/postSlackMessage.ts +21 -21
  55. package/src/preload.ts +30 -30
  56. package/src/pullStatusFollowSchema.ts +12 -12
  57. package/src/readTemplateTitle.ts +11 -11
  58. package/src/sendEmailAction.ts +56 -0
  59. package/src/sendGmail.ts +104 -0
  60. package/src/showFollowRuleSet.ts +12 -12
  61. package/src/summaryLastPullComment.ts +8 -8
  62. package/src/tomlFillDescription.ts +17 -17
  63. package/src/updateAuthors.ts +7 -7
  64. package/src/updateAuthorsForGithub.ts +54 -50
  65. package/src/updateAuthorsFromCNRepo.ts +30 -30
  66. package/src/updateCMNodesDuplicationWarnings.ts +56 -56
  67. package/src/updateCMRepos.ts +27 -27
  68. package/src/updateCNRepos.ts +58 -58
  69. package/src/updateCNReposCRPullsComments.ts +40 -40
  70. package/src/updateCNReposInfo.ts +57 -57
  71. package/src/updateCNReposPRCandidate.ts +85 -85
  72. package/src/updateCNReposPulls.ts +28 -28
  73. package/src/updateCNReposPullsDashboard.ts +49 -49
  74. package/src/updateCNReposRelatedPulls.ts +25 -25
  75. package/src/updateCRNodes.ts +50 -50
  76. package/src/updateCRRepos.ts +26 -26
  77. package/src/updateComfyTotals.ts +43 -43
  78. package/src/updateFollowRuleSet.ts +137 -127
  79. package/src/updateOutdatedPullsTemplates.ts +160 -160
  80. package/src/updateSlackMessages.ts +43 -43
  81. package/tailwind.config.ts +20 -20
@@ -1,170 +1,193 @@
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 } 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
+ export async function analyzePullsStatus({ skip = 0, limit = 0, pipeline = analyzePullsStatusPipeline() } = {}) {
43
+ "use server";
44
+ return await pipeline
45
+ .skip(skip)
46
+ .limit(limit || 2 ** 31 - 1)
47
+ .aggregate()
48
+ .map(({ updated_at, created_at, actived_at, on_registry_at, ...pull }) => {
49
+ const pull_updated = prettyMs(+new Date() - +new Date(updated_at), { compact: true }) + " ago";
50
+ const repo_updated = prettyMs(+new Date() - +new Date(actived_at), { compact: true }) + " ago";
51
+ return {
52
+ updated: pull_updated, // @deprecated
53
+ pull_updated,
54
+ repo_updated,
55
+ ...pull,
56
+ lastwords: pull.lastwords?.replace(/\s+/g, " ").replace(/\*\*\*.*/g, "..."),
57
+ };
58
+ })
59
+ .toArray();
60
+ }
61
+ export function baseCRPullStatusPipeline() {
62
+ return (
63
+ $pipeline(CNRepos)
64
+ // get latest pr comments time
65
+ .set({ "crPulls.data.pull.latest_comment_at": { $max: { $max: "$crPulls.data.comments.data.updated_at" } } })
66
+ // unwind
67
+ .stage({ $unwind: "$crPulls.data" })
68
+ .match({ "crPulls.data.comments.data": { $exists: true } })
69
+ // repo infos
70
+ .set({ "crPulls.data.pull.actived_at": { $toDate: "$info.data.updated_at" } })
71
+ .set({ "crPulls.data.pull.repo": "$repository" })
72
+ .set({ "crPulls.data.pull.email": "$email" })
73
+ .set({ "crPulls.data.pull.on_registry": "$on_registry" })
74
+ // pull info
75
+ .set({ "crPulls.data.pull.type": "$crPulls.data.type" })
76
+ .set({ "crPulls.data.pull": "$crPulls.data.pull" })
77
+ .set({ "crPulls.data.pull.comments": "$crPulls.data.comments.data" })
78
+ .set({ "crPulls.data.pull.emailTask_id": "$crPulls.data.emailTask_id" })
79
+ // replace root as pull
80
+ .replaceRoot({ newRoot: "$crPulls.data.pull" })
81
+ .as<
82
+ CRPull & {
83
+ repo: string;
84
+ on_registry: Task<boolean>;
85
+ type: string;
86
+ comments: GithubIssueComment[];
87
+ emailTask_id?: ObjectId;
88
+ }
89
+ >()
90
+ );
91
+ }
92
+ export function analyzePullsStatusPipeline() {
93
+ return (
94
+ baseCRPullStatusPipeline()
95
+ // fetch author email from Authors collection
96
+ .set({ ownername: "$base.user.login" })
97
+ .lookup({
98
+ from: "Authors",
99
+ // let: { <var_1>: <expression>, …, <var_n>: <expression> },
100
+ localField: "ownername",
101
+ foreignField: "githubId",
102
+ as: "author",
103
+ pipeline: [{ $project: { email: 1 } }],
104
+ })
105
+ .unwind({ path: "$author", preserveNullAndEmptyArrays: true })
106
+ .with<{ author: Author }>()
107
+ .lookup({
108
+ from: "EmailTasks",
109
+ // let: { <var_1>: <expression>, …, <var_n>: <expression> },
110
+ localField: "emailTask_id",
111
+ foreignField: "_id",
112
+ as: "emailTask",
113
+ })
114
+ .unwind({ path: "$emailTask", preserveNullAndEmptyArrays: true })
115
+ .set({ emailState: "$emailTask.state" }) //could be undefined or "waiting" | "sending" | "sent" | "error";
116
+ .with<{ emailState: EmailTask["state"] }>()
117
+
118
+ // .set({ author: { $first: ["$author"] } })
119
+ .project({ authors: 0 })
120
+
121
+ .set({ lastwords: { $arrayElemAt: ["$comments", -1] } })
122
+ .set({ lastwords: { $ifNull: [{ $concat: ["$lastwords.user.login", ": ", "$lastwords.body"] }, ""] } })
123
+
124
+ // calculate update_at max( )
125
+ // date format convert
126
+ .set({ created_at: { $toDate: "$created_at" } })
127
+ .set({ updated_at: { $toDate: "$updated_at" } })
128
+ .set({ latest_comment_at: { $toDate: "$latest_comment_at" } })
129
+ .set({ updated_at: { $max: ["$latest_comment_at", "$updated_at"] } })
130
+
131
+ // // projecting
132
+ .project({
133
+ created_at: 1,
134
+ updated_at: 1,
135
+ repository: 1,
136
+ on_registry: "$on_registry.data",
137
+ on_registry_at: "$on_registry.mtime",
138
+ state: { $toUpper: `$prState` },
139
+ url: "$html_url",
140
+ ownername: "$base.user.login",
141
+ nickName: "$base.user.name",
142
+ head: { $concat: ["$user.login", ":", "$type"] },
143
+ comments: { $size: "$comments" },
144
+ comments_author: {
145
+ $trim: {
146
+ input: {
147
+ $reduce: {
148
+ input: "$comments.user.login",
149
+ initialValue: "",
150
+ in: { $concat: ["$$value", " ", "$$this"] },
151
+ },
152
+ },
153
+ chars: " ",
154
+ },
155
+ },
156
+ lastwords: 1,
157
+ actived_at: 1,
158
+
159
+ instagramId: "$author.instagramId",
160
+ discordId: "$author.discordId",
161
+ twitterId: "$author.twitterId",
162
+ email: { $ifNull: ["$author.email", ""] },
163
+ emailState: 1,
164
+ })
165
+ .unset("latest_comment_at")
166
+ .set({
167
+ CLOSED: { $eq: ["$state", "CLOSED"] },
168
+ MERGED: { $eq: ["$state", "MERGED"] },
169
+ OPEN: { $eq: ["$state", "OPEN"] },
170
+ })
171
+ .sort({ ownername: 1 })
172
+ .sort({ OPEN: -1, MERGED: -1, CLOSED: -1, updated_at: 1 })
173
+ .unset(["CLOSED", "MERGED", "OPEN"])
174
+ .as<{
175
+ actived_at: Date;
176
+ email: string | "";
177
+ comments: number;
178
+ created_at: Date;
179
+ head: string;
180
+ lastwords: string;
181
+ on_registry_at: Date;
182
+ on_registry: boolean;
183
+ comments_author: string;
184
+ ownername: string;
185
+ nickName: string;
186
+ repository: string;
187
+ state: "OPEN" | "MERGED" | "CLOSED";
188
+ updated_at: Date;
189
+ emailState: EmailTask["state"];
190
+ url: string;
191
+ }>()
192
+ );
193
+ }
@@ -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
+ }