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
@@ -0,0 +1,245 @@
1
+ import { $pipeline } from "@/packages/mongodb-pipeline-ts/$pipeline";
2
+ import { TaskError, TaskErrorOrNull, TaskOK, type Task } from "@/packages/mongodb-pipeline-ts/Task";
3
+ import DIE from "@snomiao/die";
4
+ import { sleep } from "bun";
5
+ import { readFile } from "fs/promises";
6
+ import type { WithId } from "mongodb";
7
+ import { basename, dirname } from "path";
8
+ import sflow, { nil } from "sflow";
9
+ import { CNRepos } from "./CNRepos";
10
+ import { GIT_USEREMAIL } from "./GIT_USEREMAIL";
11
+ import { GIT_USERNAME } from "./GIT_USERNAME";
12
+ import { isRepoBypassed } from "./bypassRepos";
13
+ import { $ } from "./cli/echoBunShell";
14
+ import { createGithubForkForRepo } from "./createGithubForkForRepo";
15
+ import { createGithubPullRequest } from "./createGithubPullRequest";
16
+ import { $filaten, $stale, db } from "./db";
17
+ import { getBranchWorkingDir } from "./getBranchWorkingDir";
18
+ import { gh } from "./gh";
19
+ import type { GithubPull } from "./gh/GithubPull";
20
+ import { parseUrlRepoOwner, stringifyGithubOrigin } from "./parseOwnerRepo";
21
+ import { parsePullUrl } from "./parsePullUrl";
22
+ import { parseTitleBodyOfMarkdown } from "./parseTitleBodyOfMarkdown";
23
+
24
+ type LicenseUpdateTask = {
25
+ repository: string;
26
+ tomlUpdated?: boolean;
27
+ prTask: Task<any>;
28
+ updatedAt?: Date;
29
+ };
30
+
31
+ const LicenseTasks = db.collection<LicenseUpdateTask>("LicenseTasks");
32
+ await LicenseTasks.createIndex({ repository: 1 }, { unique: true });
33
+
34
+ if (import.meta.main) {
35
+ // - [Add pyproject.toml for Custom Node Registry by haohaocreates · Pull Request #1 · loopyd/ComfyUI-FD-Tagger]( https://github.com/loopyd/ComfyUI-FD-Tagger/pull/1 )
36
+ // await LicenseTasks.deleteMany({});
37
+ // await _pullTemplate();
38
+ // const testUpstreamRepo = "https://github.com/haohaocreates/ComfyUI-HH-Image-Selector";
39
+ // await _testMakeUpdateTomlLicenseBranch();
40
+ // await _listReposWithNoLicense();
41
+ const testMapping = {
42
+ [`license = "MIT"`]: `license = { text = "MIT" }`,
43
+ [`license = "LICENSE.txt"`]: `license = { file = "LICENSE.txt" }`,
44
+ };
45
+
46
+ const repoExamples = {
47
+ "https://github.com/MuziekMagie/ComfyUI-Matchering": "license already updated",
48
+ // - [ComfyUI_FizzNodes/LICENCE.txt at main · FizzleDorf/ComfyUI_FizzNodes]( https://github.com/FizzleDorf/ComfyUI_FizzNodes/blob/main/LICENCE.txt )
49
+ "https://github.com/FizzleDorf/ComfyUI_FizzNodes": "licenCe",
50
+ };
51
+
52
+ await updateTomlLicenseTasks();
53
+ console.log("ALL DONE");
54
+ }
55
+
56
+ async function _listReposWithNoLicense() {
57
+ console.log(
58
+ await $pipeline(CNRepos)
59
+ .match({ cr: { $exists: true }, "info.data": { $exists: true }, "info.data.license": null })
60
+ .project({ _id: 0, repository: 1, gh_license: "$info.data.license" })
61
+ .aggregate()
62
+ .next(),
63
+ );
64
+ }
65
+
66
+ export async function updateTomlLicenseTasks() {
67
+ // collect tasks
68
+ await $pipeline(CNRepos)
69
+ .match({ cr: { $exists: true } })
70
+ .project({ _id: 0, repository: 1 })
71
+ .merge({ into: LicenseTasks.collectionName, on: "repository" })
72
+ .aggregate()
73
+ .next();
74
+
75
+ // reset retry-able errors with a cd interval
76
+ await LicenseTasks.updateMany($filaten({ prTask: { error: /was submitted too quickly/, mtime: $stale("5m") } }), {
77
+ $unset: { prTask: 1 },
78
+ });
79
+ await LicenseTasks.updateMany($filaten({ prTask: { error: /Missing env.GH_TOKEN_COMFY_PR/, mtime: $stale("1h") } }), {
80
+ $unset: { prTask: 1 },
81
+ });
82
+ console.log((await LicenseTasks.estimatedDocumentCount()) + " license tasks");
83
+
84
+ // update tasks
85
+ await sflow(
86
+ $pipeline(LicenseTasks)
87
+ .match({ tomlUpdated: { $ne: true }, updatedAt: $stale("5m") })
88
+ .as<WithId<LicenseUpdateTask>>()
89
+ .aggregate(),
90
+ )
91
+ .filter(({ repository }) => !isRepoBypassed(repository))
92
+ .pMap(
93
+ async ({ _id, repository }) => {
94
+ const prTask = await createTomlLicensePR(repository).then(TaskOK).catch(TaskError);
95
+ const tomlUpdated = !!TaskErrorOrNull(prTask)?.match("not matched outdated case");
96
+ return await LicenseTasks.findOneAndUpdate(
97
+ { _id },
98
+ { $set: { tomlUpdated, prTask, updatedAt: new Date() } },
99
+ { returnDocument: "after" },
100
+ );
101
+ },
102
+ { concurrency: 3 },
103
+ )
104
+ .forEach(() => sleep(2e3))
105
+ .toLog();
106
+ }
107
+
108
+ async function _testMakeUpdateTomlLicenseBranch() {
109
+ const testUpstreamRepo = "https://github.com/snomiao/comfy-malicious-node-test";
110
+
111
+ const prTask = await createTomlLicensePR(testUpstreamRepo).then(TaskOK).catch(TaskError);
112
+ if (TaskErrorOrNull(prTask)?.match("Not matched outdated case")) console.log("not matched outdated case");
113
+ console.log(prTask);
114
+ console.log("prs_updateTomlLicense PRs DONE");
115
+ }
116
+
117
+ async function createTomlLicensePR(upstreamUrl: string): Promise<GithubPull> {
118
+ const { html_url: forkUrl } = await createGithubForkForRepo(upstreamUrl);
119
+ const branchInfo = await makeUpdateTomlLicenseBranch(upstreamUrl, forkUrl);
120
+ // console.log(forkUrl); // note: this forkUrl may not be final forked url
121
+ console.log({ branchInfo });
122
+ return (
123
+ (await sflow([branchInfo])
124
+ .map(({ upstreamUrl, forkUrl, ...e }) => ({
125
+ ...e,
126
+ srcUrl: forkUrl,
127
+ dstUrl: upstreamUrl,
128
+ }))
129
+ .map(async ({ type, ...prInfo }) => await createGithubPullRequest({ ...prInfo }))
130
+ .forEach((e) => e || DIE("missing pr result"))
131
+ .toOne()) ?? DIE("never")
132
+ );
133
+ }
134
+
135
+ export async function makeUpdateTomlLicenseBranch(upstreamUrl: string, forkUrl: string) {
136
+ const type = "licence-update" as const;
137
+ const branch = "licence-update";
138
+ const tmpl = await readFile("./templates/update-toml-license.md", "utf8");
139
+ const { title, body } = parseTitleBodyOfMarkdown(tmpl);
140
+
141
+ // check forked repo if target branch existed
142
+ const origin = await stringifyGithubOrigin(parseUrlRepoOwner(forkUrl));
143
+ const repo = parseUrlRepoOwner(forkUrl);
144
+ const existedBranch = await gh.repos.getBranch({ ...repo, branch }).catch(() => null);
145
+
146
+ const cwd = await getBranchWorkingDir(upstreamUrl, forkUrl, branch);
147
+ // commit changes
148
+ await $`
149
+ rm -rf ${cwd}
150
+ git clone ${upstreamUrl} ${cwd}
151
+ `;
152
+
153
+ // // also pull from existed forked branch
154
+ // if (existedBranch)
155
+ // await $`
156
+ // cd ${cwd}
157
+ // git pull ${forkUrl} ${branch}
158
+ // `;
159
+
160
+ const pyprojectToml = cwd + "/pyproject.toml";
161
+ const { updated, license } = await pyprojectTomlUpdateLicenses(pyprojectToml, upstreamUrl);
162
+ if (!updated) throw new Error("License field not matched outdated case, skip pr");
163
+
164
+ if (existedBranch) {
165
+ console.log("[debug] skip update already forked branch " + branch);
166
+ return { type, title, body, branch, upstreamUrl, forkUrl, license };
167
+ }
168
+
169
+ // prepare local branch
170
+ await $`
171
+ cd ${cwd}
172
+ git config user.name ${GIT_USERNAME} && \
173
+ git config user.email ${GIT_USEREMAIL} && \
174
+ git checkout -b ${branch} && \
175
+ git add . && \
176
+ git commit -am ${`chore(${branch}): ${title}`}
177
+ `;
178
+
179
+ await $`
180
+ cd ${cwd}
181
+ git push "${origin}" ${branch}:${branch}
182
+ `;
183
+ const branchUrl = `https://github.com/${repo.owner}/${repo.repo}/tree/${branch}`;
184
+ console.log(`Branch Push OK: ${branchUrl}`);
185
+
186
+ return { type, title, body, branch, upstreamUrl, forkUrl, license };
187
+ }
188
+
189
+ export async function pyprojectTomlUpdateLicenses(tomlFile: string, upstreamRepoUrl: string) {
190
+ const raw =
191
+ (await Bun.file(tomlFile).text().catch(nil)) || DIE(new Error("pyproject.toml file not existed or got empty file"));
192
+ const m = raw.match(/^license\s*=(.*)/im);
193
+
194
+ const licenseLine = m?.[0];
195
+ const license = m?.[1]?.trim();
196
+ const outdatedDesiredLicense = license?.match(/^"([^"\n\r]+)"$/i)?.[1];
197
+ const isOutdated = !!outdatedDesiredLicense;
198
+ // const isOutdated = !!raw.match(outdated);
199
+ license && (await LicenseTasks.updateOne({ repository: upstreamRepoUrl }, { $set: { license: license } }));
200
+ if (!licenseLine) throw new Error("no license line was found, please check toml file");
201
+ if (!isOutdated) return { updated: false }; // not outdated
202
+
203
+ let updated: string | null = "";
204
+
205
+ // try load local license file first
206
+ updated ||= await (async function () {
207
+ const desiredLicenseIsFile = !!outdatedDesiredLicense.match(/LICEN[SC]E/);
208
+ if (!desiredLicenseIsFile) return null;
209
+ const licenses = await Array.fromAsync(new Bun.Glob(dirname(tomlFile) + "/LICEN[CS]E*").scan()); // note: LICENCE will be mismatch in this case
210
+ if (licenses.length > 1) DIE(new Error("Multiple license found: " + JSON.stringify(licenses)));
211
+
212
+ const licenseFilename = licenses[0];
213
+ if (!licenseFilename) return null;
214
+ return `license = { file = "${basename(licenseFilename)}" }`;
215
+ })();
216
+
217
+ // - [Writing your pyproject.toml - Python Packaging User Guide]( https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license )
218
+ updated ||= await (async function () {
219
+ const resp = await gh.repos.get({ ...parseUrlRepoOwner(upstreamRepoUrl) });
220
+ const license = resp.data.license;
221
+ if (!license) return null;
222
+ return `license = { text = "${license?.name}" }`;
223
+ })();
224
+
225
+ if (!updated)
226
+ DIE(
227
+ `Fail to get repo license from repo please contact author to create a license file\nMISSING_LICENSE_REPO: ${upstreamRepoUrl}`,
228
+ );
229
+
230
+ const replaced = raw.replace(licenseLine, () => updated);
231
+ if (replaced === raw) DIE(new Error("licenseLine not matched", { cause: { raw, licenseLine, updated } }));
232
+ await LicenseTasks.updateOne({ repository: upstreamRepoUrl }, { $set: { updateLine: updated } });
233
+ await Bun.write(tomlFile, replaced);
234
+ return { updated: true, license: replaced.match(/^license\s*=(.*)/i)?.[1]?.trim() };
235
+ }
236
+
237
+ /** use when template updated */
238
+ async function _pullTemplate() {
239
+ const referenceTemplate = "https://github.com/haohaocreates/ComfyUI-HH-Image-Selector/pull/3";
240
+ const template = await sflow(gh.pulls.get(parsePullUrl(referenceTemplate)))
241
+ .map((e) => e.data.body!)
242
+ .text();
243
+ await Bun.write("./templates/update-toml-license.md", template);
244
+ console.log(template);
245
+ }
@@ -1,60 +1,47 @@
1
- import pMap from "p-map";
2
- import { match } from "ts-pattern";
3
- import { fetchRelatedPullWithComments } from "./fetchRelatedPullWithComments";
4
- import type { GithubPullParsed } from "./parsePullsState";
5
- import { readTemplateTitle } from "./readTemplateTitle";
6
-
7
- export type RelatedPullsWithComments = Awaited<ReturnType<typeof fetchRelatedPullWithComments>>;
8
- export type RelatedPull = Awaited<ReturnType<typeof matchRelatedPulls>>[number];
9
- export async function matchRelatedPulls(pulls: GithubPullParsed[]): Promise<
10
- (
11
- | {
12
- type: "pyproject";
13
- pull: {
14
- title: string;
15
- number: number;
16
- url: string;
17
- html_url: string;
18
- user: { login: string; html_url: string };
19
- body: string | null;
20
- prState: "closed" | "open" | "merged";
21
- updatedAt: Date;
22
- createdAt: Date;
23
- updated_at: Date;
24
- created_at: Date;
25
- };
26
- }
27
- | {
28
- type: "publishcr";
29
- pull: {
30
- title: string;
31
- number: number;
32
- url: string;
33
- html_url: string;
34
- user: { login: string; html_url: string };
35
- body: string | null;
36
- prState: "closed" | "open" | "merged";
37
- updatedAt: Date;
38
- createdAt: Date;
39
- updated_at: Date;
40
- created_at: Date;
41
- };
42
- }
43
- )[]
44
- > {
45
- const pyproject = await readTemplateTitle("add-toml.md");
46
- const publishcr = await readTemplateTitle("add-action.md");
47
- const relatedPulls = await pMap(pulls, async (pull) =>
48
- match(pull)
49
- .with({ title: pyproject }, (pull) => ({
50
- type: "pyproject" as const,
51
- pull,
52
- }))
53
- .with({ title: publishcr }, (pull) => ({
54
- type: "publishcr" as const,
55
- pull,
56
- }))
57
- .otherwise(() => null),
58
- );
59
- return relatedPulls.flatMap((e) => (e ? [e] : []));
60
- }
1
+ import pMap from "p-map";
2
+ import { match } from "ts-pattern";
3
+ import { fetchRelatedPullWithComments } from "./fetchRelatedPullWithComments";
4
+ import type { GithubPullParsed } from "./parsePullsState";
5
+ import { readTemplateTitle } from "./readTemplateTitle";
6
+
7
+ export type RelatedPullsWithComments = Awaited<ReturnType<typeof fetchRelatedPullWithComments>>;
8
+ export type RelatedPull = Awaited<ReturnType<typeof matchRelatedPulls>>[number];
9
+ export async function matchRelatedPulls(pulls: GithubPullParsed[]): Promise<
10
+ {
11
+ type: "pyproject" | "publishcr" | "licence-update";
12
+ pull: {
13
+ title: string;
14
+ number: number;
15
+ url: string;
16
+ html_url: string;
17
+ user: { login: string; html_url: string };
18
+ body: string | null;
19
+ prState: "closed" | "open" | "merged";
20
+ updatedAt: Date;
21
+ createdAt: Date;
22
+ updated_at: Date;
23
+ created_at: Date;
24
+ };
25
+ }[]
26
+ > {
27
+ const pyproject = await readTemplateTitle("add-toml.md");
28
+ const publishcr = await readTemplateTitle("add-action.md");
29
+ const licenseUpdate = await readTemplateTitle("update-toml-license.md");
30
+ const relatedPulls = await pMap(pulls, async (pull) =>
31
+ match(pull)
32
+ .with({ title: pyproject }, (pull) => ({
33
+ type: "pyproject" as const,
34
+ pull,
35
+ }))
36
+ .with({ title: licenseUpdate }, (pull) => ({
37
+ type: "licence-update" as const,
38
+ pull,
39
+ }))
40
+ .with({ title: publishcr }, (pull) => ({
41
+ type: "publishcr" as const,
42
+ pull,
43
+ }))
44
+ .otherwise(() => null),
45
+ );
46
+ return relatedPulls.flatMap((e) => (e ? [e] : []));
47
+ }
@@ -1,16 +1,16 @@
1
- #!/usr/bin/env bun
2
- import { readFile, writeFile } from "fs/promises";
3
- import { globby } from "globby";
4
- import pMap from "p-map";
5
- if (import.meta.main) {
6
- const files = await globby("node_modules/**/*instance*.js");
7
- await pMap(files, async (file) => {
8
- const x = await readFile(file, "utf8");
9
- const y = x.replace(/console.warn/, ";");
10
- if (x !== y) {
11
- await writeFile(file, y);
12
- console.log("muted: " + file);
13
- }
14
- });
15
- console.log("done");
16
- }
1
+ #!/usr/bin/env bun
2
+ import { readFile, writeFile } from "fs/promises";
3
+ import { globby } from "globby";
4
+ import pMap from "p-map";
5
+ if (import.meta.main) {
6
+ const files = await globby("node_modules/**/*instance*.js");
7
+ await pMap(files, async (file) => {
8
+ const x = await readFile(file, "utf8");
9
+ const y = x.replace(/console.warn/, ";");
10
+ if (x !== y) {
11
+ await writeFile(file, y);
12
+ console.log("muted: " + file);
13
+ }
14
+ });
15
+ console.log("done");
16
+ }
@@ -1,6 +1,6 @@
1
- export function parseIssueUrl(issueUrl: string) {
2
- const [owner, repo, strNumber] = issueUrl
3
- .match(/^https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(?:pull|issues)\/(\d+)$/)!
4
- .slice(1);
5
- return { owner, repo, issue_number: Number(strNumber) };
6
- }
1
+ export function parseIssueUrl(issueUrl: string) {
2
+ const [owner, repo, strNumber] = issueUrl
3
+ .match(/^https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(?:pull|issues)\/(\d+)$/)!
4
+ .slice(1);
5
+ return { owner, repo, issue_number: Number(strNumber) };
6
+ }
@@ -1,33 +1,33 @@
1
- import { basename, dirname } from "path";
2
-
3
- /**
4
- * Parse owner and repo obj
5
- * @param gitUrl git@github.ocm:owner/repo or https://github.ocm/owner/repo
6
- */
7
- export function parseUrlRepoOwner(gitUrl: string) {
8
- return {
9
- owner: basename(dirname(gitUrl.replace(/:/, "/"))),
10
- repo: basename(gitUrl.replace(/:/, "/")).replace(/\.git$/, ""),
11
- };
12
- }
13
- export function stringifyOwnerRepo({ owner, repo }: ReturnType<typeof parseUrlRepoOwner>) {
14
- return owner + "/" + repo;
15
- }
16
- export function stringifyGithubRepoUrl({ owner, repo }: ReturnType<typeof parseUrlRepoOwner>) {
17
- return "https://github.com/" + owner + "/" + repo;
18
- }
19
- export async function stringifyGithubOrigin({ owner, repo }: ReturnType<typeof parseUrlRepoOwner>) {
20
- const PR_TOKEN = process.env.GH_TOKEN_COMFY_PR;
21
- if (PR_TOKEN) {
22
- // fails: maybe permission issue
23
- // const USERNAME = (
24
- // await new Octokit({
25
- // auth: PR_TOKEN,
26
- // }).rest.users.getAuthenticated()
27
- // ).data.login;
28
- // return `https://${USERNAME}:${PR_TOKEN}@github.com/${owner}/${repo}`;
29
-
30
- return `git@github.com:${owner}/${repo}`;
31
- }
32
- return `git@github.com:${owner}/${repo}`;
33
- }
1
+ import { basename, dirname } from "path";
2
+
3
+ /**
4
+ * Parse owner and repo obj
5
+ * @param gitUrl git@github.ocm:owner/repo or https://github.ocm/owner/repo
6
+ */
7
+ export function parseUrlRepoOwner(gitUrl: string) {
8
+ return {
9
+ owner: basename(dirname(gitUrl.replace(/:/, "/"))),
10
+ repo: basename(gitUrl.replace(/:/, "/")).replace(/\.git$/, ""),
11
+ };
12
+ }
13
+ export function stringifyOwnerRepo({ owner, repo }: ReturnType<typeof parseUrlRepoOwner>) {
14
+ return owner + "/" + repo;
15
+ }
16
+ export function stringifyGithubRepoUrl({ owner, repo }: ReturnType<typeof parseUrlRepoOwner>) {
17
+ return "https://github.com/" + owner + "/" + repo;
18
+ }
19
+ export async function stringifyGithubOrigin({ owner, repo }: ReturnType<typeof parseUrlRepoOwner>) {
20
+ const PR_TOKEN = process.env.GH_TOKEN_COMFY_PR;
21
+ if (PR_TOKEN) {
22
+ // fails: maybe permission issue
23
+ // const USERNAME = (
24
+ // await new Octokit({
25
+ // auth: PR_TOKEN,
26
+ // }).rest.users.getAuthenticated()
27
+ // ).data.login;
28
+ // return `https://${USERNAME}:${PR_TOKEN}@github.com/${owner}/${repo}`;
29
+
30
+ return `git@github.com:${owner}/${repo}`;
31
+ }
32
+ return `git@github.com:${owner}/${repo}`;
33
+ }
@@ -1,6 +1,6 @@
1
- export function parsePullUrl(issueUrl: string) {
2
- const [owner, repo, strNumber] = issueUrl
3
- .match(/^https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(?:pull)\/(\d+)$/)!
4
- .slice(1);
5
- return { owner, repo, pull_number: Number(strNumber) };
6
- }
1
+ export function parsePullUrl(issueUrl: string) {
2
+ const [owner, repo, strNumber] = issueUrl
3
+ .match(/^https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(?:pull)\/(\d+)$/)!
4
+ .slice(1);
5
+ return { owner, repo, pull_number: Number(strNumber) };
6
+ }
@@ -1,6 +1,6 @@
1
- import type { GithubPull } from "./gh/GithubPull";
2
- import { parsePull } from "./gh/parsePull";
3
- export type GithubPullParsed = ReturnType<typeof parsePulls>[number];
4
- export function parsePulls(data: GithubPull[]) {
5
- return data.map((e) => parsePull(e));
6
- }
1
+ import type { GithubPull } from "./gh/GithubPull";
2
+ import { parsePull } from "./gh/parsePull";
3
+ export type GithubPullParsed = ReturnType<typeof parsePulls>[number];
4
+ export function parsePulls(data: GithubPull[]) {
5
+ return data.map((e) => parsePull(e));
6
+ }
@@ -1,8 +1,8 @@
1
- import DIE from "@snomiao/die";
2
-
3
- export function parseTitleBodyOfMarkdown(tmpl: string) {
4
- tmpl.startsWith("# ") || DIE("Unrecognized template format:" + tmpl);
5
- const title = tmpl.split("\n")[0].slice(1).trim();
6
- const body = tmpl.split("\n").slice(1).join("\n").trim();
7
- return { title, body };
8
- }
1
+ import DIE from "@snomiao/die";
2
+
3
+ export function parseTitleBodyOfMarkdown(tmpl: string) {
4
+ tmpl.startsWith("# ") || DIE("Unrecognized template format:" + tmpl);
5
+ const title = tmpl.split("\n")[0].slice(1).trim();
6
+ const body = tmpl.split("\n").slice(1).join("\n").trim();
7
+ return { title, body };
8
+ }
@@ -1,21 +1,21 @@
1
- import DIE from "@snomiao/die";
2
- import { slack } from "./slack";
3
-
4
- export async function postSlackMessage(text: string) {
5
- const channel = process.env.SLACK_BOT_CHANNEL || DIE(new Error("missing env.SLACK_BOT_CHANNEL"));
6
- // this api will auto retry if failed
7
- const response = await slack.chat.postMessage({
8
- channel,
9
- text,
10
- blocks: [
11
- {
12
- type: "section",
13
- text: {
14
- type: "mrkdwn",
15
- text: text,
16
- },
17
- },
18
- ],
19
- });
20
- return { channel, ts: response.ts, text };
21
- }
1
+ import DIE from "@snomiao/die";
2
+ import { slack } from "./slack";
3
+
4
+ export async function postSlackMessage(text: string) {
5
+ const channel = process.env.SLACK_BOT_CHANNEL || DIE(new Error("missing env.SLACK_BOT_CHANNEL"));
6
+ // this api will auto retry if failed
7
+ const response = await slack.chat.postMessage({
8
+ channel,
9
+ text,
10
+ blocks: [
11
+ {
12
+ type: "section",
13
+ text: {
14
+ type: "mrkdwn",
15
+ text: text,
16
+ },
17
+ },
18
+ ],
19
+ });
20
+ return { channel, ts: response.ts, text };
21
+ }
package/src/preload.ts CHANGED
@@ -1,30 +1,30 @@
1
- await Bun.plugin({
2
- name: "YAML",
3
- async setup(build) {
4
- const { load } = await import("js-yaml");
5
-
6
- // when a .yaml file is imported...
7
- build.onLoad({ filter: /\.(yaml|yml)$/ }, async (args) => {
8
- // read and parse the file
9
- const text = await Bun.file(args.path).text();
10
- const exports = load(text) as Record<string, any>;
11
-
12
- // and returns it as a module
13
- return {
14
- exports,
15
- loader: "object", // special loader for JS objects
16
- };
17
- });
18
- },
19
- });
20
-
21
- Bun.plugin({
22
- name: "preload-plugin",
23
- setup(builder) {
24
- builder.onLoad({ filter: /\.ts$/ }, async (args) => {
25
- const text = await Bun.file(args.path).text();
26
- // console.log("text", text);
27
- return { contents: text, loader: args.loader };
28
- });
29
- },
30
- });
1
+ await Bun.plugin({
2
+ name: "YAML",
3
+ async setup(build) {
4
+ const { load } = await import("js-yaml");
5
+
6
+ // when a .yaml file is imported...
7
+ build.onLoad({ filter: /\.(yaml|yml)$/ }, async (args) => {
8
+ // read and parse the file
9
+ const text = await Bun.file(args.path).text();
10
+ const exports = load(text) as Record<string, any>;
11
+
12
+ // and returns it as a module
13
+ return {
14
+ exports,
15
+ loader: "object", // special loader for JS objects
16
+ };
17
+ });
18
+ },
19
+ });
20
+
21
+ Bun.plugin({
22
+ name: "preload-plugin",
23
+ setup(builder) {
24
+ builder.onLoad({ filter: /\.ts$/ }, async (args) => {
25
+ const text = await Bun.file(args.path).text();
26
+ // console.log("text", text);
27
+ return { contents: text, loader: args.loader };
28
+ });
29
+ },
30
+ });
@@ -1,12 +1,12 @@
1
- import { z } from "zod";
2
-
3
- export const zPullStatusFollow = z.array(
4
- z.object({
5
- updated: z.string(),
6
- state: z.string(),
7
- url: z.string(),
8
- head: z.string(),
9
- comments: z.number(),
10
- lastwords: z.string(),
11
- }),
12
- );
1
+ import { z } from "zod";
2
+
3
+ export const zPullStatusFollow = z.array(
4
+ z.object({
5
+ updated: z.string(),
6
+ state: z.string(),
7
+ url: z.string(),
8
+ head: z.string(),
9
+ comments: z.number(),
10
+ lastcomment: z.string(),
11
+ }),
12
+ );