From 68adf6cf922ffd11ca1c049f815e2f5fef6b59eb Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:06:23 +0100 Subject: [PATCH 1/8] trigger.dev setup --- app/api/trigger/route.ts | 10 ++ jobs/index.ts | 3 + jobs/issueReminder.ts | 83 ++++++++++++++ package.json | 6 + pnpm-lock.yaml | 232 ++++++++++++++++++++++++++++++++++++++- trigger.ts | 7 ++ 6 files changed, 335 insertions(+), 6 deletions(-) create mode 100644 app/api/trigger/route.ts create mode 100644 jobs/index.ts create mode 100644 jobs/issueReminder.ts create mode 100644 trigger.ts diff --git a/app/api/trigger/route.ts b/app/api/trigger/route.ts new file mode 100644 index 0000000..304646e --- /dev/null +++ b/app/api/trigger/route.ts @@ -0,0 +1,10 @@ +import { createAppRoute } from "@trigger.dev/nextjs"; +import { client } from "@/trigger"; + +import "@/jobs"; + +//this route is used to send and receive data with Trigger.dev +export const { POST, dynamic } = createAppRoute(client); + +//uncomment this to set a higher max duration (it must be inside your plan limits). Full docs: https://vercel.com/docs/functions/serverless-functions/runtimes#max-duration +//export const maxDuration = 60; \ No newline at end of file diff --git a/jobs/index.ts b/jobs/index.ts new file mode 100644 index 0000000..669902f --- /dev/null +++ b/jobs/index.ts @@ -0,0 +1,3 @@ +// export all your job files here + +export * from "./issueReminder" \ No newline at end of file diff --git a/jobs/issueReminder.ts b/jobs/issueReminder.ts new file mode 100644 index 0000000..25eb172 --- /dev/null +++ b/jobs/issueReminder.ts @@ -0,0 +1,83 @@ +import { getOctokitInstance } from "@/lib/github/utils"; +import { client } from "@/trigger"; +import { eventTrigger } from "@trigger.dev/sdk"; +import { z } from "zod"; + +client.defineJob({ + // This is the unique identifier for your Job, it must be unique across all Jobs in your project. + id: "issue-remainder-job", + name: "issue remainder job", + version: "0.0.1", + // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction + trigger: eventTrigger({ + name: "issue.remainder", + schema: z.object({ + issueNumber: z.number(), + repo: z.string(), + owner: z.string(), + commenter: z.string(), + installationId: z.number(), + }), + }), + run: async (payload, io, ctx) => { + const { issueNumber, repo, owner, commenter, installationId } = payload; + + const octokit = getOctokitInstance(installationId); + + //wait for 36hrs + await io.wait("waiting for 36hrs",36 * 60 * 60); + + //make this a task so that it can return the completed value from the prev run + await io.runTask("pull-request-checker", async () => { + const { data: issue } = await octokit.issues.get({ + owner: owner, + repo: repo, + issue_number: issueNumber, + }); + + if (issue.pull_request) { + io.logger.info("pull request has been created for the issue after 36hrs"); + return; + } else { + //send a comment remainder to the issue + io.logger.info("pull request has not been created for the issue after 36hrs, sending a reminder"); + await octokit.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body: ` @${commenter}, You have 12hrs left to create a pull request for this issue. `, + }); + } + }); + + await io.wait("waiting for 12hrs",12 * 60 * 60); + + await io.runTask("pull-request-checker-after-12hrs", async () => { + const { data: issue } = await octokit.issues.get({ + owner: owner, + repo: repo, + issue_number: issueNumber, + }); + + if (issue.pull_request) { + io.logger.info("pull request has been created for the issue after 12hrs"); + return + } else { + io.logger.info("pull request has not been created for the issue after 12hrs"); + await octokit.issues.createComment({ + owner: owner, + repo: repo, + issue_number: issueNumber, + body: `@${commenter} has been unassigned from the issue, anyone can now take it up.`, + }); + await octokit.issues.removeAssignees({ + owner: owner, + repo: repo, + issue_number: issueNumber, + assignees: [commenter], + }); + } + }); + + }, +}); diff --git a/package.json b/package.json index 5fd942e..f1ccaff 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,9 @@ "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "@t3-oss/env-nextjs": "^0.8.0", + "@trigger.dev/nextjs": "^2.3.18", + "@trigger.dev/react": "^2.3.18", + "@trigger.dev/sdk": "^2.3.18", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "jsonwebtoken": "^9.0.2", @@ -68,5 +71,8 @@ "rimraf": "^5.0.5", "tailwindcss": "^3.4.1", "typescript": "^5" + }, + "trigger.dev": { + "endpointId": "testing-bHhV" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10dba76..7d71727 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,15 @@ dependencies: '@t3-oss/env-nextjs': specifier: ^0.8.0 version: 0.8.0(typescript@5.3.3)(zod@3.22.4) + '@trigger.dev/nextjs': + specifier: ^2.3.18 + version: 2.3.18(@trigger.dev/sdk@2.3.18)(next@14.1.0) + '@trigger.dev/react': + specifier: ^2.3.18 + version: 2.3.18(react-dom@18.2.0)(react@18.2.0) + '@trigger.dev/sdk': + specifier: ^2.3.18 + version: 2.3.18 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -1872,6 +1881,97 @@ packages: zod: 3.22.4 dev: false + /@tanstack/query-core@5.0.0-beta.0: + resolution: {integrity: sha512-VGq/H3PuRoj0shOcg1S5Flv3YD2qNz2ttk8w5xe5AHQE1I8NO9EHSBUxezIpk4dD6M7bQDtwHBMqqU2EwMwyUw==} + dev: false + + /@tanstack/react-query@5.0.0-beta.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JdK1HRw20tuwg3GfT3QZTkuS7s2KDa9FeozuJ7jZULlwPczZagouqYmM6+PL0ad6jfCnw8NzmLFtZdlBx6cTmA==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@tanstack/query-core': 5.0.0-beta.0 + client-only: 0.0.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@trigger.dev/core-backend@2.3.18: + resolution: {integrity: sha512-LVeeerraGeqKNd2gtajQY+mnGWqkYW7Q2r5oWpL5xIZ8aQg3HRhSIfZs1dryexwKlfqnRjGWueGTy2+j1tbzcg==} + engines: {node: '>=18.0.0'} + dev: false + + /@trigger.dev/core@2.3.18: + resolution: {integrity: sha512-j2EdCeyMkZ+zlVnnHl5zmBb+YURSw4x75NqQU1G5X08pQAza7G0qEn8DDGIMR5ieUMiHP0WS9oYy/voYdNfibQ==} + engines: {node: '>=18.0.0'} + dependencies: + ulidx: 2.3.0 + zod: 3.22.3 + zod-error: 1.5.0 + dev: false + + /@trigger.dev/nextjs@2.3.18(@trigger.dev/sdk@2.3.18)(next@14.1.0): + resolution: {integrity: sha512-ZS0RTZNrzGEKfOLQLYt3iqlNquD7pd39Hpd/+2tvRCaPSQ3qPYQvdjBSueW0OURZSQSiNno5VUYR5vbVBcAaXA==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@trigger.dev/sdk': ^2.3.18 + next: '>=12.0.0' + dependencies: + '@trigger.dev/sdk': 2.3.18 + debug: 4.3.4 + next: 14.1.0(react-dom@18.2.0)(react@18.2.0) + transitivePeerDependencies: + - supports-color + dev: false + + /@trigger.dev/react@2.3.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-S+frKgYJoT5JEzYejqlL5rkeHVxTR7wuJvvBMk+cFwA+nKV6isr8VnWmGQivGXGDlKMdF8IihwO+Guqs5tv/Hw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18 + dependencies: + '@tanstack/react-query': 5.0.0-beta.2(react-dom@18.2.0)(react@18.2.0) + '@trigger.dev/core': 2.3.18 + debug: 4.3.4 + react: 18.2.0 + zod: 3.22.3 + transitivePeerDependencies: + - react-dom + - react-native + - supports-color + dev: false + + /@trigger.dev/sdk@2.3.18: + resolution: {integrity: sha512-Bjxgl4BbWOAL8rhxeBkl7SzvLLRBMJjiftq/7W7u96MDyPRFUoZZvVMSZzTJufnLBf/xS2JTi8LWU8gzhDJDvw==} + engines: {node: '>=18.0.0'} + dependencies: + '@trigger.dev/core': 2.3.18 + '@trigger.dev/core-backend': 2.3.18 + chalk: 5.3.0 + cronstrue: 2.48.0 + debug: 4.3.4 + evt: 2.5.7 + get-caller-file: 2.0.5 + git-remote-origin-url: 4.0.0 + git-repo-info: 2.1.1 + slug: 6.1.0 + terminal-link: 3.0.0 + ulid: 2.3.0 + uuid: 9.0.1 + ws: 8.16.0 + zod: 3.22.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.2.5): resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} peerDependencies: @@ -2057,6 +2157,13 @@ packages: uri-js: 4.4.1 dev: true + /ansi-escapes@5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: false + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2350,6 +2457,11 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -2507,6 +2619,11 @@ packages: typescript: 5.3.3 dev: true + /cronstrue@2.48.0: + resolution: {integrity: sha512-w+VAWjiBJmKYeeK+i0ur3G47LcKNgFuWwb8LVJTaXSS2ExtQ5zdiIVnuysgB3N457gTaSllme0qTpdsJWK/wIg==} + hasBin: true + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2553,7 +2670,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} @@ -3062,6 +3178,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /evt@2.5.7: + resolution: {integrity: sha512-dr7Wd16ry5F8WNU1xXLKpFpO3HsoAGg8zC48e08vDdzMzGWCP9/QFGt1PQptEEDh8SwYP3EL8M+d/Gb0kgUp6g==} + dependencies: + minimal-polyfills: 2.2.3 + run-exclusive: 2.2.19 + tsafe: 1.6.6 + dev: false + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3194,7 +3318,6 @@ packages: /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: true /get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} @@ -3241,6 +3364,24 @@ packages: through2: 4.0.2 dev: true + /git-remote-origin-url@4.0.0: + resolution: {integrity: sha512-EAxDksNdjuWgmVW9pVvA9jQDi/dmTaiDONktIy7qiRRhBZUI4FQK1YvBvteuTSX24aNKg9lfgxNYJEeeSXe6DA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + gitconfiglocal: 2.1.0 + dev: false + + /git-repo-info@2.1.1: + resolution: {integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==} + engines: {node: '>= 4.0'} + dev: false + + /gitconfiglocal@2.1.0: + resolution: {integrity: sha512-qoerOEliJn3z+Zyn1HW2F6eoYJqKwS6MgC9cztTLUB/xLWX8gD/6T60pKn4+t/d6tP7JlybI7Z3z+I572CR/Vg==} + dependencies: + ini: 1.3.8 + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3343,7 +3484,6 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-property-descriptors@1.0.1: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} @@ -3431,7 +3571,6 @@ packages: /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} @@ -3786,6 +3925,10 @@ packages: language-subtag-registry: 0.3.22 dev: true + /layerr@2.0.1: + resolution: {integrity: sha512-z0730CwG/JO24evdORnyDkwG1Q7b7mF2Tp1qRQ0YvrMMARbt1DFG694SOv439Gm7hYKolyZyaB49YIrYIfZBdg==} + dev: false + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -3967,6 +4110,10 @@ packages: engines: {node: '>=4'} dev: true + /minimal-polyfills@2.2.3: + resolution: {integrity: sha512-oxdmJ9cL+xV72h0xYxp4tP2d5/fTBpP45H8DIOn9pASuF8a3IYTf+25fMGDYGiWW+MFsuog6KD6nfmhZJQ+uUw==} + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -3998,7 +4145,6 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -4771,6 +4917,12 @@ packages: glob: 10.3.10 dev: true + /run-exclusive@2.2.19: + resolution: {integrity: sha512-K3mdoAi7tjJ/qT7Flj90L7QyPozwUaAG+CVhkdDje4HLKXUYC3N/Jzkau3flHVDLQVhiHBtcimVodMjN9egYbA==} + dependencies: + minimal-polyfills: 2.2.3 + dev: false + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -4912,6 +5064,10 @@ packages: engines: {node: '>=8'} dev: true + /slug@6.1.0: + resolution: {integrity: sha512-x6vLHCMasg4DR2LPiyFGI0gJJhywY6DTiGhCrOMzb3SOk/0JVLIaL4UhyFSHu04SD3uAavrKY/K3zZ3i6iRcgA==} + dev: false + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -5096,7 +5252,14 @@ packages: engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: true + + /supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: false /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -5151,6 +5314,14 @@ packages: engines: {node: '>=6'} dev: true + /terminal-link@3.0.0: + resolution: {integrity: sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==} + engines: {node: '>=12'} + dependencies: + ansi-escapes: 5.0.0 + supports-hyperlinks: 2.3.0 + dev: false + /text-extensions@2.4.0: resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} engines: {node: '>=8'} @@ -5209,6 +5380,10 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + /tsafe@1.6.6: + resolution: {integrity: sha512-gzkapsdbMNwBnTIjgO758GujLCj031IgHK/PKr2mrmkCSJMhSOR5FeOuSxKLMUoYc0vAA4RGEYYbjt/v6afD3g==} + dev: false + /tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: @@ -5249,6 +5424,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: false + /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} engines: {node: '>= 0.4'} @@ -5292,6 +5472,18 @@ packages: engines: {node: '>=14.17'} hasBin: true + /ulid@2.3.0: + resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==} + hasBin: true + dev: false + + /ulidx@2.3.0: + resolution: {integrity: sha512-36piWNqcdp9hKlQewyeehCaALy4lyx3FodsCxHuV6i0YdexSkjDOubwxEVr2yi4kh62L/0MgyrxqG4K+qtovnw==} + engines: {node: '>=16'} + dependencies: + layerr: 2.0.1 + dev: false + /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -5371,6 +5563,11 @@ packages: hasBin: true dev: false + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + dev: false + /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -5452,6 +5649,19 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /ws@8.16.0: + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5492,6 +5702,16 @@ packages: engines: {node: '>=10'} dev: true + /zod-error@1.5.0: + resolution: {integrity: sha512-zzopKZ/skI9iXpqCEPj+iLCKl9b88E43ehcU+sbRoHuwGd9F1IDVGQ70TyO6kmfiRL1g4IXkjsXK+g1gLYl4WQ==} + dependencies: + zod: 3.22.4 + dev: false + + /zod@3.22.3: + resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + dev: false + /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false diff --git a/trigger.ts b/trigger.ts new file mode 100644 index 0000000..9b99e57 --- /dev/null +++ b/trigger.ts @@ -0,0 +1,7 @@ +import { TriggerClient } from "@trigger.dev/sdk"; + +export const client = new TriggerClient({ + id: "testing-bHhV", + apiKey: process.env.TRIGGER_API_KEY, + apiUrl: process.env.TRIGGER_API_URL, +}); From 83cd2a1748977291eeab6bcbb16ecf159f2be551 Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:28:25 +0100 Subject: [PATCH 2/8] created a trigger event to dispatch a remainder job --- lib/github/hooks/issue.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/github/hooks/issue.ts b/lib/github/hooks/issue.ts index 3d3bc5e..de5d1e6 100644 --- a/lib/github/hooks/issue.ts +++ b/lib/github/hooks/issue.ts @@ -9,6 +9,7 @@ import { import { assignUserPoints } from "@/lib/points/service"; import { getRepositoryByGithubId } from "@/lib/repository/service"; import { createUser, getUser, getUserByGithubId } from "@/lib/user/service"; +import { client } from "@/trigger"; import { Webhooks } from "@octokit/webhooks"; import { getOctokitInstance } from "../utils"; @@ -17,6 +18,10 @@ export const onIssueOpened = async (webhooks: Webhooks) => { webhooks.on(EVENT_TRIGGERS.ISSUE_OPENED, async (context) => { const projectId = context.payload.repository.id; + //TODO: + //1. check if the issue has the oss label + //2. if it has the OSS label find all the users that are currently subscribed to the repo and have the right points, then send them an email + // const isProjectRegistered = await getProject(projectId) // if (!isProjectRegistered) { // await context.octokit.issues.createComment( @@ -102,6 +107,18 @@ export const onAssignCommented = async (webhooks: Webhooks) => { issue_number: issueNumber, assignees: [commenter], }); + + //send trigger event to wait for 36hrs then send a reminder if the user has not created a pull request + await client.sendEvent({ + name: "issue.remainder", + payload: { + issueNumber, + repo, + owner, + commenter, + installationId: context.payload.installation?.id, + }, + }); await octokit.issues.createComment({ owner, repo, From 7c186a5531667f7c1e63ead12c5cba02482f6c4f Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:29:00 +0100 Subject: [PATCH 3/8] converted private key to PKCS#8 format --- lib/github/utils.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/github/utils.ts b/lib/github/utils.ts index 1c902d1..d2a3bd2 100644 --- a/lib/github/utils.ts +++ b/lib/github/utils.ts @@ -1,5 +1,6 @@ import { createAppAuth } from "@octokit/auth-app"; import { Octokit } from "@octokit/rest"; +import crypto from "node:crypto"; import { GITHUB_APP_CLIENT_ID, @@ -13,11 +14,19 @@ export const getOctokitInstance = (installationId: number) => { throw new Error("No installation id provided"); } + //Converting PKCS#1 to PKCS#8 + //For it to work trigger it has to be in PKCS#8 format + + const privateKeyPkcs8 = crypto.createPrivateKey(GITHUB_APP_PRIVATE_KEY).export({ + type: "pkcs8", + format: "pem", + }); + const octokit = new Octokit({ authStrategy: createAppAuth, auth: { appId: GITHUB_APP_ID!, - privateKey: GITHUB_APP_PRIVATE_KEY!, + privateKey: privateKeyPkcs8!, installationId, }, }); From dd26345941e1110bec3c727796c437c1b4b1b4e1 Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:52:53 +0100 Subject: [PATCH 4/8] updated trigger credential in env.example file --- .env.example | 5 +++++ env.mjs | 3 +++ 2 files changed, 8 insertions(+) diff --git a/.env.example b/.env.example index 9723a23..8199214 100644 --- a/.env.example +++ b/.env.example @@ -41,3 +41,8 @@ GITHUB_APP_PRIVATE_KEY="" # GitHub App Name in your App's Installation URL (https://github.com/apps/${GITHUB_APP_SLUG}/installations/new) GITHUB_APP_SLUG= + +#Trigger API credential URL(https://trigger.dev/docs/documentation/introduction) +TRIGGER_API_KEY= +TRIGGER_API_URL= +NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY= \ No newline at end of file diff --git a/env.mjs b/env.mjs index 1769d1d..96bd730 100644 --- a/env.mjs +++ b/env.mjs @@ -21,9 +21,12 @@ export const env = createEnv({ GITHUB_APP_PRIVATE_KEY: z.string().min(1).optional(), GITHUB_APP_SLUG: z.string().min(1), GITHUB_APP_ACCESS_TOKEN: z.string().min(1), + TRIGGER_API_KEY: z.string().min(1), + TRIGGER_API_URL: z.string().min(1), }, client: { NEXT_PUBLIC_APP_URL: z.string().min(1), + NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY: z.string().min(1).optional(), }, runtimeEnv: { NEXTAUTH_URL: process.env.NEXTAUTH_URL, From 755131e580664d44f00cb642c1e984176b34d1da Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:32:32 +0100 Subject: [PATCH 5/8] refactor - added requested changes --- app/api/trigger/route.ts | 4 ++-- env.mjs | 3 +++ jobs/issueReminder.ts | 27 +++++++++++++++++++-------- lib/constants.ts | 4 ++++ lib/github/hooks/issue.ts | 8 ++++---- trigger.ts | 7 ++++--- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/app/api/trigger/route.ts b/app/api/trigger/route.ts index 304646e..67a3caf 100644 --- a/app/api/trigger/route.ts +++ b/app/api/trigger/route.ts @@ -1,10 +1,10 @@ import { createAppRoute } from "@trigger.dev/nextjs"; -import { client } from "@/trigger"; +import { triggerDotDevClient } from "@/trigger"; import "@/jobs"; //this route is used to send and receive data with Trigger.dev -export const { POST, dynamic } = createAppRoute(client); +export const { POST, dynamic } = createAppRoute(triggerDotDevClient); //uncomment this to set a higher max duration (it must be inside your plan limits). Full docs: https://vercel.com/docs/functions/serverless-functions/runtimes#max-duration //export const maxDuration = 60; \ No newline at end of file diff --git a/env.mjs b/env.mjs index 96bd730..dd35a5d 100644 --- a/env.mjs +++ b/env.mjs @@ -46,5 +46,8 @@ export const env = createEnv({ GITHUB_APP_PRIVATE_KEY: process.env.GITHUB_APP_PRIVATE_KEY, GITHUB_APP_SLUG: process.env.GITHUB_APP_SLUG, GITHUB_APP_ACCESS_TOKEN: process.env.GITHUB_APP_ACCESS_TOKEN, + TRIGGER_API_KEY: process.env.TRIGGER_API_KEY, + TRIGGER_API_URL: process.env.TRIGGER_API_URL, + NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY: process.env.NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY, }, }); diff --git a/jobs/issueReminder.ts b/jobs/issueReminder.ts index 25eb172..e185d7b 100644 --- a/jobs/issueReminder.ts +++ b/jobs/issueReminder.ts @@ -1,16 +1,27 @@ import { getOctokitInstance } from "@/lib/github/utils"; -import { client } from "@/trigger"; +import { triggerDotDevClient } from "@/trigger"; import { eventTrigger } from "@trigger.dev/sdk"; import { z } from "zod"; -client.defineJob({ + +//TODO: This doesn't look so good rightnow. + +// 1. create a waitUntil function to wait for an instance when a pull request is created(would need to listen for a pullrequest webhook) for the issue by the commenter + +// 2. if no pull request is created after 36hrs(this would be the timeout of the waitUntil function), which is the time out send a reminder(this should be a task!) + +// 3. io.wait(12hrs), another task to check if a pull request has been created, if not, send a comment to the issue that the commenter has been unassigned from the issue and anyone can take it up. + +// Extract the pull request checker into it's own function for DRY purposes + +triggerDotDevClient.defineJob({ // This is the unique identifier for your Job, it must be unique across all Jobs in your project. - id: "issue-remainder-job", - name: "issue remainder job", + id: "issue-reminder-job", + name: "issue reminder job", version: "0.0.1", // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction trigger: eventTrigger({ - name: "issue.remainder", + name: "issue.reminder", schema: z.object({ issueNumber: z.number(), repo: z.string(), @@ -27,7 +38,7 @@ client.defineJob({ //wait for 36hrs await io.wait("waiting for 36hrs",36 * 60 * 60); - //make this a task so that it can return the completed value from the prev run + //made this a task so it can return the completed value from the prev run await io.runTask("pull-request-checker", async () => { const { data: issue } = await octokit.issues.get({ owner: owner, @@ -39,7 +50,7 @@ client.defineJob({ io.logger.info("pull request has been created for the issue after 36hrs"); return; } else { - //send a comment remainder to the issue + //send a comment reminder to the issue io.logger.info("pull request has not been created for the issue after 36hrs, sending a reminder"); await octokit.issues.createComment({ owner, @@ -80,4 +91,4 @@ client.defineJob({ }); }, -}); +}); \ No newline at end of file diff --git a/lib/constants.ts b/lib/constants.ts index e533c3f..2ca65a7 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -29,3 +29,7 @@ export const GITHUB_APP_SLUG = env.GITHUB_APP_SLUG as string; export const GITHUB_APP_ACCESS_TOKEN = env.GITHUB_APP_ACCESS_TOKEN as string; export const OSS_GG_LABEL = "🕹️ oss.gg" as const; + +// Trigger.dev +export const TRIGGER_API_KEY = env.TRIGGER_API_KEY as string; +export const TRIGGER_API_URL = env.TRIGGER_API_URL as string; diff --git a/lib/github/hooks/issue.ts b/lib/github/hooks/issue.ts index de5d1e6..0ab1cd8 100644 --- a/lib/github/hooks/issue.ts +++ b/lib/github/hooks/issue.ts @@ -9,7 +9,7 @@ import { import { assignUserPoints } from "@/lib/points/service"; import { getRepositoryByGithubId } from "@/lib/repository/service"; import { createUser, getUser, getUserByGithubId } from "@/lib/user/service"; -import { client } from "@/trigger"; +import { triggerDotDevClient } from "@/trigger"; import { Webhooks } from "@octokit/webhooks"; import { getOctokitInstance } from "../utils"; @@ -20,7 +20,7 @@ export const onIssueOpened = async (webhooks: Webhooks) => { //TODO: //1. check if the issue has the oss label - //2. if it has the OSS label find all the users that are currently subscribed to the repo and have the right points, then send them an email + //2. if it has the OSS label find all the users that are currently subscribed to the repo, have the right points/permission, then send them an email // const isProjectRegistered = await getProject(projectId) // if (!isProjectRegistered) { @@ -109,8 +109,8 @@ export const onAssignCommented = async (webhooks: Webhooks) => { }); //send trigger event to wait for 36hrs then send a reminder if the user has not created a pull request - await client.sendEvent({ - name: "issue.remainder", + await triggerDotDevClient.sendEvent({ + name: "issue.reminder", payload: { issueNumber, repo, diff --git a/trigger.ts b/trigger.ts index 9b99e57..5c9d4e4 100644 --- a/trigger.ts +++ b/trigger.ts @@ -1,7 +1,8 @@ import { TriggerClient } from "@trigger.dev/sdk"; +import { TRIGGER_API_KEY, TRIGGER_API_URL } from "@/lib/constants"; -export const client = new TriggerClient({ +export const triggerDotDevClient = new TriggerClient({ id: "testing-bHhV", - apiKey: process.env.TRIGGER_API_KEY, - apiUrl: process.env.TRIGGER_API_URL, + apiKey: TRIGGER_API_KEY, + apiUrl: TRIGGER_API_URL, }); From d62be6bfe3b7fd634cd7852eab6cdc0031db23d5 Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Sun, 24 Mar 2024 12:56:09 +0100 Subject: [PATCH 6/8] refactored the issue reminder code --- .env.example | 3 +- env.mjs | 2 - jobs/issueReminder.ts | 117 +++++++++++++++++++++++++----------------- 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/.env.example b/.env.example index 8199214..dd35c34 100644 --- a/.env.example +++ b/.env.example @@ -44,5 +44,4 @@ GITHUB_APP_SLUG= #Trigger API credential URL(https://trigger.dev/docs/documentation/introduction) TRIGGER_API_KEY= -TRIGGER_API_URL= -NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY= \ No newline at end of file +TRIGGER_API_URL= \ No newline at end of file diff --git a/env.mjs b/env.mjs index dd35a5d..7d0b9c8 100644 --- a/env.mjs +++ b/env.mjs @@ -26,7 +26,6 @@ export const env = createEnv({ }, client: { NEXT_PUBLIC_APP_URL: z.string().min(1), - NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY: z.string().min(1).optional(), }, runtimeEnv: { NEXTAUTH_URL: process.env.NEXTAUTH_URL, @@ -48,6 +47,5 @@ export const env = createEnv({ GITHUB_APP_ACCESS_TOKEN: process.env.GITHUB_APP_ACCESS_TOKEN, TRIGGER_API_KEY: process.env.TRIGGER_API_KEY, TRIGGER_API_URL: process.env.TRIGGER_API_URL, - NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY: process.env.NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY, }, }); diff --git a/jobs/issueReminder.ts b/jobs/issueReminder.ts index e185d7b..e260ddf 100644 --- a/jobs/issueReminder.ts +++ b/jobs/issueReminder.ts @@ -1,18 +1,32 @@ -import { getOctokitInstance } from "@/lib/github/utils"; +import { extractIssueNumbers, getOctokitInstance } from "@/lib/github/utils"; import { triggerDotDevClient } from "@/trigger"; +import { Octokit } from "@octokit/rest"; import { eventTrigger } from "@trigger.dev/sdk"; import { z } from "zod"; +const findPullRequestByIssueAndCommenter = async ( + octokit: Octokit, + owner: string, + repo: string, + issueNumber: number, + commenter: string +) => { + const { data: pullRequests } = await octokit.pulls.list({ + owner, + repo, + state: "open", + }); + const pullRequest = pullRequests.find(async (pr) => { + const openedBy = pr.user?.login; + const prBody = pr.body; + const prIssueNumber = extractIssueNumbers(prBody!); -//TODO: This doesn't look so good rightnow. + // Return the PR that matches the issue number and belongs to the commenter + return prIssueNumber.includes(issueNumber) && openedBy === commenter; + }); -// 1. create a waitUntil function to wait for an instance when a pull request is created(would need to listen for a pullrequest webhook) for the issue by the commenter - -// 2. if no pull request is created after 36hrs(this would be the timeout of the waitUntil function), which is the time out send a reminder(this should be a task!) - -// 3. io.wait(12hrs), another task to check if a pull request has been created, if not, send a comment to the issue that the commenter has been unassigned from the issue and anyone can take it up. - -// Extract the pull request checker into it's own function for DRY purposes + return pullRequest; +}; triggerDotDevClient.defineJob({ // This is the unique identifier for your Job, it must be unique across all Jobs in your project. @@ -32,23 +46,24 @@ triggerDotDevClient.defineJob({ }), run: async (payload, io, ctx) => { const { issueNumber, repo, owner, commenter, installationId } = payload; - const octokit = getOctokitInstance(installationId); //wait for 36hrs - await io.wait("waiting for 36hrs",36 * 60 * 60); + await io.wait("waiting for 36hrs", 36 * 60 * 60); - //made this a task so it can return the completed value from the prev run - await io.runTask("pull-request-checker", async () => { - const { data: issue } = await octokit.issues.get({ - owner: owner, - repo: repo, - issue_number: issueNumber, - }); + //made this a task so it doesn't get replayed + const taskValue = await io.runTask("36-hrs", async () => { + const pullRequest = await findPullRequestByIssueAndCommenter( + octokit, + owner, + repo, + issueNumber, + commenter + ); - if (issue.pull_request) { + if (!!pullRequest) { io.logger.info("pull request has been created for the issue after 36hrs"); - return; + return { completed: true }; } else { //send a comment reminder to the issue io.logger.info("pull request has not been created for the issue after 36hrs, sending a reminder"); @@ -58,37 +73,43 @@ triggerDotDevClient.defineJob({ issue_number: issueNumber, body: ` @${commenter}, You have 12hrs left to create a pull request for this issue. `, }); + return { completed: false }; } }); - await io.wait("waiting for 12hrs",12 * 60 * 60); + if (taskValue?.completed) { + return; + } else { + await io.wait("waiting for 12hrs", 12 * 60 * 60); - await io.runTask("pull-request-checker-after-12hrs", async () => { - const { data: issue } = await octokit.issues.get({ - owner: owner, - repo: repo, - issue_number: issueNumber, - }); - - if (issue.pull_request) { - io.logger.info("pull request has been created for the issue after 12hrs"); - return - } else { - io.logger.info("pull request has not been created for the issue after 12hrs"); - await octokit.issues.createComment({ - owner: owner, - repo: repo, - issue_number: issueNumber, - body: `@${commenter} has been unassigned from the issue, anyone can now take it up.`, - }); - await octokit.issues.removeAssignees({ - owner: owner, - repo: repo, - issue_number: issueNumber, - assignees: [commenter], - }); - } - }); + await io.runTask("48-hrs", async () => { + const pullRequest = await findPullRequestByIssueAndCommenter( + octokit, + owner, + repo, + issueNumber, + commenter + ); + if (!!pullRequest) { + io.logger.info("pull request has been created for the issue within 48hrs"); + return; + } else { + io.logger.info("pull request has not been created for the issue after 12hrs"); + await octokit.issues.createComment({ + owner: owner, + repo: repo, + issue_number: issueNumber, + body: `@${commenter} has been unassigned from the issue, anyone can now take it up.`, + }); + await octokit.issues.removeAssignees({ + owner: owner, + repo: repo, + issue_number: issueNumber, + assignees: [commenter], + }); + } + }); + } }, -}); \ No newline at end of file +}); From 5bc87ed6a59bcac24c0bced24c1550624bb98e79 Mon Sep 17 00:00:00 2001 From: Chigala <92148630+Chigala@users.noreply.github.com> Date: Sun, 24 Mar 2024 12:56:54 +0100 Subject: [PATCH 7/8] added pull_request_open webhook --- lib/constants.ts | 7 +++++-- lib/github/hooks/issue.ts | 12 +++++++++++- lib/github/index.ts | 9 ++++++++- lib/github/utils.ts | 10 ++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index 2ca65a7..b9fa8ba 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,5 +1,6 @@ import { env } from "../env.mjs"; + export const DEFAULT_CACHE_REVALIDATION_INTERVAL = 60 * 30; // 30 minutes export const GITHUB_CACHE_REVALIDATION_INTERVAL = 60 * 60 * 24; // 24 hours @@ -15,6 +16,7 @@ export enum EVENT_TRIGGERS { ISSUE_OPENED = "issues.opened", INSTALLATION_CREATED = "installation.created", ISSUE_COMMENTED = "issue_comment.created", + PULL_REQUEST_OPENED = "pull_request.opened" } export const AWARD_POINTS_IDENTIFIER = "/award" as const; @@ -28,8 +30,9 @@ export const GITHUB_APP_WEBHOOK_SECRET = env.GITHUB_APP_WEBHOOK_SECRET as string export const GITHUB_APP_SLUG = env.GITHUB_APP_SLUG as string; export const GITHUB_APP_ACCESS_TOKEN = env.GITHUB_APP_ACCESS_TOKEN as string; -export const OSS_GG_LABEL = "🕹️ oss.gg" as const; +// export const OSS_GG_LABEL = "🕹️ oss.gg" as const; +export const OSS_GG_LABEL = ":joystick: oss.gg" as const; // Trigger.dev export const TRIGGER_API_KEY = env.TRIGGER_API_KEY as string; -export const TRIGGER_API_URL = env.TRIGGER_API_URL as string; +export const TRIGGER_API_URL = env.TRIGGER_API_URL as string; \ No newline at end of file diff --git a/lib/github/hooks/issue.ts b/lib/github/hooks/issue.ts index 0ab1cd8..354e41b 100644 --- a/lib/github/hooks/issue.ts +++ b/lib/github/hooks/issue.ts @@ -12,7 +12,7 @@ import { createUser, getUser, getUserByGithubId } from "@/lib/user/service"; import { triggerDotDevClient } from "@/trigger"; import { Webhooks } from "@octokit/webhooks"; -import { getOctokitInstance } from "../utils"; +import { extractIssueNumbers, getOctokitInstance } from "../utils"; export const onIssueOpened = async (webhooks: Webhooks) => { webhooks.on(EVENT_TRIGGERS.ISSUE_OPENED, async (context) => { @@ -119,6 +119,7 @@ export const onAssignCommented = async (webhooks: Webhooks) => { installationId: context.payload.installation?.id, }, }); + await octokit.issues.createComment({ owner, repo, @@ -297,3 +298,12 @@ export const onAwardPoints = async (webhooks: Webhooks) => { } }); }; + +export const onPullRequestOpened = async (webhooks: Webhooks) => { + webhooks.on(EVENT_TRIGGERS.PULL_REQUEST_OPENED, async (context) => { + const pullRequestUser = context.payload.pull_request.user; + const body = context.payload.pull_request.body; + const issueNumber = extractIssueNumbers(body!); + // create a comment on the issue that a PR has been opened + }); +}; diff --git a/lib/github/index.ts b/lib/github/index.ts index 8cd3314..6dd3e11 100644 --- a/lib/github/index.ts +++ b/lib/github/index.ts @@ -2,7 +2,13 @@ import { Webhooks, createNodeMiddleware } from "@octokit/webhooks"; import { GITHUB_APP_WEBHOOK_SECRET } from "../constants"; import { onInstallationCreated } from "./hooks/installation"; -import { onAssignCommented, onAwardPoints, onIssueOpened, onUnassignCommented } from "./hooks/issue"; +import { + onAssignCommented, + onAwardPoints, + onIssueOpened, + onPullRequestOpened, + onUnassignCommented, +} from "./hooks/issue"; const webhooks = new Webhooks({ secret: GITHUB_APP_WEBHOOK_SECRET, @@ -18,4 +24,5 @@ export const registerHooks = async () => { onAssignCommented(webhooks); onUnassignCommented(webhooks); onAwardPoints(webhooks); + onPullRequestOpened(webhooks); }; diff --git a/lib/github/utils.ts b/lib/github/utils.ts index d2a3bd2..e58d1a1 100644 --- a/lib/github/utils.ts +++ b/lib/github/utils.ts @@ -33,3 +33,13 @@ export const getOctokitInstance = (installationId: number) => { return octokit; }; + +export const extractIssueNumbers = (body: string): number[] => { + const regex = /#(\d+)/g; + const matches = body.match(regex); + if (matches) { + return matches.map((match) => parseInt(match.substring(1))); + } else { + return []; + } +}; From 0e50352adf55ce607de2b04aa0b91a0a04563563 Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Mon, 1 Apr 2024 15:10:11 +0530 Subject: [PATCH 8/8] revert: constant var chagne for ossgg label --- lib/constants.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index b9fa8ba..33d467c 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,6 +1,5 @@ import { env } from "../env.mjs"; - export const DEFAULT_CACHE_REVALIDATION_INTERVAL = 60 * 30; // 30 minutes export const GITHUB_CACHE_REVALIDATION_INTERVAL = 60 * 60 * 24; // 24 hours @@ -16,7 +15,7 @@ export enum EVENT_TRIGGERS { ISSUE_OPENED = "issues.opened", INSTALLATION_CREATED = "installation.created", ISSUE_COMMENTED = "issue_comment.created", - PULL_REQUEST_OPENED = "pull_request.opened" + PULL_REQUEST_OPENED = "pull_request.opened", } export const AWARD_POINTS_IDENTIFIER = "/award" as const; @@ -30,9 +29,8 @@ export const GITHUB_APP_WEBHOOK_SECRET = env.GITHUB_APP_WEBHOOK_SECRET as string export const GITHUB_APP_SLUG = env.GITHUB_APP_SLUG as string; export const GITHUB_APP_ACCESS_TOKEN = env.GITHUB_APP_ACCESS_TOKEN as string; -// export const OSS_GG_LABEL = "🕹️ oss.gg" as const; -export const OSS_GG_LABEL = ":joystick: oss.gg" as const; +export const OSS_GG_LABEL = "🕹️ oss.gg" as const; // Trigger.dev export const TRIGGER_API_KEY = env.TRIGGER_API_KEY as string; -export const TRIGGER_API_URL = env.TRIGGER_API_URL as string; \ No newline at end of file +export const TRIGGER_API_URL = env.TRIGGER_API_URL as string;