name: External Plugin Mark Ready Command on: issue_comment: types: [created] concurrency: group: external-plugin-intake-${{ github.event.issue.number }} cancel-in-progress: false permissions: contents: read issues: write jobs: mark-ready: runs-on: ubuntu-latest if: >- !github.event.issue.pull_request && startsWith(github.event.comment.body, '/mark-ready-for-review') steps: - name: Checkout staged branch uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: ref: staged - name: Apply explicit ready-for-review override uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const path = require('path'); const { pathToFileURL } = require('url'); const intake = await import(pathToFileURL(path.join(process.env.GITHUB_WORKSPACE, 'eng', 'external-plugin-intake.mjs')).href); const intakeState = await import(pathToFileURL(path.join(process.env.GITHUB_WORKSPACE, 'eng', 'external-plugin-intake-state.mjs')).href); const parsed = intake.parseMarkReadyForReviewCommand(context.payload.comment.body); if (!parsed) { core.info('No supported /mark-ready-for-review command was found.'); return; } const actor = context.payload.comment.user?.login; if (!actor || context.payload.comment.user?.type === 'Bot' || actor === 'github-actions[bot]') { core.info('Ignoring command from a bot or unknown actor.'); return; } const permission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: context.repo.owner, repo: context.repo.repo, username: actor }); const hasWriteAccess = ['admin', 'write', 'maintain'].includes(permission.data.permission); if (!hasWriteAccess) { core.info(`Ignoring /mark-ready-for-review because ${actor} does not have write access.`); return; } const { data: currentIssue } = await github.rest.issues.get({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number }); const labelNames = new Set((currentIssue.labels || []).map((label) => label.name)); if (!labelNames.has('external-plugin')) { core.info('Ignoring command because issue is not an external plugin submission.'); return; } if (labelNames.has('approved')) { core.info('Ignoring command because issue is already approved.'); return; } if (!labelNames.has('requires-submitter-fixes')) { core.info('Ignoring command because issue is not currently blocked by submitter-fix gates.'); return; } await intakeState.syncExternalPluginIntakeLabels({ github, owner: context.repo.owner, repo: context.repo.repo, issueNumber: context.issue.number, desiredLabels: new Set(['external-plugin', 'ready-for-review']) }); const marker = ''; const reason = parsed.reason || 'No reason provided.'; const body = [ marker, '## ✅ External plugin manually moved to ready-for-review', '', `Maintainer **${actor}** used \`${intake.MARK_READY_FOR_REVIEW_COMMAND}\` to move this submission from \`requires-submitter-fixes\` to \`ready-for-review\`.`, '', '### Reason', '', reason ].join('\n'); await intakeState.upsertExternalPluginIntakeComment({ github, owner: context.repo.owner, repo: context.repo.repo, issueNumber: context.issue.number, marker, body }); if (currentIssue.state === 'closed') { await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, state: 'open' }); }