-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add reusable PR description check workflow #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
LuWang1983
merged 4 commits into
master
from
task/INFR-6089/pr-description-check-workflows
Aug 26, 2026
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
eea6cbc
feat: add reusable PR description check workflow
LuWang1983 113dfbd
feat: exempt revert PRs and document Overview section requirement
LuWang1983 5ab2b7c
refactor: tighten PR description check workflow triggers
LuWang1983 ab23e84
chore: remove space
LuWang1983 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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,65 @@ | ||
| /** | ||
| * Validate that a PR description has a filled Overview section. | ||
| * Intended for use with actions/github-script. | ||
| * | ||
| * @param {{ core: import('@actions/core'), context: import('@actions/github').Context }} params | ||
| * @param {{ minOverviewLength?: number }} options | ||
| */ | ||
| /** | ||
| * Revert PRs are exempt from description validation. Detection lives here rather than | ||
| * in a workflow `if` condition so the job still completes successfully instead of | ||
| * showing as skipped, which can block merges when this check is required. | ||
| */ | ||
| function isRevertPr(pr) { | ||
| const title = pr?.title ?? ''; | ||
| const headRef = pr?.head?.ref ?? ''; | ||
| return /^Revert\s/i.test(title) || /^revert[-_]/i.test(headRef); | ||
| } | ||
|
|
||
| module.exports = async function validatePrDescription({ core, context }, options = {}) { | ||
| const minOverviewLength = Number(options.minOverviewLength) || 40; | ||
| const pr = context.payload.pull_request; | ||
|
|
||
| if (isRevertPr(pr)) { | ||
| core.info('Skipping PR description check for revert PR.'); | ||
| return; | ||
| } | ||
|
|
||
| const body = pr?.body ?? ''; | ||
|
|
||
| if (!body.trim()) { | ||
| core.setFailed('PR description is empty. Please add a description with enough context for reviewers.'); | ||
| return; | ||
| } | ||
|
|
||
| if (/\*\*REPLACE ME\*\*/.test(body)) { | ||
| core.setFailed('PR description still contains the "REPLACE ME" placeholder. Please fill in the overview.'); | ||
| return; | ||
| } | ||
|
|
||
| const withoutComments = body.replace(/<!--[\s\S]*?-->/g, ''); | ||
| const overviewSection = withoutComments | ||
| .split(/\n(?=## )/) | ||
| .find((section) => /^##[^\n]*overview/i.test(section.trim())); | ||
|
|
||
| if (!overviewSection) { | ||
| core.setFailed( | ||
| 'PR description must include an "## Overview" section. Use the standard PR template and fill in the overview.' | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const overviewText = overviewSection | ||
| .replace(/^##[^\n]*\n?/i, '') | ||
| .replace(/\s+/g, ' ') | ||
| .trim(); | ||
|
|
||
| if (overviewText.length < minOverviewLength) { | ||
| core.setFailed( | ||
| `Overview section is too short (${overviewText.length} characters, minimum ${minOverviewLength}). Please add a brief description of the change.` | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| core.info(`PR description check passed (overview: ${overviewText.length} characters).`); | ||
| }; |
This file contains hidden or 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,44 @@ | ||
| name: pr-description-check | ||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| min_overview_length: | ||
| description: Minimum character count required in the Overview section after stripping HTML comments and placeholders. | ||
| type: number | ||
| required: false | ||
| default: 40 | ||
| secrets: | ||
| GH_TOKEN: | ||
| required: true | ||
|
|
||
| jobs: | ||
| pr-description-check: | ||
| name: PR description check | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout workflow scripts | ||
| uses: actions/checkout@v7 | ||
| with: | ||
| # Check out the reusable workflow's own repo/SHA so callers get the | ||
| # script version that matches the pinned callable workflow. | ||
| repository: ${{ job.workflow_repository }} | ||
| ref: ${{ job.workflow_sha }} | ||
| sparse-checkout: | | ||
| .github/scripts | ||
| token: ${{ secrets.GH_TOKEN }} | ||
|
|
||
| - name: Validate PR description | ||
| uses: actions/github-script@v9 | ||
| env: | ||
| MIN_OVERVIEW_LENGTH: ${{ inputs.min_overview_length }} | ||
| with: | ||
| github-token: ${{ secrets.GH_TOKEN }} | ||
| script: | | ||
| const script = require('${{ github.workspace }}/.github/scripts/validate-pr-description.js'); | ||
| // github, context, and core are injected by github-script from this | ||
| // job's runtime context (the caller's workflow run / PR payload). | ||
| // Revert PRs (title "Revert ..." or revert-* branch) are exempt — see validate-pr-description.js. | ||
| await script( | ||
| { github, context, core }, | ||
| { minOverviewLength: Number(process.env.MIN_OVERVIEW_LENGTH) } | ||
| ); | ||
This file contains hidden or 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,13 @@ | ||
| name: pr-description-check | ||
| on: | ||
| pull_request: | ||
| types: | ||
| - opened | ||
| - edited | ||
| - reopened | ||
|
|
||
| jobs: | ||
| call-pr-description-check-workflow: | ||
| uses: ./.github/workflows/callable.pr-description-check.yaml | ||
| secrets: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: there's a new way to reference actions in the same repo without having to checkout the source code. this would mean wrapping the
validate-pr-description.jsscript in a callable actionhttps://github.blog/changelog/2026-07-30-reference-same-repository-actions-with-self-repository-syntax/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave this to the next time if necessary. But TIL, this is good to know!