@@ -2,6 +2,14 @@ name: PR Checklist
22on :
33 pull_request_target :
44 types : [opened, reopened, ready_for_review, synchronize]
5+ issue_comment :
6+ types : [created, edited]
7+ workflow_dispatch :
8+ inputs :
9+ pr_number :
10+ description : ' PR number to check'
11+ required : true
12+ type : string
513
614permissions :
715 pull-requests : write
@@ -10,34 +18,65 @@ permissions:
1018jobs :
1119 checklist :
1220 runs-on : ubuntu-latest
13- if : github.event.pull_request.draft == false
21+ if : github.event_name == 'workflow_dispatch' || github. event.pull_request.draft == false || github.event.issue.pull_request
1422 steps :
1523 - name : Manage PR Checklist
1624 uses : actions/github-script@v7
1725 with :
1826 github-token : ${{ secrets.GITHUB_TOKEN }}
1927 script : |
20- const pr = context.payload.pull_request;
21- const checklistBody = `## 🚀 PR Checklist
28+ // Get PR information based on event type
29+ let pr, prNumber;
30+ if (context.eventName === 'pull_request_target') {
31+ pr = context.payload.pull_request;
32+ prNumber = pr.number;
33+ } else if (context.eventName === 'issue_comment') {
34+ // For issue_comment events, get PR info from the issue
35+ if (!context.payload.issue.pull_request) {
36+ console.log('Comment is not on a PR, skipping');
37+ return;
38+ }
39+ prNumber = context.payload.issue.number;
40+ const { data: prData } = await github.rest.pulls.get({
41+ owner: context.repo.owner,
42+ repo: context.repo.repo,
43+ pull_number: prNumber
44+ });
45+ pr = prData;
46+ } else if (context.eventName === 'workflow_dispatch') {
47+ // For manual dispatch, get PR info from input
48+ prNumber = parseInt(context.payload.inputs.pr_number);
49+ const { data: prData } = await github.rest.pulls.get({
50+ owner: context.repo.owner,
51+ repo: context.repo.repo,
52+ pull_number: prNumber
53+ });
54+ pr = prData;
55+ } else {
56+ console.log('Unexpected event type:', context.eventName);
57+ return;
58+ }
2259
23- Please review all applicable items before requesting a review:
60+ console.log(`Processing PR #${prNumber}`);
2461
25- - [ ] PR title follows format: \`[JIRA/Issue][type] Description\`
62+ const checklistBody = `## 🚀 PR Checklist
63+
64+ - [ ] PR title follows format: \`[type] Description\`
2665 - [ ] PR description explains both **what** you're doing and **why**
2766 - [ ] Code conforms to coding conventions (see \`CODING_GUIDELINES.md\`)
28- - [ ] Inputs validated and possible nullptr dereferences checked
2967 - [ ] Test cases added for new code
3068 - [ ] All existing tests pass
3169 - [ ] PR and commit messages cleaned up via \`git rebase -i\`
3270
3371 ---
34- **Please check the items and react with 👍 to acknowledge you've reviewed the checklist.**`;
72+ **Please ✅ check the below item to confirm you've reviewed the checklist when ready for review!.**
73+ - [ ] **I have reviewed the above checklist and addressed all applicable items**`;
3574
3675 // Get all comments
3776 const { data: comments } = await github.rest.issues.listComments({
3877 owner: context.repo.owner,
3978 repo: context.repo.repo,
40- issue_number: pr.number
79+ issue_number: prNumber
4180 });
4281
4382 // Find checklist comment
@@ -47,11 +86,13 @@ jobs:
4786 );
4887
4988 // Post checklist if not exists
50- if (!checklistComment && ['opened', 'reopened', 'ready_for_review'].includes(context.payload.action)) {
89+ if (!checklistComment &&
90+ (context.eventName === 'workflow_dispatch' ||
91+ ['opened', 'reopened', 'ready_for_review'].includes(context.payload.action))) {
5192 const { data: newComment } = await github.rest.issues.createComment({
5293 owner: context.repo.owner,
5394 repo: context.repo.repo,
54- issue_number: pr.number ,
95+ issue_number: prNumber ,
5596 body: checklistBody
5697 });
5798 checklistComment = newComment;
@@ -63,26 +104,70 @@ jobs:
63104 return;
64105 }
65106
66- // Check for thumbs up reactions
67- const { data: reactions } = await github.rest.reactions.listForIssueComment({
68- owner: context.repo.owner,
69- repo: context.repo.repo,
70- comment_id: checklistComment.id
71- });
107+ // Parse the checklist comment to count checked items
108+ const checkboxRegex = /- \[([ x])\]/gi;
109+ const matches = [...checklistComment.body.matchAll(checkboxRegex)];
110+ const totalItems = matches.length;
111+ const checkedItems = matches.filter(match => match[1].toLowerCase() === 'x').length;
112+
113+ console.log(`Checklist status: ${checkedItems}/${totalItems} items checked`);
72114
73- const hasThumbsUp = reactions.some(reaction => reaction.content === '+1');
115+ // Check if the acknowledgment checkbox (last one) is checked
116+ const lastCheckbox = matches[matches.length - 1];
117+ const isAcknowledged = lastCheckbox && lastCheckbox[1].toLowerCase() === 'x';
74118
75- // Update commit status (using plain text to avoid Unicode issues)
119+ // Determine status based on checked items
120+ let state, description;
121+ if (!isAcknowledged) {
122+ state = 'pending';
123+ description = `Please acknowledge the checklist`;
124+ } else {
125+ state = 'success';
126+ description = `Checklist acknowledged`;
127+ }
128+
129+ // Update commit status
76130 await github.rest.repos.createCommitStatus({
77131 owner: context.repo.owner,
78132 repo: context.repo.repo,
79133 sha: pr.head.sha,
80- state: hasThumbsUp ? 'success' : 'pending' ,
134+ state: state ,
81135 context: 'PR Checklist',
82- description: hasThumbsUp
83- ? 'Checklist acknowledged'
84- : 'Please acknowledge the checklist with thumbs up',
136+ description: description,
85137 target_url: checklistComment.html_url
86138 });
87139
88- console.log(`Status: ${hasThumbsUp ? 'success' : 'pending'}`);
140+ console.log(`Status: ${state} - ${description}`);
141+
142+ // Add a helpful label based on checklist status
143+ const labels = {
144+ complete: 'checklist-complete',
145+ incomplete: 'checklist-incomplete'
146+ };
147+
148+ try {
149+ // Remove both labels first
150+ for (const label of Object.values(labels)) {
151+ try {
152+ await github.rest.issues.removeLabel({
153+ owner: context.repo.owner,
154+ repo: context.repo.repo,
155+ issue_number: prNumber,
156+ name: label
157+ });
158+ } catch (e) {
159+ // Label might not exist, that's ok
160+ }
161+ }
162+
163+ // Add appropriate label
164+ const labelToAdd = isAcknowledged ? labels.complete : labels.incomplete;
165+ await github.rest.issues.addLabels({
166+ owner: context.repo.owner,
167+ repo: context.repo.repo,
168+ issue_number: prNumber,
169+ labels: [labelToAdd]
170+ });
171+ } catch (e) {
172+ console.log('Could not update labels:', e.message);
173+ }
0 commit comments