From b74ec695681b008912437eb1c119bf3e951097bd Mon Sep 17 00:00:00 2001 From: Logan Nguyen Date: Fri, 12 Jul 2024 15:41:01 -0400 Subject: [PATCH] feat: added check-pr-label-milestone workflow Signed-off-by: Logan Nguyen --- .github/scripts/check-pr.js | 79 +++++++++++++++++++ .../workflows/pr-label-milestone-check.yml | 27 +++++++ 2 files changed, 106 insertions(+) create mode 100644 .github/scripts/check-pr.js create mode 100644 .github/workflows/pr-label-milestone-check.yml diff --git a/.github/scripts/check-pr.js b/.github/scripts/check-pr.js new file mode 100644 index 000000000..184408196 --- /dev/null +++ b/.github/scripts/check-pr.js @@ -0,0 +1,79 @@ +const axios = require('axios'); + +const githubToken = process.env.GITHUB_TOKEN; +const { GITHUB_REPOSITORY, GITHUB_PR_NUMBER } = process.env; + +const [owner, repo] = GITHUB_REPOSITORY.split('/'); + +async function getPRDetails() { + const url = `https://api.github.com/repos/${owner}/${repo}/pulls/${GITHUB_PR_NUMBER}`; + const response = await axios.get(url, { + headers: { + Authorization: `token ${githubToken}`, + }, + }); + return response.data; +} + +async function getIssueDetails(issueNumber) { + try { + const url = `https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`; + const response = await axios.get(url, { + headers: { + Authorization: `token ${githubToken}`, + }, + }); + return response.data; + } catch (error) { + if (error.response && error.response.status === 404) { + console.log(`Issue #${issueNumber} not found, skipping...`); + return null; + } else { + throw error; + } + } +} + +async function run() { + try { + const pr = await getPRDetails(); + const { labels: prLabels, milestone: prMilestone, body: prBody } = pr; + + if (prLabels.length === 0) { + throw new Error('The PR has no labels.'); + } + if (!prMilestone) { + throw new Error('The PR has no milestone.'); + } + + const issueNumberMatches = prBody.match(/#(\d+)/g); + + if (!issueNumberMatches) { + console.log('No associated issues found in PR description.'); + } else { + for (const match of issueNumberMatches) { + const issueNumber = match.replace('#', ''); + const issue = await getIssueDetails(issueNumber); + if (issue) { + const { labels: issueLabels, milestone: issueMilestone } = issue; + + if (issueLabels.length === 0) { + throw new Error(`Associated issue #${issueNumber} has no labels.`); + } + if (!issueMilestone) { + throw new Error( + `Associated issue #${issueNumber} has no milestone.` + ); + } + } + } + } + + console.log('PR and all associated issues have labels and milestones.'); + } catch (error) { + console.error(error.message); + process.exit(1); + } +} + +run(); diff --git a/.github/workflows/pr-label-milestone-check.yml b/.github/workflows/pr-label-milestone-check.yml new file mode 100644 index 000000000..61b6d5828 --- /dev/null +++ b/.github/workflows/pr-label-milestone-check.yml @@ -0,0 +1,27 @@ +name: PR Label and Milestone Check + +on: + pull_request: + types: [opened, edited, labeled, unlabeled, synchronize] + +jobs: + check_pr: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install dependencies + run: npm install axios + + - name: Check PR labels and milestones + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_NUMBER: ${{ github.event.number }} + run: node .github/scripts/check-pr.js