({ issue, token, runId, owner, repo } = {})
| 572 | } |
| 573 | |
| 574 | export async function evaluateExternalPluginIssue({ issue, token, runId, owner, repo } = {}) { |
| 575 | const issueBody = issue?.body ?? ""; |
| 576 | const parsed = parseExternalPluginIssueBody(issueBody); |
| 577 | const errors = [...parsed.errors]; |
| 578 | const warnings = []; |
| 579 | |
| 580 | const localPluginNames = readLocalPluginNames(); |
| 581 | const { plugins: existingExternalPlugins } = readExternalPlugins({ policy: "marketplace" }); |
| 582 | const duplicateNames = [ |
| 583 | ...localPluginNames, |
| 584 | ...existingExternalPlugins.map((plugin) => plugin.name).filter(Boolean), |
| 585 | ]; |
| 586 | |
| 587 | const validationResult = validateExternalPlugin(parsed.plugin, 0, { policy: "publicSubmission" }); |
| 588 | errors.push(...validationResult.errors.map(toSubmissionError)); |
| 589 | warnings.push(...validationResult.warnings.map(toSubmissionError)); |
| 590 | |
| 591 | if (parsed.plugin?.name) { |
| 592 | const matchingName = duplicateNames.find( |
| 593 | (name) => String(name).toLowerCase() === String(parsed.plugin.name).toLowerCase(), |
| 594 | ); |
| 595 | if (matchingName) { |
| 596 | errors.push(`submission: plugin name "${parsed.plugin.name}" conflicts with existing plugin "${matchingName}"`); |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | if (parsed.plugin?.source?.repo && (parsed.plugin?.source?.ref || parsed.plugin?.source?.sha)) { |
| 601 | await validateRemoteRepository(parsed.plugin.source.repo, parsed.plugin.source, errors, warnings, token); |
| 602 | } |
| 603 | |
| 604 | const dedupedErrors = [...new Set(errors)]; |
| 605 | const dedupedWarnings = [...new Set(warnings)]; |
| 606 | const valid = dedupedErrors.length === 0; |
| 607 | const marker = EXTERNAL_PLUGIN_INTAKE_COMMENT_MARKER; |
| 608 | const normalizedKeywords = parsed.plugin?.keywords?.length ? parsed.plugin.keywords.join(", ") : "_None provided_"; |
| 609 | const notes = parsed.additionalNotes ?? "_No additional notes provided._"; |
| 610 | const payload = parsed.plugin |
| 611 | ? [ |
| 612 | "```json", |
| 613 | JSON.stringify(parsed.plugin, null, 2), |
| 614 | "```", |
| 615 | ].join("\n") |
| 616 | : "```json\n{}\n```"; |
| 617 | |
| 618 | const runLink = runId && owner && repo ? `_[View workflow run](https://github.com/${owner}/${repo}/actions/runs/${runId})_` : ""; |
| 619 | |
| 620 | const commentBody = valid |
| 621 | ? [ |
| 622 | marker, |
| 623 | "## ✅ External plugin intake passed", |
| 624 | "", |
| 625 | `This submission passed automated intake validation and is ready for maintainer review.`, |
| 626 | "", |
| 627 | `- **Plugin:** ${parsed.plugin.name}`, |
| 628 | `- **Repository:** ${parsed.plugin.repository}`, |
| 629 | parsed.plugin.source.ref ? `- **Ref:** [\`${parsed.plugin.source.ref.replaceAll('\`', '\\\`')}\`](https://github.com/${encodeRepoPath(parsed.plugin.source.repo)}/tree/${encodeURIComponent(parsed.plugin.source.ref).replaceAll("%2F", "/")})` : undefined, |
| 630 | parsed.plugin.source.sha ? `- **SHA:** [\`${parsed.plugin.source.sha.replaceAll('\`', '\\\`')}\`](https://github.com/${encodeRepoPath(parsed.plugin.source.repo)}/tree/${encodeURIComponent(parsed.plugin.source.sha).replaceAll("%2F", "/")})` : undefined, |
| 631 | `- **Keywords:** ${normalizedKeywords}`, |
no test coverage detected