1
- #!/usr/bin/env node
2
- 'use strict' ;
1
+ /**
2
+ * @license
3
+ * Copyright Google Inc. All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.io/license
7
+ */
3
8
4
9
/**
5
10
* **Usage:**
6
11
* ```
7
- * node aio/scripts /verify-codeownership
12
+ * node tools /verify-codeownership
8
13
* ```
9
14
*
10
- * Verify whether there are directories in the codebase that don't have a codeowner (in `.github/CODEOWNERS`) and vice
11
- * versa (that there are no patterns in `CODEOWNERS` that do not correspond to actual directories).
15
+ * Verify whether there are directories in the codebase that don't have a codeowner (in
16
+ * `.github/CODEOWNERS`) and vice versa (that there are no patterns in `CODEOWNERS` that do not
17
+ * correspond to actual directories).
12
18
*
13
- * The script does not aim to be exhaustive and highly accurate, checking all files and directories (since that would be
14
- * too complicated). Instead, it does a coarse check on some important (or frequently changing) directories.
19
+ * The script does not aim to be exhaustive and highly accurate, checking all files and directories
20
+ * (since that would be too complicated). Instead, it does a coarse check on some important (or
21
+ * frequently changing) directories.
15
22
*
16
23
* Currently, it checks the following:
17
24
* - **Packages**: Top-level directories in `packages/`.
20
27
* - **Guide images**: Top-level directories in `aio/content/images/guide/`.
21
28
* - **Guide examples**: Top-level directories in `aio/content/examples/`.
22
29
*/
30
+ 'use strict' ;
23
31
24
32
// Imports
33
+ const chalk = require ( 'chalk' ) ;
25
34
const fs = require ( 'fs' ) ;
26
35
const path = require ( 'path' ) ;
27
36
28
37
// Constants
29
- const PROJECT_ROOT_DIR = path . resolve ( __dirname , '../.. ' ) ;
38
+ const PROJECT_ROOT_DIR = path . resolve ( __dirname , '..' ) ;
30
39
const CODEOWNERS_PATH = path . resolve ( PROJECT_ROOT_DIR , '.github/CODEOWNERS' ) ;
31
40
const PKG_DIR = path . resolve ( PROJECT_ROOT_DIR , 'packages' ) ;
32
41
const PKG_EXAMPLES_DIR = path . resolve ( PKG_DIR , 'examples' ) ;
@@ -45,7 +54,11 @@ _main();
45
54
// Functions - Definitions
46
55
function _main ( ) {
47
56
const { packages : pkgPackagePaths , examples : pkgExamplePaths } = getPathsFromPkg ( ) ;
48
- const { guides : aioGuidePaths , images : aioGuideImagesPaths , examples : aioExamplePaths } = getPathsFromAioContent ( ) ;
57
+ const {
58
+ guides : aioGuidePaths ,
59
+ images : aioGuideImagesPaths ,
60
+ examples : aioExamplePaths ,
61
+ } = getPathsFromAioContent ( ) ;
49
62
const {
50
63
pkgPackages : coPkgPackagePaths ,
51
64
pkgExamples : coPkgExamplePaths ,
@@ -60,7 +73,8 @@ function _main() {
60
73
const aioImagesDiff = arrayDiff ( aioGuideImagesPaths , coAioGuideImagesPaths ) ;
61
74
const aioExamplesDiff = arrayDiff ( aioExamplePaths , coAioExamplePaths ) ;
62
75
const hasDiff = ( pkgPackagesDiff . diffCount > 0 ) || ( pkgExamplesDiff . diffCount > 0 ) ||
63
- ( aioGuidesDiff . diffCount > 0 ) || ( aioImagesDiff . diffCount > 0 ) || ( aioExamplesDiff . diffCount > 0 ) ;
76
+ ( aioGuidesDiff . diffCount > 0 ) || ( aioImagesDiff . diffCount > 0 ) ||
77
+ ( aioExamplesDiff . diffCount > 0 ) ;
64
78
65
79
if ( hasDiff ) {
66
80
const expectedPkgPackagesSrc = path . relative ( PROJECT_ROOT_DIR , PKG_DIR ) ;
@@ -75,6 +89,16 @@ function _main() {
75
89
reportDiff ( aioGuidesDiff , expectedAioGuidesSrc , actualSrc ) ;
76
90
reportDiff ( aioImagesDiff , expectedAioImagesSrc , actualSrc ) ;
77
91
reportDiff ( aioExamplesDiff , expectedAioExamplesSrc , actualSrc ) ;
92
+
93
+ // tslint:disable-next-line: no-console
94
+ console . log ( chalk . red (
95
+ '\nCode-ownership verification failed.\n' +
96
+ 'Please update \'.github/CODEOWNERS\' to ensure that all necessary files/directories ' +
97
+ 'have code-owners and all patterns that appear in the file correspond to actual ' +
98
+ 'files/directories in the repo.' ) ) ;
99
+ } else {
100
+ // tslint:disable-next-line: no-console
101
+ console . log ( chalk . green ( '\nCode-ownership verification succeeded!' ) ) ;
78
102
}
79
103
80
104
process . exit ( hasDiff ? 1 : 0 ) ;
@@ -88,16 +112,16 @@ function arrayDiff(expected, actual) {
88
112
}
89
113
90
114
function findDirectories ( parentDir ) {
91
- return fs . readdirSync ( parentDir ) .
92
- filter ( name => fs . statSync ( `${ parentDir } /${ name } ` ) . isDirectory ( ) ) ;
115
+ return fs . readdirSync ( parentDir ) . filter (
116
+ name => fs . statSync ( `${ parentDir } /${ name } ` ) . isDirectory ( ) ) ;
93
117
}
94
118
95
119
function getPathsFromAioContent ( ) {
96
120
return {
97
121
guides : fs . readdirSync ( AIO_GUIDES_DIR ) ,
98
122
images : fs . readdirSync ( AIO_GUIDE_IMAGES_DIR ) ,
99
- examples : fs . readdirSync ( AIO_GUIDE_EXAMPLES_DIR ) .
100
- filter ( name => fs . statSync ( `${ AIO_GUIDE_EXAMPLES_DIR } /${ name } ` ) . isDirectory ( ) ) ,
123
+ examples : fs . readdirSync ( AIO_GUIDE_EXAMPLES_DIR )
124
+ . filter ( name => fs . statSync ( `${ AIO_GUIDE_EXAMPLES_DIR } /${ name } ` ) . isDirectory ( ) ) ,
101
125
} ;
102
126
}
103
127
@@ -106,7 +130,8 @@ function getPathsFromCodeowners() {
106
130
const pkgExamplesPathRe = / ^ \/ p a c k a g e s \/ e x a m p l e s \/ ( [ ^ \s \* / ] + ) / ;
107
131
// Use capturing groups for `images/` and `examples` to be able to differentiate between the
108
132
// different kinds of matches (guide, image, example) later (see `isImage`/`isExample` below).
109
- const aioGuidesImagesExamplesPathRe = / ^ \/ a i o \/ c o n t e n t \/ (?: ( i m a g e s \/ ) ? g u i d e | ( e x a m p l e s ) ) \/ ( [ ^ \s \* / ] + ) / ;
133
+ const aioGuidesImagesExamplesPathRe =
134
+ / ^ \/ a i o \/ c o n t e n t \/ (?: ( i m a g e s \/ ) ? g u i d e | ( e x a m p l e s ) ) \/ ( [ ^ \s \* / ] + ) / ;
110
135
const manualGlobExpansions = {
111
136
// `CODEOWNERS` has a glob to match all `testing/` directories, so no specific glob for
112
137
// `packages/examples/testing/` is necessary.
@@ -120,10 +145,7 @@ function getPathsFromCodeowners() {
120
145
const aioExamples = [ ] ;
121
146
122
147
// Read `CODEOWNERS` and split into lines.
123
- const lines = fs .
124
- readFileSync ( CODEOWNERS_PATH , 'utf8' ) .
125
- split ( '\n' ) .
126
- map ( l => l . trim ( ) ) ;
148
+ const lines = fs . readFileSync ( CODEOWNERS_PATH , 'utf8' ) . split ( '\n' ) . map ( l => l . trim ( ) ) ;
127
149
128
150
// Manually expand globs to known matching patterns.
129
151
for ( const [ glob , expansions ] of Object . entries ( manualGlobExpansions ) ) {
@@ -134,27 +156,22 @@ function getPathsFromCodeowners() {
134
156
}
135
157
136
158
// Collect packages (`packages/`).
137
- lines .
138
- map ( l => l . match ( pkgPackagesPathRe ) ) .
139
- filter ( m => m ) .
140
- forEach ( ( [ , path ] ) => pkgPackages . push ( path ) ) ;
159
+ lines . map ( l => l . match ( pkgPackagesPathRe ) ) . filter ( m => m ) . forEach ( ( [
160
+ , path
161
+ ] ) => pkgPackages . push ( path ) ) ;
141
162
142
163
// Collect API docs examples (`packages/examples/`).
143
- lines .
144
- map ( l => l . match ( pkgExamplesPathRe ) ) .
145
- filter ( m => m ) .
146
- forEach ( ( [ , path ] ) => pkgExamples . push ( path ) ) ;
164
+ lines . map ( l => l . match ( pkgExamplesPathRe ) ) . filter ( m => m ) . forEach ( ( [
165
+ , path
166
+ ] ) => pkgExamples . push ( path ) ) ;
147
167
148
168
// Collect `aio/` guides/images/examples.
149
- lines .
150
- map ( l => l . match ( aioGuidesImagesExamplesPathRe ) ) .
151
- filter ( m => m ) .
152
- forEach ( ( [ , isImage , isExample , path ] ) => {
153
- const list = isExample ? aioExamples :
154
- isImage ? aioImages :
155
- aioGuides ;
156
- list . push ( path ) ;
157
- } ) ;
169
+ lines . map ( l => l . match ( aioGuidesImagesExamplesPathRe ) )
170
+ . filter ( m => m )
171
+ . forEach ( ( [ , isImage , isExample , path ] ) => {
172
+ const list = isExample ? aioExamples : isImage ? aioImages : aioGuides ;
173
+ list . push ( path ) ;
174
+ } ) ;
158
175
159
176
return { pkgPackages, pkgExamples, aioGuides, aioImages, aioExamples} ;
160
177
}
0 commit comments