@@ -2,14 +2,14 @@ name: RFC approval automation
22
33on :
44 issues :
5- types : [opened]
5+ types : [opened, closed ]
66 issue_comment :
77 types : [created, edited]
88
99jobs :
1010 rfc_approval :
11- # Only run for RFC proposal issues that are still open
12- if : startsWith(github.event.issue.title, 'New RFC') && github.event.issue.state == 'open'
11+ # Only run for RFC proposal issues
12+ if : startsWith(github.event.issue.title, 'New RFC')
1313 runs-on : ubuntu-latest
1414
1515 steps :
2222 const org = context.repo.owner;
2323 const repo = context.repo.repo;
2424
25+ // Ignore comments on closed issues
26+ if (context.eventName === 'issue_comment' && context.payload.issue.state === 'closed') {
27+ console.log('Comment event on closed issue, ignoring.');
28+ return;
29+ }
30+
2531 // ---------------------------------------------
2632 // Fetch members of the core team
2733 // ---------------------------------------------
@@ -45,12 +51,21 @@ jobs:
4551 const quorum = Math.ceil(teamMembers.length / 2);
4652 console.log(`Quorum set to ${quorum}.`);
4753
54+ // Helper for list formatting and complete status body
55+ function formatUserList(users) {
56+ return users.length ? users.map(u => `[@${u}](https://github.com/${u})`).join(', ') : '-';
57+ }
58+
59+ function generateStatusBody(status, approvalsSet, rejectionsSet, awaitingArr) {
60+ return `## RFC approval status: ${status}\n\nRFC has approvals from ${approvalsSet.size}/${quorum} required @core-team quorum.\n\nCore team approvers: ${formatUserList([...approvalsSet])}\nRejection from: ${formatUserList([...rejectionsSet])}\nAwaiting approval from: ${formatUserList(awaitingArr)}`;
61+ }
62+
4863 // -------------------------------------------------
4964 // If this workflow was triggered by issue creation
5065 // -------------------------------------------------
5166 if (context.eventName === 'issues' && context.payload.action === 'opened') {
67+ const body = generateStatusBody('🕐 Pending', new Set(), new Set(), teamMembers);
5268 console.log('Creating initial comment for review status');
53- const body = `## RFC approval status: 🕐 Pending\n\nCore team approvers:\nRejection from: -\nAwaiting approval from:`;
5469
5570 await github.rest.issues.createComment({
5671 owner: org,
@@ -62,11 +77,10 @@ jobs:
6277 }
6378
6479 // ---------------------------------------------------------------------
65- // From here on we handle updates triggered by comment creation / edits
80+ // Collect comments and compute votes (shared for comment & closed events)
6681 // ---------------------------------------------------------------------
6782
68- // Collect all comments on the issue (may require pagination)
69- console.log('Fetching issue comments');
83+ // Collect all comments on the issue
7084 const comments = await github.paginate(github.rest.issues.listComments, {
7185 owner: org,
7286 repo,
@@ -97,24 +111,34 @@ jobs:
97111 console.log(`Rejections (${rejections.size}):`, [...rejections]);
98112
99113 const awaiting = teamMembers.filter(u => !approvals.has(u) && !rejections.has(u));
100- const status = approvals.size >= quorum && rejections.size === 0 ? '✅ Approved' : '🕐 Pending';
101114
102- function formatUserList(users) {
103- return users.length ? users.map(u => `[@${u}](https://github.com/${u})`).join(', ') : '-';
115+ // Determine status
116+ let status = '🕐 Pending';
117+
118+ if (context.eventName === 'issues' && context.payload.action === 'closed' && context.payload.issue.state_reason === 'not_planned' && rejections.size > 0) {
119+ status = '❌ Rejected';
120+ } else if (approvals.size >= quorum && rejections.size === 0) {
121+ status = '✅ Approved';
104122 }
105- const statusBody = `## RFC approval status: ${status}\n\nCore team approvers: ${formatUserList([...approvals])}\nRejection from: ${formatUserList([...rejections])}\nAwaiting approval from: ${formatUserList(awaiting)}`;
123+
124+ const statusBody = generateStatusBody(status, approvals, rejections, awaiting);
106125 console.log('New status body to post:\n', statusBody);
107126
108127 // Try to locate the existing status comment (starts with our header)
109128 let statusComment = comments.find(c => c.body.startsWith('## RFC approval status:'));
110129
111130 if (statusComment) {
112- await github.rest.issues.updateComment({
113- owner: org,
114- repo,
115- comment_id: statusComment.id,
116- body: statusBody
117- });
131+ if (statusComment.body.trim() === statusBody.trim()) {
132+ console.log('Status comment already up to date - no update required.');
133+ } else {
134+ console.log('Updating existing status comment.');
135+ await github.rest.issues.updateComment({
136+ owner: org,
137+ repo,
138+ comment_id: statusComment.id,
139+ body: statusBody
140+ });
141+ }
118142 } else {
119143 // Fallback: create a new status comment if missing (shouldn't normally happen)
120144 await github.rest.issues.createComment({
0 commit comments