Use github-script to safely label PRs from forks (#9256)
parent
485b72cd0d
commit
ff2d9ad67d
|
@ -1,27 +1,75 @@
|
||||||
name: "Apply issue labels to PR"
|
name: "Apply issue labels to PR"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request_target:
|
||||||
types: [opened]
|
types:
|
||||||
|
- opened
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
label_on_pr:
|
label_on_pr:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
contents: none
|
||||||
|
issues: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
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
|
- name: Apply labels from linked issue to PR
|
||||||
env:
|
uses: actions/github-script@v5
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
with:
|
||||||
PR_DATA: ${{ toJson(github.event.pull_request) }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: node ./.github/workflows/scripts/apply-issue-labels-to-pr.ts
|
script: |
|
||||||
|
async function getLinkedIssues(owner, repo, prNumber) {
|
||||||
|
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 variables = {
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
prNumber: prNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await github.graphql(query, variables);
|
||||||
|
return result.repository.pullRequest.closingIssuesReferences.nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pr = context.payload.pull_request;
|
||||||
|
const linkedIssues = await getLinkedIssues(
|
||||||
|
context.repo.owner,
|
||||||
|
context.repo.repo,
|
||||||
|
pr.number
|
||||||
|
);
|
||||||
|
|
||||||
|
const labelsToAdd = new Set();
|
||||||
|
for (const issue of linkedIssues) {
|
||||||
|
if (issue.labels && issue.labels.nodes) {
|
||||||
|
for (const label of issue.labels.nodes) {
|
||||||
|
labelsToAdd.add(label.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelsToAdd.size) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
labels: Array.from(labelsToAdd),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
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);
|
|
||||||
})();
|
|
Loading…
Reference in New Issue