-
-
Notifications
You must be signed in to change notification settings - Fork 159
129 lines (113 loc) · 5.58 KB
/
pr-validation.yml
File metadata and controls
129 lines (113 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
name: PR Validation
on:
pull_request:
types: [opened, synchronize]
permissions:
pull-requests: write
issues: read
contents: read
jobs:
validate:
name: Validate PR Requirements
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Validate PR requirements
uses: actions/github-script@v8
with:
script: |
const pr = context.payload.pull_request;
const prBody = pr.body || '';
const prAuthor = pr.user.login;
// Extract issue numbers from PR description
// Matches patterns like: Fixes #123, Closes #456, Relates to #789, etc.
const issuePattern = /(?:fixes?|closes?|resolves?|relates?\s+to|see|refs?)\s+#(\d+)/gi;
const matches = [...prBody.matchAll(issuePattern)];
const issueNumbers = [...new Set(matches.map(m => parseInt(m[1])))];
const warnings = [];
if (issueNumbers.length === 0) {
warnings.push('❌ **No linked issue found**: This PR does not reference any issue. Please link to an issue using "Fixes #123" or "Closes #123" in the PR description.');
} else {
// Check each linked issue
for (const issueNumber of issueNumbers) {
try {
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber
});
if (issue.data.state === 'closed') {
warnings.push(`⚠️ **Issue #${issueNumber} is closed**: The linked issue #${issueNumber} is already closed. Please ensure you're linking to the correct issue.`);
}
// Check if PR author is assigned to the issue
const assignees = issue.data.assignees.map(a => a.login);
if (assignees.length === 0) {
warnings.push(`⚠️ **Issue #${issueNumber} has no assignee**: This issue has not been assigned to anyone. Please wait for a maintainer to assign it to you before submitting a PR.`);
} else if (!assignees.includes(prAuthor)) {
warnings.push(`⚠️ **Assignment mismatch**: You (@${prAuthor}) are not assigned to issue #${issueNumber}. The issue is assigned to: ${assignees.map(a => `@${a}`).join(', ')}. Please wait for a maintainer to assign the issue to you.`);
}
// Check if issue has triage label (indicating it might not be approved yet)
const labels = issue.data.labels.map(l => l.name);
if (labels.includes('triage')) {
warnings.push(`ℹ️ **Issue #${issueNumber} is still in triage**: This issue may not have been reviewed and approved by a maintainer yet. Please ensure the issue has been approved before submitting a PR.`);
}
} catch (error) {
if (error.status === 404) {
warnings.push(`❌ **Issue #${issueNumber} not found**: The linked issue #${issueNumber} does not exist. Please check the issue number.`);
} else {
warnings.push(`⚠️ **Error checking issue #${issueNumber}**: ${error.message}`);
}
}
}
}
// Post comment if there are warnings
if (warnings.length > 0) {
const commentBody = '## ⚠️ PR Validation Warnings\n\n' +
warnings.join('\n\n') + '\n\n' +
'---\n\n' +
'**Note**: This PR can remain open, but please address these issues to ensure a smooth review process. For more information, see our [Contributing Guide](CONTRIBUTING.md).';
// Check if we already posted a comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number
});
const botComment = comments.data.find(
c => c.user.type === 'Bot' && c.body.includes('PR Validation Warnings')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: commentBody
});
}
} else {
// Remove any existing warning comments if validation passes
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number
});
const botComment = comments.data.find(
c => c.user.type === 'Bot' && c.body.includes('PR Validation Warnings')
);
if (botComment) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id
});
}
}