Skip to content

Commit dd160a5

Browse files
committed
feat: enhance linting script
- improved error handling - a running count for each issue - adding emojis for each type of syntax issue
1 parent e18c383 commit dd160a5

File tree

1 file changed

+39
-18
lines changed

1 file changed

+39
-18
lines changed

.github/scripts/lint-readme.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,20 @@ function escapeRegExp(string) {
1919
const readmePath = path.join(directoryPath, 'README.md');
2020

2121
// Read README.md content
22+
if (!fs.existsSync(readmePath)) {
23+
console.log(`README.md not found at ${readmePath}`);
24+
process.exit(1);
25+
}
2226
const readme = fs.readFileSync(readmePath, 'utf8');
2327

2428
// Get all files tracked by Git
25-
const gitFiles = execSync('git ls-files', { cwd: directoryPath, encoding: 'utf-8' });
29+
let gitFiles;
30+
try {
31+
gitFiles = execSync('git ls-files', { cwd: directoryPath, encoding: 'utf-8' });
32+
} catch (error) {
33+
console.log(`Error running git ls-files in ${directoryPath}: ${error.message}`);
34+
process.exit(1);
35+
}
2636

2737
// Split the output into an array of file paths
2838
const files = gitFiles.split('\n');
@@ -49,19 +59,23 @@ const allScripts = filteredFiles.concat(subdirectories);
4959
// Initialize a counter for the number of issues
5060
let issueCount = 0;
5161

62+
// Helper function to log numbered issues
63+
function logIssue(message) {
64+
issueCount++;
65+
console.log(`${issueCount}. ${message}`);
66+
}
67+
5268
// Check if each .sh file is mentioned in the README.md
5369
allScripts.forEach(file => {
5470
if (!readme.includes(`${headingLevel} ${file}`)) {
55-
console.log(`The file ${file} is not mentioned in the README.md`);
56-
issueCount++;
71+
logIssue(`📝 The file ${file} is not mentioned in the README.md`);
5772
}
5873
});
5974

6075
// Check that all files follow the kebab-case naming convention
6176
allScripts.forEach(file => {
6277
if (!/^([a-z0-9]+-)*[a-z0-9]+(\.[a-z0-9]+)*$/.test(file)) {
63-
console.log(`The file ${file} does not follow the kebab-case naming convention`);
64-
issueCount++;
78+
logIssue(`🔤 The file ${file} does not follow the kebab-case naming convention`);
6579
}
6680
});
6781

@@ -76,8 +90,7 @@ allScripts.forEach(file => {
7690
const isExecutable = (stats.mode & fs.constants.X_OK) !== 0;
7791

7892
if (!isExecutable) {
79-
console.log(`The file ${file} does not have execution permissions`);
80-
issueCount++;
93+
logIssue(`🔒 The file ${file} does not have execution permissions`);
8194
}
8295
});
8396

@@ -91,24 +104,33 @@ allScripts.forEach(file => {
91104
try {
92105
execSync(`bash -n "${filePath}"`, { stdio: 'pipe' });
93106
} catch (error) {
94-
console.log(`Bash syntax error in ${file}: ${error.stderr.toString().trim()}`);
95-
issueCount++;
107+
logIssue(`🐛 The file ${file} has a bash syntax error`);
108+
const errorLines = error.stderr.toString().trim().split('\n');
109+
errorLines.forEach(line => console.log(` ${line}`));
96110
}
97111
});
98112

99113
// Extract the part of the README under the ## Scripts heading
100114
const scriptsSection = readme.split(`${parentHeading}\n`)[1];
115+
if (!scriptsSection) {
116+
console.log(`Section "${parentHeading}" not found in README.md`);
117+
process.exit(1);
118+
}
101119

102120
// Extract all ### headings from the scripts section
103121
const regex = new RegExp(`${escapeRegExp(headingLevel)} .*`, 'g');
104122
const headings = scriptsSection.match(regex);
105123

124+
if (!headings || headings.length === 0) {
125+
console.log(`No headings found with level "${headingLevel}" in the scripts section`);
126+
process.exit(1);
127+
}
128+
106129
// Check that all scripts mentioned in the README.md actually exist in the repository
107130
headings.forEach(heading => {
108131
const script = heading.slice(headingLevel.length + 1); // Remove the '### ' prefix
109132
if (!allScripts.includes(script)) {
110-
console.log(`The script ${script} is mentioned in the README.md but does not exist in the repository`);
111-
issueCount++;
133+
logIssue(`📁 The script ${script} is mentioned in the README.md but does not exist in the repository`);
112134
}
113135
});
114136

@@ -124,8 +146,7 @@ allScripts.forEach(file => {
124146
Object.keys(shortWords).forEach(word => {
125147
const regex = new RegExp(`\\b${word}\\b`, 'g');
126148
if (regex.test(file)) {
127-
console.log(`The file name "${file}" uses the short word "${word}". Consider using "${shortWords[word]}" instead.`);
128-
issueCount++;
149+
logIssue(`📏 The file name "${file}" uses the short word "${word}". Consider using "${shortWords[word]}" instead.`);
129150
}
130151
});
131152
});
@@ -136,16 +157,16 @@ for (let i = 0; i < headings.length - 1; i++) {
136157
const next = headings[i + 1].toLowerCase();
137158

138159
if (next.startsWith(current + '-') || (current > next && !current.startsWith(next + '-'))) {
139-
console.log(`The heading "${headings[i + 1]}" is out of order. It should come before "${headings[i]}".`);
140-
issueCount++;
160+
logIssue(`📋 The heading "${headings[i + 1]}" is out of order. It should come before "${headings[i]}".`);
141161
break;
142162
}
143163
}
144164

145-
// If there are no issues, print a message
165+
// Output final summary
146166
if (issueCount === 0) {
147-
console.log('No issues found.');
167+
console.log('No issues found.');
148168
} else {
149-
console.log(`Found ${issueCount} issue(s). ❌`);
169+
console.log('');
170+
console.log(`❌ Found ${issueCount} issue${issueCount === 1 ? '' : 's'} that need to be addressed.`);
150171
process.exit(1);
151172
}

0 commit comments

Comments
 (0)