From bb547a0111dd57e9b3500e15944b1fa6e935d198 Mon Sep 17 00:00:00 2001 From: Ted Spare Date: Tue, 4 Apr 2023 05:28:36 -0400 Subject: [PATCH] Apply labels from linked issues to a PR (#8069) Co-authored-by: Peer Richelsen --- .../workflows/apply-issue-labels-to-pr.yml | 27 ++++ .../scripts/apply-issue-labels-to-pr.ts | 149 ++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 .github/workflows/apply-issue-labels-to-pr.yml create mode 100644 .github/workflows/scripts/apply-issue-labels-to-pr.ts diff --git a/.github/workflows/apply-issue-labels-to-pr.yml b/.github/workflows/apply-issue-labels-to-pr.yml new file mode 100644 index 0000000000..bf35292598 --- /dev/null +++ b/.github/workflows/apply-issue-labels-to-pr.yml @@ -0,0 +1,27 @@ +name: "Apply issue labels to PR" + +on: + pull_request: + types: [opened] + +jobs: + label_on_pr: + runs-on: ubuntu-latest + + permissions: + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: 16 + + - name: Apply labels from linked issue to PR + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_DATA: ${{ toJson(github.event.pull_request) }} + run: node ./.github/workflows/scripts/apply-issue-labels-to-pr.ts diff --git a/.github/workflows/scripts/apply-issue-labels-to-pr.ts b/.github/workflows/scripts/apply-issue-labels-to-pr.ts new file mode 100644 index 0000000000..0993c6455f --- /dev/null +++ b/.github/workflows/scripts/apply-issue-labels-to-pr.ts @@ -0,0 +1,149 @@ +const https = require("https"); + +async function applyLabelFromLinkedIssueToPR(pr, token) { + + // Get the labels from issues linked to the PR + const query = ` + query GetLinkedIssues($owner: String!, $repo: String!, $prNumber: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $prNumber) { + closingIssuesReferences(first: 10) { + nodes { + number + labels(first: 10) { + nodes { + name + } + } + } + } + } + } + } + `; + + const graphqlData = JSON.stringify({ + query, + variables: { + owner: pr.base.repo.owner.login, + repo: pr.base.repo.name, + prNumber: pr.number, + }, + }); + + const requestOptions = { + hostname: "api.github.com", + path: "/graphql", + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": graphqlData.length, + "Authorization": "Bearer " + token, + "User-Agent": "Node.js", + }, + }; + + // Use the native Node.js request library to make the request + let linkedIssues; + linkedIssues = await new Promise((resolve, reject) => { + const request = https.request(requestOptions, (response) => { + let responseBody = ""; + response.on("data", (chunk) => { + responseBody += chunk; + }); + response.on("end", () => { + resolve( + JSON.parse(responseBody) + ?.data + ?.repository + ?.pullRequest + ?.closingIssuesReferences + ?.nodes + ); + }); + }); + + request.on("error", (error) => { + reject(error); + }); + + request.write(graphqlData); + request.end(); + }); + + if (!linkedIssues || linkedIssues.length === 0) { + console.log("No issue linked."); + return; + } + + // Iterate over linked issues and apply labels to PR + for (const issue of linkedIssues) { + const labels = issue?.labels?.nodes?.map((label) => label.name); + + if (!labels || labels.length === 0) { + console.log(`No labels found on the linked issue #${issue.number}.`); + continue; + } + + const labelsData = JSON.stringify({ + labels: labels, + }); + + const requestOptions = { + hostname: "api.github.com", + path: `/repos/${pr.base.repo.owner.login}/${pr.base.repo.name}/issues/${pr.number}/labels`, + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": labelsData.length, + "Authorization": "Bearer " + token, + "User-Agent": "Node.js", + }, + }; + + let labelResult; + labelResult = await new Promise((resolve, reject) => { + const request = https.request(requestOptions, (response) => { + let responseBody = ""; + response.on("data", (chunk) => { + responseBody += chunk; + }); + response.on("data", () => {}); + response.on("end", () => { + resolve(JSON.parse(responseBody)); + }); + }); + + request.on("error", (error) => { + reject(error); + }); + + request.write(labelsData); + request.end(); + }); + + if (labelResult.message) { + console.log(`Error labelling PR: ${labelResult.message}`); + continue; + } + + console.log( + `Applied labels: ${labels.join(", ")} to PR #${ + pr.number + } from linked issue #${issue.number}` + ); + } +} + +// Pass the PR data and GitHub token to the script +(async () => { + if (!process.env.PR_DATA) { + console.log("No PR data found."); + return; + } + + const prData = JSON.parse(process.env.PR_DATA); + const token = process.env.GITHUB_TOKEN; + + await applyLabelFromLinkedIssueToPR(prData, token); +})();