-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Actions: New PR labeling and issue link workflows (#1149)
* Actions: New PR labeling and issue link workflows * Update issue/pr trigger workflows, remove dependabot workflow
- Loading branch information
1 parent
5ba8064
commit 22e3fae
Showing
9 changed files
with
238 additions
and
50 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Check Linked Issue on PR | ||
on: | ||
pull_request: | ||
types: [opened, edited] | ||
branches: | ||
- "develop" | ||
|
||
jobs: | ||
Check-For-Linked-Issue: | ||
runs-on: ubuntu-latest | ||
if: ${{ github.event.action == 'opened' || github.event.action == 'edited' }} | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Check for keyword and issue number | ||
id: check-for-keyword | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const script = require('./scripts/github-actions/checkPRLinkedIssue.js') | ||
script({g: github, c: context}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: Auto-label PR from Linked Issue and Review Status | ||
|
||
on: | ||
pull_request: | ||
types: [opened, edited, synchronize] | ||
pull_request_review: | ||
types: [submitted, edited, dismissed] | ||
|
||
jobs: | ||
auto-label: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup Node.js | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: "20" | ||
|
||
- name: Install dependencies | ||
run: npm install @actions/github @actions/core | ||
|
||
- name: Run PR labeling script | ||
uses: actions/github-script@v7 | ||
with: | ||
github-token: ${{secrets.GITHUB_TOKEN}} | ||
script: | | ||
const script = require('./scripts/github-actions/prLabeling.js') | ||
await script({github, context, core}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
const postIssueComment = require('./utils/postGHComment'); | ||
|
||
async function main({ g, c }) { | ||
const github = g; | ||
const context = c; | ||
|
||
// Retrieve body of context.payload and search for GitHub keywords followed by | ||
// '#' + number. Exclude any matches that are in a comment within the PR body | ||
const prBody = context.payload.pull_request.body; | ||
const prNumber = context.payload.pull_request.number; | ||
const prOwner = context.payload.pull_request.user.login; | ||
const exemptPrOwners = ['kyleecodes', 'swetha-charles', 'eleanorreem', 'annarhughes', 'tarebyte', 'dependabot[bot]', 'dependabot', 'github-actions[bot]', 'github-actions']; | ||
const regex = | ||
/(?!<!--)(?:close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\s*#(\d+)(?![^<]*-->)/gi; | ||
const match = prBody.match(regex); | ||
|
||
let prComment; | ||
|
||
// if no issue linked in description and PR not owned by staff | ||
if (!match && !exemptPrOwners.includes(prOwner)) { | ||
console.log('PR does not have a properly linked issue.'); | ||
prComment = `@${prOwner}, this Pull Request is not linked to a valid issue. Above, on the first line of your PR, please link the number of the issue that you worked on using the format of 'Resolves #' + issue number, for example: **_Fixes #9876_**\n\nNote: Do **_not_** use the number of this PR or URL for issue. Chayn staff may disregard this. A linked issue is required for automated PR labeling.`; | ||
} else { | ||
console.log(match[0]); | ||
const [keyword, linkNumber] = match[0].replaceAll('#', '').split(' '); | ||
console.log(`Found a keyword: \'${keyword}\'. Checking for legitimate linked issue...`); | ||
|
||
// Check if the linked issue exists in repo | ||
// Issue get request: https://octokit.github.io/rest.js/v20#issues-get | ||
try { | ||
await github.rest.issues.get({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: linkNumber, | ||
}); | ||
console.log( | ||
`Found an issue: \'#${linkNumber}\' in repo. Reference is a legitimate linked issue.`, | ||
); | ||
} catch (error) { | ||
console.log(`Couldn\'t find issue: \'#${linkNumber}\' in repo. Posting comment...`); | ||
prComment = `@${prOwner}, the issue number referenced above as "**${keyword} #${linkNumber}**" is not found. Please replace with a valid issue number.`; | ||
} | ||
} | ||
|
||
// Post comment to PR | ||
if (prComment) { | ||
postIssueComment(prNumber, prComment, github, context); | ||
} | ||
} | ||
|
||
module.exports = main; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
module.exports = async ({ github, context, core }) => { | ||
const pr = context.payload.pull_request; | ||
const bodyText = pr.body; | ||
// regex to search for issue linked in description | ||
const issuePattern = /(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\s+#(\d+)/i; | ||
const match = bodyText.match(issuePattern); | ||
|
||
// reset labels | ||
async function removeAllLabels() { | ||
const currentLabels = await github.rest.issues.listLabelsOnIssue({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: pr.number, | ||
}); | ||
|
||
for (const label of currentLabels.data) { | ||
await github.rest.issues.removeLabel({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: pr.number, | ||
name: label.name, | ||
}); | ||
} | ||
} | ||
|
||
if (!match) { | ||
console.log('No linked issue found in the pull request description.'); | ||
await removeAllLabels(); | ||
return; | ||
} | ||
|
||
// label PR with linked issue labels | ||
const issueNumber = match[2]; | ||
console.log(`Linked issue found: #${issueNumber}`); | ||
|
||
try { | ||
const issue = await github.rest.issues.get({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: issueNumber, | ||
}); | ||
|
||
const issueLabels = issue.data.labels.map((label) => label.name); | ||
|
||
// Remove all existing labels | ||
await removeAllLabels(); | ||
|
||
if (issueLabels.length > 0) { | ||
await github.rest.issues.addLabels({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: pr.number, | ||
labels: issueLabels, | ||
}); | ||
console.log(`Added labels to PR: ${issueLabels.join(', ')}`); | ||
} else { | ||
console.log('No labels found on the linked issue.'); | ||
} | ||
|
||
// Update review status label | ||
const reviews = await github.rest.pulls.listReviews({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
pull_number: pr.number, | ||
}); | ||
|
||
let reviewStatus = { name: 'needs review', color: 'b60205' }; | ||
if (reviews.data.length > 0) { | ||
const latestReview = reviews.data[reviews.data.length - 1]; | ||
switch (latestReview.state) { | ||
case 'APPROVED': | ||
reviewStatus = { name: 'review approved', color: '0E8A16' }; | ||
break; | ||
case 'CHANGES_REQUESTED': | ||
reviewStatus = { name: 'changes requested', color: 'FBCA04' }; | ||
break; | ||
case 'COMMENTED': | ||
reviewStatus = { name: 'review in progress', color: 'FBCA04' }; | ||
break; | ||
} | ||
} | ||
await github.rest.issues | ||
.createLabel({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
name: reviewStatus.name, | ||
color: reviewStatus.color, | ||
}) | ||
.catch((error) => { | ||
if (error.status !== 422) { | ||
// 422 means label already exists | ||
throw error; | ||
} | ||
}); | ||
|
||
await github.rest.issues.addLabels({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: pr.number, | ||
labels: [reviewStatus.name], | ||
}); | ||
console.log( | ||
`Updated review status label: ${reviewStatus.name} with color: ${reviewStatus.color}`, | ||
); | ||
} catch (error) { | ||
console.error(`Error processing PR: ${error}`); | ||
core.setFailed(`Error processing PR: ${error.message}`); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* Posts a comment on GitHub issues and pull requests | ||
* TODO: reduce repetition and use in other workflow scripts. | ||
* @param {Number} issueNum - the issue number where the comment should be posted | ||
* @param {String} comment - the comment to be posted | ||
*/ | ||
async function postComment(issueNum, comment, github, context) { | ||
try { | ||
await github.rest.issues.createComment({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: issueNum, | ||
body: comment, | ||
}); | ||
} catch (err) { | ||
throw new Error(err); | ||
} | ||
} | ||
|
||
module.exports = postComment; |