Skip to content

Commit 5483ce1

Browse files
Added pr-body-validation workflow (#1233)
1 parent 10b311f commit 5483ce1

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

.github/pull_request_template.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,9 @@ Thanks for submitting a pull request! Please provide enough information so that
3232
**Does this PR introduce a breaking change?**
3333

3434
<!-- If this PR introduces a breaking change, please describe the impact and a migration path for existing applications. -->
35+
36+
# Checklist
37+
38+
Please ensure the following tasks are completed before submitting this pull request.
39+
40+
- [ ] Read, understood, and followed the [contributing guidelines](https://github.com/json-schema-org/website/blob/main/CONTRIBUTING.md).
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
name: PR Body Validation
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, edited, synchronize, reopened]
6+
7+
jobs:
8+
check-pr-content:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
pull-requests: write
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Check PR content
18+
uses: actions/github-script@v7
19+
with:
20+
github-token: ${{ secrets.GITHUB_TOKEN }}
21+
script: |
22+
const pr = context.payload.pull_request;
23+
const prBody = pr.body || '';
24+
25+
let missingItems = [];
26+
27+
// Helper function to extract content between section headers
28+
function extractSectionContent(content, sectionHeader) {
29+
const regex = new RegExp(`\\*\\*${sectionHeader}\\*\\*(.*?)(?=\\*\\*|$)`, 's');
30+
const match = content.match(regex);
31+
if (!match) return '';
32+
33+
// Remove HTML comments and trim whitespace
34+
return match[1].replace(/<!--[\s\S]*?-->/g, '').trim();
35+
}
36+
37+
// Helper function to check if content is meaningful
38+
function hasMeaningfulContent(content) {
39+
// Remove HTML comments, markdown symbols, and extra whitespace
40+
const cleanContent = content
41+
.replace(/<!--[\s\S]*?-->/g, '')
42+
.replace(/[#*\[\]()_]/g, '')
43+
.trim();
44+
return cleanContent.length >= 3; // Requiring at least 3 characters
45+
}
46+
47+
// Check for issue links
48+
const issueRegex = /(closes|related to)\s+#\d+/i;
49+
if (!issueRegex.test(prBody)) {
50+
missingItems.push('issue reference');
51+
}
52+
53+
// Check for kind of change
54+
const changeContent = extractSectionContent(prBody, 'What kind of change does this PR introduce\\?');
55+
if (!hasMeaningfulContent(changeContent)) {
56+
missingItems.push('kind of change description');
57+
}
58+
59+
// Check for breaking changes
60+
const breakingContent = extractSectionContent(prBody, 'Does this PR introduce a breaking change\\?');
61+
if (!hasMeaningfulContent(breakingContent)) {
62+
missingItems.push('breaking changes information');
63+
}
64+
65+
// Check for unchecked items in checklist
66+
const checklistMatch = prBody.match(/# Checklist([\s\S]*?)(?=(?:#|$))/);
67+
if (checklistMatch && checklistMatch[1].includes('- [ ]')) {
68+
missingItems.push('completed checklist items');
69+
}
70+
71+
// Get current labels
72+
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
73+
owner: context.repo.owner,
74+
repo: context.repo.repo,
75+
issue_number: context.issue.number
76+
});
77+
78+
const hasNeedsInfoLabel = currentLabels.some(label => label.name === 'needs-info');
79+
80+
if (missingItems.length > 0) {
81+
// If there are missing items, add comment and label
82+
const missingItemsList = missingItems.join(', ');
83+
const comment = `Hi @${pr.user.login}! Thanks a lot for your contribution!
84+
85+
I noticed that the following required information is missing or incomplete: ${missingItemsList}
86+
87+
Please update the PR description to include this information. You can find placeholders in the PR template for these items.
88+
89+
Thanks a lot!`;
90+
91+
await github.rest.issues.createComment({
92+
owner: context.repo.owner,
93+
repo: context.repo.repo,
94+
issue_number: context.issue.number,
95+
body: comment
96+
});
97+
98+
// Add needs-info label if not already present
99+
if (!hasNeedsInfoLabel) {
100+
await github.rest.issues.addLabels({
101+
owner: context.repo.owner,
102+
repo: context.repo.repo,
103+
issue_number: context.issue.number,
104+
labels: ['needs-info']
105+
});
106+
}
107+
core.setFailed(`The following required information is missing or incomplete: ${missingItemsList}`);
108+
} else if (hasNeedsInfoLabel) {
109+
// If all requirements are met and the needs-info label exists, remove it
110+
await github.rest.issues.removeLabel({
111+
owner: context.repo.owner,
112+
repo: context.repo.repo,
113+
issue_number: context.issue.number,
114+
name: 'needs-info'
115+
});
116+
}

0 commit comments

Comments
 (0)