From 735eaaac2a1899b09188d55839dba8bf657b0c08 Mon Sep 17 00:00:00 2001 From: Sam Vevang Date: Tue, 7 Jul 2026 14:02:17 -0500 Subject: [PATCH] Add pull requests --- README.md | 2 +- src/webhook-endpoint/index.mjs | 99 +++++++++++++++++++--------------- template.yml | 3 +- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 3185d7c..c5fb3a5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # GitHub Toolkit -A [GitHub App](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) that could do a variety of things, but currently adds all new issues created in the GitHub organization to some specific project. +A [GitHub App](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) that could do a variety of things, but currently adds all new issues and pull requests created in the GitHub organization to some specific project. diff --git a/src/webhook-endpoint/index.mjs b/src/webhook-endpoint/index.mjs index 54fd6f1..a1c1d4d 100644 --- a/src/webhook-endpoint/index.mjs +++ b/src/webhook-endpoint/index.mjs @@ -3,55 +3,65 @@ import { App } from "octokit"; const OK_RESPONSE = { statusCode: 200 }; -async function handleIssue(payload) { - console.log(JSON.stringify(payload)); - if (payload.action === "opened" && payload.issue.state === "open") { - const app = new App({ - appId: 311508, - // If the envar is added directly to the Lambda function it will - // probably look like: - // -----BEGIN RSA PRIVATE KEY-----\nMIIEo… - // with the newlines replaced with literal "\n". - // Those will be replaced with real newlines below. - // If the envar is added via CloudFormation or AWS SAM, it will - // maintain actual newlines and the `replace` will be a no-op. - // When generating a private key for a GitHub app, it will download a - // .pem file. The contents of that file is the private key. - privateKey: process.env.GITHUB_APP_PRIVATE_KEY.replace(/\\n/g, "\n"), - }); +async function addToProject(installationId, contentId) { + const app = new App({ + appId: 311508, + // If the envar is added directly to the Lambda function it will + // probably look like: + // -----BEGIN RSA PRIVATE KEY-----\nMIIEo… + // with the newlines replaced with literal "\n". + // Those will be replaced with real newlines below. + // If the envar is added via CloudFormation or AWS SAM, it will + // maintain actual newlines and the `replace` will be a no-op. + // When generating a private key for a GitHub app, it will download a + // .pem file. The contents of that file is the private key. + privateKey: process.env.GITHUB_APP_PRIVATE_KEY.replace(/\\n/g, "\n"), + }); - const octokit = await app.getInstallationOctokit(payload.installation.id); + const octokit = await app.getInstallationOctokit(installationId); - const projectOwnerName = "PRX"; - const projectNumber = 3; - const ownerType = "organization"; + const projectOwnerName = "PRX"; + const projectNumber = 3; + const ownerType = "organization"; - const idResp = await octokit.graphql( - `query getProject($projectOwnerName: String!, $projectNumber: Int!) { - ${ownerType}(login: $projectOwnerName) { - projectV2(number: $projectNumber) { - id - } + const idResp = await octokit.graphql( + `query getProject($projectOwnerName: String!, $projectNumber: Int!) { + ${ownerType}(login: $projectOwnerName) { + projectV2(number: $projectNumber) { + id } - }`, - { - projectOwnerName, - projectNumber, - }, - ); + } + }`, + { + projectOwnerName, + projectNumber, + }, + ); - const projectId = idResp[ownerType]?.projectV2.id; - const contentId = payload.issue.node_id; + const projectId = idResp[ownerType]?.projectV2.id; - await octokit.graphql( - `mutation addIssueToProject { - addProjectV2ItemById( - input: {projectId: "${projectId}", contentId: "${contentId}"} - ) { - clientMutationId - } - }`, - ); + await octokit.graphql( + `mutation addItemToProject { + addProjectV2ItemById( + input: {projectId: "${projectId}", contentId: "${contentId}"} + ) { + clientMutationId + } + }`, + ); +} + +async function handleIssue(payload) { + console.log(JSON.stringify(payload)); + if (payload.action === "opened" && payload.issue.state === "open") { + await addToProject(payload.installation.id, payload.issue.node_id); + } +} + +async function handlePullRequest(payload) { + console.log(JSON.stringify(payload)); + if (payload.action === "opened" && payload.pull_request.state === "open") { + await addToProject(payload.installation.id, payload.pull_request.node_id); } } @@ -78,6 +88,9 @@ export const handler = async (event) => { case "issues": await handleIssue(JSON.parse(body)); break; + case "pull_request": + await handlePullRequest(JSON.parse(body)); + break; default: break; } diff --git a/template.yml b/template.yml index c82b71c..526fffc 100644 --- a/template.yml +++ b/template.yml @@ -35,7 +35,8 @@ Resources: Architectures: [arm64] CodeUri: src/webhook-endpoint Description: >- - Receives GitHub webhooks for issues and performs some actions + Receives GitHub webhooks for issues and pull requests and performs + some actions Environment: Variables: GITHUB_WEBHOOK_SECRET: !Ref GitHubWebhookSecret