@@ -19,10 +19,20 @@ function escapeRegExp(string) {
1919const 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+ }
2226const 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
2838const files = gitFiles . split ( '\n' ) ;
@@ -49,19 +59,23 @@ const allScripts = filteredFiles.concat(subdirectories);
4959// Initialize a counter for the number of issues
5060let 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
5369allScripts . 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
6176allScripts . forEach ( file => {
6277 if ( ! / ^ ( [ a - z 0 - 9 ] + - ) * [ a - z 0 - 9 ] + ( \. [ a - z 0 - 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
100114const 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
103121const regex = new RegExp ( `${ escapeRegExp ( headingLevel ) } .*` , 'g' ) ;
104122const 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
107130headings . 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
146166if ( 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