New pipeline: nf-core/lrp2 #2711
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: RFC approval automation | |
| on: | |
| issues: | |
| types: [opened, closed, labeled, unlabeled] | |
| issue_comment: | |
| types: [created, edited] | |
| jobs: | |
| rfc_approval: | |
| # Only run for RFC proposal issues | |
| if: startsWith(github.event.issue.title, 'New RFC') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Handle RFC approval logic | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1 | |
| with: | |
| github-token: ${{ secrets.nf_core_bot_auth_token }} | |
| script: | | |
| const ApprovalManager = require('./.github/workflows/lib/approval.js'); | |
| const issueNumber = context.issue.number; | |
| const org = context.repo.owner; | |
| const repo = context.repo.repo; | |
| // Initialize approval manager | |
| const approvalManager = await new ApprovalManager(github, org, repo, issueNumber).initialize(); | |
| // Ignore comments on closed issues | |
| if (context.eventName === 'issue_comment' && context.payload.issue.state === 'closed') { | |
| console.log('Comment event on closed issue, ignoring.'); | |
| return; | |
| } | |
| const quorum = Math.ceil(approvalManager.coreTeamMembers.length / 2); | |
| console.log(`Quorum set to ${quorum}.`); | |
| function generateStatusBody(status) { | |
| const coreApprovers = [...approvalManager.coreApprovals]; | |
| const maintainerApprovers = [...approvalManager.maintainerApprovals]; | |
| const coreRejecters = [...approvalManager.coreRejections]; | |
| const maintainerRejecters = [...approvalManager.maintainerRejections]; | |
| const awaitingCore = [...approvalManager.awaitingCore]; | |
| const awaitingMaintainers = [...approvalManager.awaitingMaintainers]; | |
| const totalApprovals = approvalManager.coreApprovals.size + approvalManager.maintainerApprovals.size; | |
| let body = `## Approval status: ${status}\n\nRFC needs ${quorum} approvals: core team only, or core + maintainer combined (min. 1 core).\n**${totalApprovals}/${quorum}** approvals (${approvalManager.coreApprovals.size} core, ${approvalManager.maintainerApprovals.size} maintainer)\n\n`; | |
| if (coreApprovers.length > 0 || maintainerApprovers.length > 0 || coreRejecters.length > 0 || maintainerRejecters.length > 0 || awaitingCore.length > 0 || awaitingMaintainers.length > 0) { | |
| body += `|Review Status|Team members|\n|--|--|\n`; | |
| if (coreApprovers.length > 0) { | |
| body += `| ✅ Approved (Core) | ${approvalManager.formatUserList(coreApprovers)} |\n`; | |
| } | |
| if (maintainerApprovers.length > 0) { | |
| body += `| ✅ Approved (Maintainer) | ${approvalManager.formatUserList(maintainerApprovers)} |\n`; | |
| } | |
| if (coreRejecters.length > 0) { | |
| body += `| ❌ Rejected (Core) | ${approvalManager.formatUserList(coreRejecters)} |\n`; | |
| } | |
| if (maintainerRejecters.length > 0) { | |
| body += `| ❌ Rejected (Maintainer) | ${approvalManager.formatUserList(maintainerRejecters)} |\n`; | |
| } | |
| if (awaitingCore.length > 0) { | |
| body += `| 🕐 Pending (Core) | ${approvalManager.formatUserList(awaitingCore)} |\n`; | |
| } | |
| if (awaitingMaintainers.length > 0) { | |
| body += `| 🕐 Pending (Maintainer) | ${approvalManager.formatUserList(awaitingMaintainers)} |\n`; | |
| } | |
| } | |
| return body; | |
| } | |
| // Handle label changes | |
| if (context.eventName === 'issues' && (context.payload.action === 'labeled' || context.payload.action === 'unlabeled')) { | |
| const label = context.payload.label.name; | |
| if (label === 'timed-out') { | |
| console.log('Timed-out label detected, updating status'); | |
| const statusBody = generateStatusBody('⏰ Timed Out'); | |
| await approvalManager.updateStatusComment(statusBody); | |
| return; | |
| } | |
| } | |
| // Handle new issue creation | |
| if (context.eventName === 'issues' && context.payload.action === 'opened') { | |
| const body = generateStatusBody('🕐 Pending'); | |
| console.log('Creating initial comment for review status'); | |
| await approvalManager.updateStatusComment(body); | |
| await approvalManager.updateIssueStatus('🕐 Pending'); | |
| return; | |
| } | |
| // Determine status | |
| let status = '🕐 Pending'; | |
| if (context.eventName === 'issues' && context.payload.action === 'closed' && context.payload.issue.state_reason === 'not_planned' && (approvalManager.coreRejections.size > 0)) { | |
| status = '❌ Rejected'; | |
| } else if (approvalManager.coreApprovals.size >= quorum || (approvalManager.coreApprovals.size >= 1 && (approvalManager.coreApprovals.size + approvalManager.maintainerApprovals.size) >= quorum)) { | |
| status = '✅ Approved'; | |
| } | |
| const statusBody = generateStatusBody(status); | |
| console.log('New status body to post:\n', statusBody); | |
| await approvalManager.updateStatusComment(statusBody); | |
| await approvalManager.updateIssueStatus(status); |