import * as core from '@actions/core'; import { context, getOctokit } from '@actions/github'; import { GitHub } from '@actions/github/lib/utils'; main().catch((error: Error): void => { console.error(error); process.exit(1); }); async function main(): Promise { // "GITHUB_TOKEN" is an automatically generated, repository-specific access token provided by GitHub Actions. const githubToken = process.env.GITHUB_TOKEN; if (!githubToken) { core.setFailed('GITHUB_TOKEN not found'); process.exit(1); } // Initialise octokit, required to call Github GraphQL API const octokit: InstanceType = getOctokit(githubToken); // Retrieve pull request info from context const prRepoOwner = context.repo.owner; const prRepoName = context.repo.repo; const prNumber = context.payload.pull_request?.number; if (!prNumber) { core.setFailed('Pull request number not found'); process.exit(1); } // Retrieve pull request labels const prLabels = await retrievePullRequestLabels(octokit, prRepoOwner, prRepoName, prNumber); const preventMergeLabels = ["needs-qa", "QA'd but questions", "issues-found", "need-ux-ds-review", "blocked", "stale", "DO-NOT-MERGE"]; let hasTeamLabel = false; // Check pull request has at least required QA label and team label for (const label of prLabels) { if (label.startsWith("team-") || label === "external-contributor") { console.log(`PR contains a team label as expected: ${label}`); hasTeamLabel = true; } if (preventMergeLabels.includes(label)) { throw new Error(`PR cannot be merged because it still contains this label: ${label}`); } if (hasTeamLabel) { return; } } // Otherwise, throw an arror to prevent from merging let errorMessage = ''; if (!hasTeamLabel) { errorMessage += 'No team labels found on the PR. '; } errorMessage += `Please make sure the PR is appropriately labeled before merging it.\n\nSee labeling guidelines for more detail: https://github.com/MetaMask/metamask-extension/blob/develop/.github/LABELING_GUIDELINES.md`; throw new Error(errorMessage); } // This function retrieves the pull request on a specific repo async function retrievePullRequestLabels(octokit: InstanceType, repoOwner: string, repoName: string, prNumber: number): Promise { const retrievePullRequestLabelsQuery = ` query RetrievePullRequestLabels($repoOwner: String!, $repoName: String!, $prNumber: Int!) { repository(owner: $repoOwner, name: $repoName) { pullRequest(number: $prNumber) { labels(first: 100) { nodes { name } } } } } `; const retrievePullRequestLabelsResult: { repository: { pullRequest: { labels: { nodes: { name: string; }[]; } }; }; } = await octokit.graphql(retrievePullRequestLabelsQuery, { repoOwner, repoName, prNumber, }); const pullRequestLabels = retrievePullRequestLabelsResult?.repository?.pullRequest?.labels?.nodes?.map(labelObject => labelObject?.name); return pullRequestLabels || []; }