-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdangerfile.js
More file actions
91 lines (77 loc) · 2.87 KB
/
Copy pathdangerfile.js
File metadata and controls
91 lines (77 loc) · 2.87 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
// dangerfile.js — enforces the PR description template
// Docs: https://danger.systems/js/
const body = danger.github.pr.body || "";
const normalizedBody = body.replace(/\r\n/g, "\n");
const issues = [];
function escapeRegex(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function hasCheckedChecklistItem(itemText) {
const escapedItem = escapeRegex(itemText).replace(/\s+/g, "\\s+");
const checkedItemPattern = new RegExp(`-\\s*\\[[xX]\\]\\s*${escapedItem}`, "i");
return checkedItemPattern.test(normalizedBody);
}
// ---------------------------------------------------------------------------
// 1. Required section headings (tolerant to spacing and casing)
// ---------------------------------------------------------------------------
const requiredSections = [
{
label: "### Addressed Issues:",
pattern: /#{3}\s+addressed\s+issues:/i,
},
{
label: "## Checklist",
pattern: /#{2}\s+checklist/i,
},
];
const missingSections = requiredSections
.filter((section) => !section.pattern.test(normalizedBody))
.map((section) => section.label);
if (!normalizedBody.trim()) {
fail("PR description is empty. Please follow the PR template.");
}
if (missingSections.length > 0) {
issues.push(
`**PR description is missing required sections:**\n` +
missingSections.map((s) => `- \`${s}\``).join("\n") +
`\n\nPlease follow the [PR template](.github/PULL_REQUEST_TEMPLATE.md).`
);
}
// ---------------------------------------------------------------------------
// 2. Issue link — warn on placeholder and missing issue reference
// ---------------------------------------------------------------------------
if (/\bfixes\s*#\s*\(\s*issue\s*number\s*\)/i.test(normalizedBody)) {
issues.push(
"Please replace the placeholder `Fixes #(issue number)` with the actual " +
"issue number (e.g. `Fixes #42`)."
);
} else if (!/\b(fixes|closes|resolves)\s*#\d+\b/i.test(normalizedBody)) {
issues.push(
"No issue linked. Consider adding `Fixes #<number>` (e.g. `Fixes #42`) " +
"under the **Addressed Issues** section."
);
}
// ---------------------------------------------------------------------------
// 3. Checklist — required items must be checked
// ---------------------------------------------------------------------------
const requiredChecklistItems = [
"My PR addresses a single issue",
"My code follows the project's code style",
"My changes generate no new warnings or errors",
];
const missingRequired = requiredChecklistItems.filter(
(item) => !hasCheckedChecklistItem(item)
);
if (missingRequired.length > 0) {
issues.push(
"Some required checklist items are not completed:\n" +
missingRequired.map((item) => `- ${item}`).join("\n")
);
}
if (issues.length > 0) {
message(`
### ⚠️ PR Template Check
These are non-blocking, but please fix:
${issues.map((issue) => `- ${issue}`).join("\n")}
`);
}