Skip to content

Commit 40a138d

Browse files
feat: automated cla flow with robust cla requirement check
2 parents 0dc09c0 + 84185b2 commit 40a138d

File tree

15 files changed

+458
-134
lines changed

15 files changed

+458
-134
lines changed

.env.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ APP_ID="11"
22
GITHUB_APP_PRIVATE_KEY_BASE64="base64 encoded private key"
33
PRIVATE_KEY_PATH="very/secure/location/gh_app_key.pem"
44
WEBHOOK_SECRET="secret"
5+
WEBSITE_ADDRESS="https://github.app.home"

app.js

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import dotenv from "dotenv";
22
import fs from "fs";
33
import http from "http";
4+
import url from "url";
45
import { Octokit, App } from "octokit";
56
import { createNodeMiddleware } from "@octokit/webhooks";
6-
import { routes } from "./routes.js";
7+
import { routes } from "./src/routes.js";
8+
import {
9+
getMessage,
10+
isCLARequired,
11+
isMessageAfterMergeRequired,
12+
} from "./src/helpers.js";
713

814
// Load environment variables from .env file
915
dotenv.config();
@@ -26,7 +32,6 @@ const privateKey =
2632
);
2733
const secret = process.env.WEBHOOK_SECRET;
2834
const enterpriseHostname = process.env.ENTERPRISE_HOSTNAME;
29-
const messageForNewPRs = fs.readFileSync("./message.md", "utf8");
3035

3136
// Create an authenticated Octokit client authenticated as a GitHub App
3237
const app = new App({
@@ -54,11 +59,63 @@ app.webhooks.on("pull_request.opened", async ({ octokit, payload }) => {
5459
`Received a pull request event for #${payload.pull_request.number}`,
5560
);
5661
try {
62+
if (!isCLARequired(payload.pull_request)) {
63+
return;
64+
}
65+
// If the user is not a member of the organization and haven't yet signed CLA,
66+
// ask them to sign the CLA
67+
const comment = getMessage("ask-to-sign-cla", {
68+
username: payload.pull_request.user.login,
69+
org: payload.repository.owner.login,
70+
repo: payload.repository.name,
71+
pr_number: payload.pull_request.number,
72+
});
5773
await octokit.rest.issues.createComment({
5874
owner: payload.repository.owner.login,
5975
repo: payload.repository.name,
6076
issue_number: payload.pull_request.number,
61-
body: messageForNewPRs,
77+
body: comment,
78+
});
79+
// Add a label to the PR
80+
octokit.rest.issues.addLabels({
81+
owner: payload.repository.owner.login,
82+
repo: payload.repository.name,
83+
issue_number: payload.pull_request.number,
84+
labels: ["Pending CLA"],
85+
});
86+
} catch (error) {
87+
if (error.response) {
88+
console.error(
89+
`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`,
90+
);
91+
} else {
92+
console.error(error);
93+
}
94+
}
95+
});
96+
97+
app.webhooks.on("pull_request.closed", async ({ octokit, payload }) => {
98+
console.log(
99+
`Closed a pull request event for #${payload.pull_request.number}`,
100+
);
101+
if (!payload.pull_request.merged) return;
102+
console.log(`This PR is merged`);
103+
try {
104+
if (!isMessageAfterMergeRequired()) {
105+
return;
106+
}
107+
console.log(`Going to notify the PR author...`);
108+
const comment = getMessage("message-after-merge", {
109+
username: payload.pull_request.user.login,
110+
org: payload.repository.owner.login,
111+
repo: payload.repository.name,
112+
pr_number: payload.pull_request.number,
113+
});
114+
await octokit.rest.issues.createComment({
115+
owner: payload.repository.owner,
116+
repo: payload.repository.name,
117+
issue_number: payload.pull_request.number,
118+
body: comment,
62119
});
63120
} catch (error) {
64121
if (error.response) {
@@ -72,7 +129,9 @@ app.webhooks.on("pull_request.opened", async ({ octokit, payload }) => {
72129
});
73130

74131
app.webhooks.on("issues.opened", async ({ octokit, payload }) => {
75-
console.log(`Received a new issue event for #${payload.issue.number}`);
132+
console.log(
133+
`Received a new issue event for #${payload.issue.number} by ${pull_request.user.type}: ${pull_request.user.login}`,
134+
);
76135
try {
77136
await octokit.rest.issues.createComment({
78137
owner: payload.repository.owner.login,
@@ -118,15 +177,20 @@ const middleware = createNodeMiddleware(app.webhooks, { path });
118177

119178
http
120179
.createServer((req, res) => {
121-
switch (req.method + " " + req.url) {
180+
const parsedUrl = url.parse(req.url);
181+
const pathWithoutQuery = parsedUrl.pathname;
182+
const queryString = parsedUrl.query;
183+
console.log(req.method + " " + pathWithoutQuery);
184+
if (queryString) console.log(queryString.substring(0, 20) + "...");
185+
switch (req.method + " " + pathWithoutQuery) {
122186
case "GET /":
123187
routes.home(req, res);
124188
break;
125-
case "GET /form":
126-
routes.form(req, res);
189+
case "GET /cla":
190+
routes.cla(req, res);
127191
break;
128-
case "POST /form":
129-
routes.submitForm(req, res);
192+
case "POST /cla":
193+
routes.submitCla(req, res, app);
130194
break;
131195
case "POST /api/webhook":
132196
middleware(req, res);

form.html

Lines changed: 0 additions & 45 deletions
This file was deleted.

helpers.js

Lines changed: 0 additions & 15 deletions
This file was deleted.

home.html

Lines changed: 0 additions & 34 deletions
This file was deleted.

message.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "starter_github_app",
3-
"private": true,
4-
"version": "0.0.1",
2+
"name": "rudder_github_app",
3+
"private": false,
4+
"version": "0.0.2",
55
"type": "module",
66
"scripts": {
77
"lint": "standard",
@@ -15,5 +15,8 @@
1515
"dependencies": {
1616
"dotenv": "^16.0.3",
1717
"octokit": "^3.1.2"
18+
},
19+
"engines": {
20+
"node": ">=20"
1821
}
1922
}

0 commit comments

Comments
 (0)