-
Notifications
You must be signed in to change notification settings - Fork 26
/
index.js
executable file
·121 lines (99 loc) · 3.18 KB
/
index.js
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
#!/usr/bin/env node
/* eslint-disable no-console */
// @ts-check
const findUp = require('find-up');
const fs = require('fs');
const ignore = require('ignore');
const intersection = require('lodash.intersection');
const padEnd = require('lodash.padend');
const path = require('path');
const program = require('commander');
const { walkStream } = require('@nodelib/fs.walk');
const Codeowners = require('./codeowners.js');
const rootPath = process.cwd();
const gitignorePath = findUp.sync('.gitignore', { cwd: rootPath });
const gitignoreMatcher = ignore();
if (gitignorePath) {
gitignoreMatcher.add(fs.readFileSync(gitignorePath).toString());
}
program
.command('audit')
.description('list the owners for all files')
.option('-u, --unowned', 'unowned files only')
.option('-w, --width <columns>', 'how much should filenames be padded?', '32')
.option(
'-c, --codeowners-filename <codeowners_filename>',
'specify CODEOWNERS filename',
'CODEOWNERS'
)
.action((options) => {
let codeowners;
try {
codeowners = new Codeowners(rootPath, options.codeownersFilename);
} catch (e) {
console.error(e.message);
process.exit(1);
}
const padding = parseInt(options.width, 10);
const stream = walkStream(rootPath, {
deepFilter: (entry) => {
const split = entry.path.split(path.sep);
return !split.includes('node_modules') && !split.includes('.git') && !split.includes('.cache');
},
errorFilter: (error) =>
error.code === 'ENOENT' || error.code === 'EACCES' || error.code === 'EPERM',
});
stream.on('data', (file) => {
const relative = path
.relative(codeowners.codeownersDirectory, file.path)
.replace(/(\r)/g, '\\r');
const owners = codeowners.getOwner(relative);
if (options.unowned) {
if (!owners.length) {
console.log(relative);
}
} else {
console.log(
`${padEnd(relative, padding)} ${owners.length ? owners.join(' ') : 'nobody'}`
);
}
});
stream.on('error', (err) => {
console.error(err);
});
});
program
.command('verify <path> <users...>')
.description('verify users/teams own a specific path')
.option(
'-c, --codeowners-filename <codeowners_filename>',
'specify CODEOWNERS filename',
'CODEOWNERS'
)
.action((checkPath, users, options) => {
let codeowners;
// instantiate new Codeowners obj
try {
codeowners = new Codeowners(rootPath, options.codeownersFilename);
} catch (e) {
console.error(e.message);
process.exit(1);
}
// call getOwner() on `path`
const owners = codeowners.getOwner(checkPath);
// check if any `users` are in the results of getOwner()
const verifiedOwners = intersection(users, owners);
// if verifiedOwners is empty, exit with error
if (verifiedOwners.length < 1) {
console.log(`None of the users/teams specified own the path ${checkPath}`);
process.exit(1);
}
// print owners
for (const currOwner of verifiedOwners) {
console.log(`${checkPath} ${currOwner}`);
}
});
if (!process.argv.slice(2).length) {
program.outputHelp();
}
program.parse(process.argv);