forked from angular/components
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathownerslint.ts
86 lines (77 loc) · 2.63 KB
/
ownerslint.ts
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
import chalk from 'chalk';
import {readdirSync, readFileSync, statSync} from 'fs';
import {IMinimatch, Minimatch} from 'minimatch';
import {join} from 'path';
/**
* Script that lints the CODEOWNERS file and makes sure that all files have an owner.
*/
/** Path for the Github owners file. */
const ownersFilePath = '.github/CODEOWNERS';
/** Path for the .gitignore file. */
const gitIgnorePath = '.gitignore';
let errors = 0;
const ownedPaths = readFileSync(ownersFilePath, 'utf8')
.split('\n')
// Trim lines.
.map(line => line.trim())
// Remove empty lines and comments.
.filter(line => line && !line.startsWith('#'))
// Split off just the path glob.
.map(line => line.split(/\s+/)[0])
// Turn paths into Minimatch objects.
.map(path => new Minimatch(path, {dot: true, matchBase: true}));
const ignoredPaths = readFileSync(gitIgnorePath, 'utf8')
.split('\n')
// Trim lines.
.map(line => line.trim())
// Remove empty lines and comments.
.filter(line => line && !line.startsWith('#'))
// Turn paths into Minimatch objects.
.map(path => new Minimatch(path, {dot: true, matchBase: true}));
for (let paths = getChildPaths('.'); paths.length; ) {
paths = Array.prototype.concat(
...paths
// Remove ignored paths
.filter(
path =>
!ignoredPaths.reduce(
(isIgnored, ignoredPath) => isIgnored || ignoredPath.match('/' + path),
false,
),
)
// Remove paths that match an owned path.
.filter(
path =>
!ownedPaths.reduce((isOwned, ownedPath) => isOwned || isOwnedBy(path, ownedPath), false),
)
// Report an error for any files that didn't match any owned paths.
.filter(path => {
if (statSync(path).isFile()) {
console.log(chalk.red(`No code owner found for "${path}".`));
errors++;
return false;
}
return true;
})
// Get the next level of children for any directories.
.map(path => getChildPaths(path)),
);
}
if (errors) {
throw Error(
`Found ${errors} files with no owner. Code owners for the files ` +
`should be added in the CODEOWNERS file.`,
);
}
/** Check if the given path is owned by the given owned path matcher. */
function isOwnedBy(path: string, ownedPath: IMinimatch) {
// If the owned path ends with `**` its safe to eliminate whole directories.
if (ownedPath.pattern.endsWith('**') || statSync(path).isFile()) {
return ownedPath.match('/' + path);
}
return false;
}
/** Get the immediate child paths of the given path. */
function getChildPaths(path: string) {
return readdirSync(path).map(child => join(path, child));
}