@@ -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+ }
59+
60+ console.log(`Processing PR #${prNumber}`);
2261
23- Please review all applicable items before requesting a review:
62+ const checklistBody = `## 🚀 PR Checklist
2463
25- - [ ] PR title follows format: \`[JIRA/Issue][ type] Description\`
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,25 +104,71 @@ 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`);
114+
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';
72118
73- const hasThumbsUp = reactions.some(reaction => reaction.content === '+1');
74119
120+ // Determine status based on checked items
121+ let state, description;
122+ if (!isAcknowledged) {
123+ state = 'pending';
124+ description = `Please acknowledge the checklist`;
125+ } else {
126+ state = 'success';
127+ description = `Checklist acknowledged`;
128+ }
129+
130+ // Update commit status
75131 await github.rest.repos.createCommitStatus({
76132 owner: context.repo.owner,
77133 repo: context.repo.repo,
78134 sha: pr.head.sha,
79- state: hasThumbsUp ? 'success' : 'pending' ,
135+ state: state ,
80136 context: 'PR Checklist',
81- description: hasThumbsUp
82- ? 'Checklist acknowledged'
83- : 'Please acknowledge the checklist with thumbs up',
137+ description: description,
84138 target_url: checklistComment.html_url
85139 });
86140
87- console.log(`Status: ${hasThumbsUp ? 'success' : 'pending'}`);
141+ console.log(`Status: ${state} - ${description}`);
142+
143+ // Add a helpful label based on checklist status
144+ const labels = {
145+ complete: 'checklist-complete',
146+ incomplete: 'checklist-incomplete'
147+ };
148+
149+ try {
150+ // Remove both labels first
151+ for (const label of Object.values(labels)) {
152+ try {
153+ await github.rest.issues.removeLabel({
154+ owner: context.repo.owner,
155+ repo: context.repo.repo,
156+ issue_number: prNumber,
157+ name: label
158+ });
159+ } catch (e) {
160+ // Label might not exist, that's ok
161+ }
162+ }
163+
164+ // Add appropriate label
165+ const labelToAdd = isAcknowledged ? labels.complete : labels.incomplete;
166+ await github.rest.issues.addLabels({
167+ owner: context.repo.owner,
168+ repo: context.repo.repo,
169+ issue_number: prNumber,
170+ labels: [labelToAdd]
171+ });
172+ } catch (e) {
173+ console.log('Could not update labels:', e.message);
174+ }
0 commit comments