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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
- name: Advanced PR Comment
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('lint-report.json', 'utf8'));
// Build detailed comment
let comment = '## š Documentation Lint Report\n\n';
// Summary with status emoji
if (report.summary.errors === 0 && report.summary.warnings === 0) {
comment += 'ā
**All documentation passes linting!**\n\n';
} else {
if (report.summary.errors > 0) {
comment += `ā **${report.summary.errors} error(s) found** - merge blocked\n`;
}
if (report.summary.warnings > 0) {
comment += `ā ļø **${report.summary.warnings} warning(s) found** - should fix\n`;
}
comment += '\n';
}
comment += `š **Summary:** ${report.summary.total_files} files scanned\n\n`;
// Group issues by file
if (report.issues && report.issues.length > 0) {
comment += '### Issues Found\n\n';
const byFile = {};
for (const issue of report.issues) {
if (!byFile[issue.file]) byFile[issue.file] = [];
byFile[issue.file].push(issue);
}
// Show up to 10 files with most severe issues first
const files = Object.keys(byFile)
.sort((a, b) => {
const aErrors = byFile[a].filter(i => i.severity === 'error').length;
const bErrors = byFile[b].filter(i => i.severity === 'error').length;
return bErrors - aErrors;
})
.slice(0, 10);
for (const file of files) {
const issues = byFile[file];
const errorCount = issues.filter(i => i.severity === 'error').length;
const warnCount = issues.filter(i => i.severity === 'warning').length;
comment += `<details>\n`;
comment += `<summary><code>${file}</code> - `;
if (errorCount > 0) comment += `${errorCount} error(s) `;
if (warnCount > 0) comment += `${warnCount} warning(s)`;
comment += `</summary>\n\n`;
for (const issue of issues.slice(0, 5)) {
const emoji = issue.severity === 'error' ? 'ā' : 'ā ļø';
const lineLink = issue.line > 0
? `[L${issue.line}](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${context.payload.pull_request.head.sha}/${issue.file}#L${issue.line})`
: 'File-level';
comment += `${emoji} **${issue.rule}** (${lineLink})\n`;
comment += `> ${issue.message}\n`;
if (issue.suggestion) {
comment += `> š” Suggestion: \`${issue.suggestion}\`\n`;
}
comment += '\n';
}
if (issues.length > 5) {
comment += `... and ${issues.length - 5} more issue(s)\n`;
}
comment += `</details>\n\n`;
}
if (Object.keys(byFile).length > 10) {
comment += `*... and ${Object.keys(byFile).length - 10} more file(s) with issues*\n\n`;
}
}
// Broken links section
if (report.broken_links && report.broken_links.length > 0) {
comment += `### š Broken Links (${report.broken_links.length})\n\n`;
for (const link of report.broken_links.slice(0, 10)) {
const lineLink = `[${link.source_file}:${link.line}](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/${context.payload.pull_request.head.sha}/${link.source_file}#L${link.line})`;
comment += `- ${lineLink}: \`${link.target}\`\n`;
comment += ` *${link.error}*\n`;
}
if (report.broken_links.length > 10) {
comment += `\n*... and ${report.broken_links.length - 10} more broken link(s)*\n`;
}
comment += '\n';
}
// Instructions
comment += '---\n\n';
comment += '### How to Fix\n\n';
comment += '```bash\n';
comment += '# Review all issues\n';
comment += 'docbuilder lint\n\n';
comment += '# Auto-fix where possible\n';
comment += 'docbuilder lint --fix\n\n';
comment += '# Preview changes without applying\n';
comment += 'docbuilder lint --fix --dry-run\n';
comment += '```\n\n';
comment += '*š” Tip: The pre-commit hook will prevent future issues*\n';
comment += '```bash\n';
comment += 'docbuilder lint install-hook\n';
comment += '```\n';
// Post or update comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const botComment = comments.find(c =>
c.user.type === 'Bot' &&
c.body.includes('Documentation Lint Report')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: comment
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
}
|