Skip to content

Commit ba5d7fe

Browse files
authored
feat: Add Issue Link Checking to PR Helper Bot (#1201)
Signed-off-by: Rob Walworth <robert.walworth@swirldslabs.com>
1 parent 0d11f2a commit ba5d7fe

22 files changed

+3903
-1180
lines changed

.github/scripts/bot-on-commit.js

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

.github/scripts/bot-on-pr-open.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
//
3+
// bot-on-pr-open.js
4+
//
5+
// Runs when a PR is opened, reopened, or converted from draft (ready_for_review).
6+
// Performs all 4 checks (DCO, GPG, merge conflict, issue link), posts/updates
7+
// the unified dashboard comment, auto-assigns the author, and applies the
8+
// appropriate status label.
9+
10+
const {
11+
createLogger,
12+
buildBotContext,
13+
addAssignees,
14+
requireSafeUsername,
15+
runAllChecksAndComment,
16+
swapStatusLabel,
17+
} = require('./helpers');
18+
19+
const logger = createLogger('on-pr-open');
20+
21+
/**
22+
* Auto-assigns the PR author if not already assigned.
23+
* @param {object} botContext
24+
*/
25+
async function autoAssignAuthor(botContext) {
26+
const prAuthor = botContext.pr?.user?.login;
27+
if (!prAuthor) {
28+
logger.log('Exit: missing pull request author');
29+
return;
30+
}
31+
try {
32+
requireSafeUsername(prAuthor, 'pr.author');
33+
} catch (err) {
34+
logger.log('Exit: invalid pr.author', err.message);
35+
return;
36+
}
37+
38+
const currentAssignees = botContext.pr?.assignees || [];
39+
const isAlreadyAssigned = currentAssignees.some(
40+
(a) => (a?.login || '').toLowerCase() === prAuthor.toLowerCase()
41+
);
42+
if (isAlreadyAssigned) {
43+
logger.log(`Author ${prAuthor} is already assigned`);
44+
return;
45+
}
46+
await addAssignees(botContext, [prAuthor]);
47+
}
48+
49+
module.exports = async ({ github, context }) => {
50+
try {
51+
const botContext = buildBotContext({ github, context });
52+
53+
await autoAssignAuthor(botContext);
54+
55+
if (botContext.pr?.user?.type === 'Bot') {
56+
logger.log('Skipping bot-authored PR');
57+
return;
58+
}
59+
60+
const { allPassed } = await runAllChecksAndComment(botContext);
61+
await swapStatusLabel(botContext, allPassed, { force: true });
62+
63+
logger.log('On-PR-open bot completed');
64+
} catch (error) {
65+
logger.error('Error:', {
66+
message: error.message,
67+
number: context?.payload?.pull_request?.number,
68+
});
69+
throw error;
70+
}
71+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
//
3+
// bot-on-pr-update.js
4+
//
5+
// Runs on new commits (synchronize) and PR body edits (edited). Performs all
6+
// 4 checks (DCO, GPG, merge conflict, issue link), posts/updates the unified
7+
// dashboard comment, and conditionally swaps the status label.
8+
// For edited events, exits early if only the title or base branch changed.
9+
10+
const {
11+
createLogger,
12+
buildBotContext,
13+
swapStatusLabel,
14+
runAllChecksAndComment,
15+
} = require('./helpers');
16+
17+
const logger = createLogger('on-pr-update');
18+
19+
module.exports = async ({ github, context }) => {
20+
try {
21+
const botContext = buildBotContext({ github, context });
22+
23+
if (botContext.pr?.user?.type === 'Bot') {
24+
logger.log('Skipping bot-authored PR');
25+
return;
26+
}
27+
28+
// Edits can be triggered by title changes, but we only care about body changes.
29+
if (context.payload.action === 'edited' && !context.payload.changes?.body) {
30+
logger.log('Body not changed, skipping');
31+
return;
32+
}
33+
34+
const { allPassed } = await runAllChecksAndComment(botContext);
35+
await swapStatusLabel(botContext, allPassed);
36+
37+
logger.log('On-PR-update bot completed');
38+
} catch (error) {
39+
logger.error('Error:', {
40+
message: error.message,
41+
number: context?.payload?.pull_request?.number,
42+
});
43+
throw error;
44+
}
45+
};

0 commit comments

Comments
 (0)