export const EXTERNAL_PLUGIN_INTAKE_LABELS = Object.freeze({ "external-plugin": { color: "FEF2C0", description: "Public external plugin submission", }, "awaiting-review": { color: "FBCA04", description: "Submission is waiting for automated intake validation", }, "ready-for-review": { color: "0E8A16", description: "Submission passed intake validation and is ready for maintainer review", }, approved: { color: "1D76DB", description: "Submission was approved by a maintainer", }, rejected: { color: "B60205", description: "Submission was rejected or failed intake validation", }, }); const EXTERNAL_PLUGIN_INTAKE_SYNC_LABELS = Object.freeze([ "external-plugin", "awaiting-review", "ready-for-review", "rejected", ]); async function ensureLabel({ github, owner, repo, name, config }) { try { await github.rest.issues.createLabel({ owner, repo, name, color: config.color, description: config.description, }); } catch (error) { if (error.status !== 422) { throw error; } } } async function removeLabel({ github, owner, repo, issueNumber, name }) { try { await github.rest.issues.removeLabel({ owner, repo, issue_number: issueNumber, name, }); } catch (error) { if (error.status !== 404) { throw error; } } } export async function syncExternalPluginIntakeLabels({ github, owner, repo, issueNumber, desiredLabels }) { await Promise.all( Object.entries(EXTERNAL_PLUGIN_INTAKE_LABELS).map(([name, config]) => ensureLabel({ github, owner, repo, name, config }) ) ); const currentLabels = await github.paginate(github.rest.issues.listLabelsOnIssue, { owner, repo, issue_number: issueNumber, per_page: 100, }); const currentManagedLabels = currentLabels .map((label) => label.name) .filter((name) => EXTERNAL_PLUGIN_INTAKE_SYNC_LABELS.includes(name)); const labelsToAdd = [...desiredLabels].filter((name) => !currentManagedLabels.includes(name)); const labelsToRemove = currentManagedLabels.filter((name) => !desiredLabels.has(name)); if (labelsToAdd.length > 0) { await github.rest.issues.addLabels({ owner, repo, issue_number: issueNumber, labels: labelsToAdd, }); } for (const name of labelsToRemove) { await removeLabel({ github, owner, repo, issueNumber, name }); } } export async function upsertExternalPluginIntakeComment({ github, owner, repo, issueNumber, marker, body, }) { const { data: comments } = await github.rest.issues.listComments({ owner, repo, issue_number: issueNumber, per_page: 100, }); const existingComment = comments.find( (comment) => comment.user?.login === "github-actions[bot]" && comment.body?.includes(marker) ); if (existingComment) { await github.rest.issues.updateComment({ owner, repo, comment_id: existingComment.id, body, }); return; } await github.rest.issues.createComment({ owner, repo, issue_number: issueNumber, body, }); } export async function applyExternalPluginIntakeEvaluation({ github, owner, repo, issueNumber, evaluation, }) { const desiredLabels = evaluation.valid ? new Set(["external-plugin", "ready-for-review"]) : new Set(["external-plugin", "rejected"]); await syncExternalPluginIntakeLabels({ github, owner, repo, issueNumber, desiredLabels, }); await upsertExternalPluginIntakeComment({ github, owner, repo, issueNumber, marker: evaluation.commentMarker, body: evaluation.commentBody, }); return { desiredLabels }; }