Skip to content

Commit ac56db5

Browse files
committed
lint: ensure all files are owned by someone
1 parent 76a6e7b commit ac56db5

File tree

2 files changed

+231
-65
lines changed

2 files changed

+231
-65
lines changed

.github/CODEOWNERS

Lines changed: 169 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,177 @@
11
# Angular Material components
2-
src/lib/list/** @jelbourn @crisbeto
3-
src/lib/tooltip/** @andrewseguin
4-
src/lib/button-toggle/** @tinayuangao
5-
src/lib/snack-bar/** @jelbourn @crisbeto @josephperrott
6-
src/lib/radio/** @tinayuangao @devversion
7-
src/lib/card/** @jelbourn
8-
src/lib/input/** @mmalerba
9-
src/lib/progress-spinner/** @jelbourn @crisbeto @josephperrott
10-
src/lib/datepicker/** @mmalerba
11-
src/lib/sort/** @andrewseguin
12-
src/lib/autocomplete/** @kara @crisbeto
13-
src/lib/chips/** @tinayuangao
14-
src/lib/icon/** @jelbourn
15-
src/lib/dialog/** @jelbourn @crisbeto
16-
src/lib/progress-bar/** @jelbourn @crisbeto @josephperrott
17-
src/lib/grid-list/** @kara @jelbourn
18-
src/lib/select/** @kara @crisbeto
19-
src/lib/expansion/** @josephperrott @jelbourn
20-
src/lib/slide-toggle/** @devversion
21-
src/lib/toolbar/** @devversion
22-
src/lib/button/** @tinayuangao
23-
src/lib/checkbox/** @tinayuangao @devversion
24-
src/lib/table/** @andrewseguin
25-
src/lib/slider/** @mmalerba
26-
src/lib/sidenav/** @mmalerba
27-
src/lib/menu/** @kara @crisbeto
28-
src/lib/paginator/** @andrewseguin
29-
src/lib/tabs/** @andrewseguin
2+
/src/lib/* @jelbourn
3+
/src/lib/autocomplete/** @kara @crisbeto
4+
/src/lib/button-toggle/** @tinayuangao
5+
/src/lib/button/** @tinayuangao
6+
/src/lib/card/** @jelbourn
7+
/src/lib/checkbox/** @tinayuangao @devversion
8+
/src/lib/chips/** @tinayuangao
9+
/src/lib/datepicker/** @mmalerba
10+
/src/lib/dialog/** @jelbourn @crisbeto
11+
/src/lib/expansion/** @josephperrott @jelbourn
12+
/src/lib/form-field/** @mmalerba
13+
/src/lib/grid-list/** @kara @jelbourn
14+
/src/lib/icon/** @jelbourn
15+
/src/lib/input/** @mmalerba
16+
/src/lib/list/** @jelbourn @crisbeto
17+
/src/lib/menu/** @kara @crisbeto
18+
/src/lib/paginator/** @andrewseguin
19+
/src/lib/progress-bar/** @jelbourn @crisbeto @josephperrott
20+
/src/lib/progress-spinner/** @jelbourn @crisbeto @josephperrott
21+
/src/lib/radio/** @tinayuangao @devversion
22+
/src/lib/select/** @kara @crisbeto
23+
/src/lib/sidenav/** @mmalerba
24+
/src/lib/slide-toggle/** @devversion
25+
/src/lib/slider/** @mmalerba
26+
/src/lib/snack-bar/** @jelbourn @crisbeto @josephperrott
27+
/src/lib/sort/** @andrewseguin
28+
/src/lib/stepper/** @mmalerba
29+
/src/lib/table/** @andrewseguin
30+
/src/lib/tabs/** @andrewseguin
31+
/src/lib/toolbar/** @devversion
32+
/src/lib/tooltip/** @andrewseguin
3033

3134
# Angular Material core
32-
src/lib/core/selection/** @tinayuangao @jelbourn
33-
src/lib/core/selection/pseudo*/** @crisbeto @jelbourn
34-
src/lib/core/theming/** @jelbourn
35-
src/lib/core/option/** @kara @crisbeto
36-
src/lib/core/rxjs/** @jelbourn
37-
src/lib/core/ripple/** @devversion
38-
src/lib/core/a11y/** @jelbourn @devversion
39-
src/lib/core/compatibility/** @jelbourn
40-
src/lib/core/overlay/** @jelbourn @crisbeto
41-
src/lib/core/overlay/scroll/** @andrewseguin @crisbeto
42-
src/lib/core/platform/** @jelbourn @devversion
43-
src/lib/core/bidi/** @jelbourn
44-
src/lib/core/placeholder/** @kara @mmalerba
45-
src/lib/core/portal/** @jelbourn
46-
src/lib/core/typography/** @crisbeto
47-
src/lib/core/datetime/** @mmalerba
35+
/src/lib/core/* @jelbourn
36+
/src/lib/core/animation/** @jelbourn
37+
/src/lib/core/common-behaviors/** @jelbourn
38+
/src/lib/core/compatibility/** @jelbourn
39+
/src/lib/core/datetime/** @mmalerba
40+
/src/lib/core/error/** @crisbeto @mmalerba
41+
/src/lib/core/gestures/** @jelbourn
42+
/src/lib/core/line/** @jelbourn
43+
/src/lib/core/option/** @kara @crisbeto
44+
/src/lib/core/placeholder/** @kara @mmalerba
45+
/src/lib/core/ripple/** @devversion
46+
/src/lib/core/selection/** @tinayuangao @jelbourn
47+
/src/lib/core/selection/pseudo*/** @crisbeto @jelbourn
48+
/src/lib/core/style/** @jelbourn
49+
/src/lib/core/testing/** @jelbourn
50+
/src/lib/core/theming/** @jelbourn
51+
/src/lib/core/typography/** @crisbeto
52+
/src/lib/core/util/** @jelbourn
4853

4954
# CDK
50-
src/cdk/coercion/** @jelbourn
51-
src/cdk/rxjs/** @jelbourn
52-
src/cdk/observers/** @jelbourn @crisbeto
53-
src/cdk/collections/** @jelbourn @crisbeto @andrewseguin
54-
src/cdk/a11y/** @jelbourn @devversion
55-
src/cdk/platform/** @jelbourn @devversion
56-
src/cdk/bidi/** @jelbourn
57-
src/cdk/table/** @andrewseguin
58-
src/cdk/portal/** @jelbourn
55+
/src/cdk/* @jelbourn
56+
/src/cdk/a11y/** @jelbourn @devversion
57+
/src/cdk/accordion/** @josephperrott
58+
/src/cdk/bidi/** @jelbourn
59+
/src/cdk/coercion/** @jelbourn
60+
/src/cdk/collections/** @jelbourn @crisbeto @andrewseguin
61+
/src/cdk/keycodes/** @jelbourn
62+
/src/cdk/layout/** @josephperrott
63+
/src/cdk/observers/** @jelbourn @crisbeto
64+
/src/cdk/overlay/** @jelbourn @crisbeto
65+
/src/cdk/platform/** @jelbourn @devversion
66+
/src/cdk/portal/** @jelbourn
67+
/src/cdk/rxjs/** @jelbourn
68+
/src/cdk/scrolling/** @andrewseguin @crisbeto
69+
/src/cdk/stepper/** @mmalerba
70+
/src/cdk/table/** @andrewseguin
71+
/src/cdk/testing/** @devversion
5972

60-
# Tooling
61-
tools/** @devversion @jelbourn
62-
test/** @devversion @jelbourn
63-
scripts/** @devversion @jelbourn
73+
# Moment adapter package
74+
/src/material-moment-adapter/** @mmalerba
6475

65-
# Docs examples
66-
src/material-examples/** @amcdnl @jelbourn
76+
# Docs examples & guides
77+
/guides/** @amcdnl @jelbourn
78+
/src/material-examples/** @amcdnl @jelbourn
6779

68-
# Moment adapter package
69-
src/material-moment-adapter/** @mmalerba
80+
# Demo app
81+
/src/demo-app/* @jelbourn
82+
/src/demo-app/a11y/** @tinayuangao
83+
/src/demo-app/autocomplete/** @kara @crisbeto
84+
/src/demo-app/baseline/** @mmalerba
85+
/src/demo-app/button-toggle/** @tinayuangao
86+
/src/demo-app/button/** @tinayuangao
87+
/src/demo-app/card/** @jelbourn
88+
/src/demo-app/checkbox/** @tinayuangao @devversion
89+
/src/demo-app/chips/** @tinayuangao
90+
/src/demo-app/dataset/** @andrewseguin
91+
/src/demo-app/datepicker/** @mmalerba
92+
/src/demo-app/demo-app/** @jelbourn
93+
/src/demo-app/dialog/** @jelbourn @crisbeto
94+
/src/demo-app/drawer/** @mmalerba
95+
/src/demo-app/expansion/** @josephperrott
96+
/src/demo-app/focus-origin/** @mmalerba
97+
/src/demo-app/gestures/** @jelbourn
98+
/src/demo-app/grid-list/** @kara @jelbourn
99+
/src/demo-app/icon/** @jelbourn
100+
/src/demo-app/input/** @mmalerba
101+
/src/demo-app/list/** @jelbourn @crisbeto
102+
/src/demo-app/live-announcer/** @jelbourn
103+
/src/demo-app/menu/** @kara @crisbeto
104+
/src/demo-app/overlay/** @jelbourn @crisbeto
105+
/src/demo-app/platform/** @jelbourn @devversion
106+
/src/demo-app/portal/** @jelbourn
107+
/src/demo-app/progress-bar/** @jelbourn @crisbeto @josephperrott
108+
/src/demo-app/progress-spinner/** @jelbourn @crisbeto @josephperrott
109+
/src/demo-app/radio/** @tinayuangao @devversion
110+
/src/demo-app/ripple/** @devversion
111+
/src/demo-app/screen-type/** @josephperrott
112+
/src/demo-app/select/** @kara @crisbeto
113+
/src/demo-app/sidenav/** @mmalerba
114+
/src/demo-app/slide-toggle/** @devversion
115+
/src/demo-app/slider/** @mmalerba
116+
/src/demo-app/snack-bar/** @jelbourn @crisbeto @josephperrott
117+
/src/demo-app/stepper/** @mmalerba
118+
/src/demo-app/table/** @andrewseguin
119+
/src/demo-app/tabs/** @andrewseguin
120+
/src/demo-app/toolbar/** @devversion
121+
/src/demo-app/tooltip/** @andrewseguin
122+
/src/demo-app/typography/** @crisbeto
123+
124+
# E2E app
125+
/e2e/* @jelbourn
126+
/e2e/components/block-scroll-strategy-e2e.spec.ts @andrewseguin @crisbeto
127+
/e2e/components/button-e2e.spec.ts @tinayuangao
128+
/e2e/components/button-toggle-e2e.spec.ts @tinayuangao
129+
/e2e/components/card-e2e.spec.ts @jelbourn
130+
/e2e/components/checkbox-e2e.spec.ts @tinayuangao @devversion
131+
/e2e/components/dialog-e2e.spec.ts @jelbourn @crisbeto
132+
/e2e/components/expansion-e2e.spec.ts @josephperrott @jelbourn
133+
/e2e/components/fullscreen-e2e.spec.ts @jelbourn
134+
/e2e/components/grid-list-e2e.spec.ts @kara @jelbourn
135+
/e2e/components/icon-e2e.spec.ts @jelbourn
136+
/e2e/components/input-e2e.spec.ts @mmalerba
137+
/e2e/components/list-e2e.spec.ts @jelbourn @crisbeto
138+
/e2e/components/menu-e2e.spec.ts @kara @crisbeto
139+
/e2e/components/progress-bar-e2e.spec.ts @jelbourn @crisbeto @josephperrott
140+
/e2e/components/progress-spinner-e2e.spec.ts @jelbourn @crisbeto @josephperrott
141+
/e2e/components/radio-e2e.spec.ts @tinayuangao @devversion
142+
/e2e/components/sidenav-e2e.spec.ts @mmalerba
143+
/e2e/components/slide-toggle-e2e.spec.ts @devversion
144+
/e2e/components/stepper-e2e.spec.ts @mmalerba
145+
/e2e/components/tabs-e2e.spec.ts @andrewseguin
146+
/e2e/components/toolbar-e2e.spec.ts @devversion
147+
/e2e/util/** @jelbourn
148+
/src/e2e-app/* @jelbourn
149+
/src/e2e-app/block-scroll-strategy/** @andrewseguin @crisbeto
150+
/src/e2e-app/button/** @tinayuangao
151+
/src/e2e-app/checkbox/** @tinayuangao @devversion
152+
/src/e2e-app/dialog/** @jelbourn @crisbeto
153+
/src/e2e-app/e2e-app/** @jelbourn
154+
/src/e2e-app/fullscreen/** @jelbourn
155+
/src/e2e-app/grid-list/** @kara @jelbourn
156+
/src/e2e-app/icon/** @jelbourn
157+
/src/e2e-app/input/** @mmalerba
158+
/src/e2e-app/menu/** @kara @crisbeto
159+
/src/e2e-app/progress-bar/** @jelbourn @crisbeto @josephperrott
160+
/src/e2e-app/progress-spinner/** @jelbourn @crisbeto @josephperrott
161+
/src/e2e-app/radio/** @tinayuangao @devversion
162+
/src/e2e-app/sidenav/** @mmalerba
163+
/src/e2e-app/slide-toggle/** @devversion
164+
/src/e2e-app/tabs/** @andrewseguin
165+
166+
# Universal app
167+
/src/universal-app/** @jelbourn
168+
169+
# Tooling
170+
/scripts/** @devversion @jelbourn
171+
/test/** @devversion @jelbourn
172+
/tools/** @devversion @jelbourn
173+
174+
# Misc
175+
/* @jelbourn
176+
/.github/** @jelbourn
177+
/src/* @jelbourn

tools/gulp/tasks/lint.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import {red} from 'chalk';
2+
import {readdirSync, readFileSync, statSync} from 'fs';
13
import {task} from 'gulp';
2-
import {execNodeTask} from '../util/task_helpers';
3-
import {join} from 'path';
44
import {buildConfig} from 'material2-build-tools';
5-
import {red} from 'chalk';
5+
import {IMinimatch, Minimatch} from 'minimatch';
6+
import {join} from 'path';
7+
import {execNodeTask} from '../util/task_helpers';
68

79
// These types lack of type definitions
810
const madge = require('madge');
@@ -19,7 +21,13 @@ const materialOutPath = join(buildConfig.outputDir, 'packages', 'material');
1921
/** Path to the output of the CDK package. */
2022
const cdkOutPath = join(buildConfig.outputDir, 'packages', 'cdk');
2123

22-
task('lint', ['tslint', 'stylelint', 'madge']);
24+
/** Path for the Github owners file. */
25+
const ownersFilePath = '.github/CODEOWNERS';
26+
27+
/** Paths that should be ignored when checking for owners coverage. */
28+
const ignoreOwners = ['/node_modules/**', '/dist/**', '/.git/**', '/.idea/**'];
29+
30+
task('lint', ['tslint', 'stylelint', 'madge', 'ownerslint']);
2331

2432
/** Task to lint Angular Material's scss stylesheets. */
2533
task('stylelint', execNodeTask(
@@ -46,6 +54,56 @@ task('madge', ['material:clean-build'], () => {
4654
});
4755
});
4856

57+
task('ownerslint', () => {
58+
let errors = 0;
59+
60+
let ownedPaths = readFileSync(ownersFilePath, 'utf8').split('\n')
61+
// Trim lines.
62+
.map(line => line.trim())
63+
// Remove empty lines and comments.
64+
.filter(line => line && !line.startsWith('#'))
65+
// Split off just the path glob and turn it into a regex.
66+
.map(line => new Minimatch(line.split(/\s+/)[0], {dot: true, matchBase: true}))
67+
// Add in the paths we're ignoring.
68+
.concat(ignoreOwners.map(path => new Minimatch(path, {dot: true, matchBase: true})));
69+
70+
for (let paths = getChildPaths('.'); paths.length;) {
71+
paths = Array.prototype.concat(...paths
72+
// Remove paths that match an owned path.
73+
.filter(path => !ownedPaths.reduce(
74+
(isOwned, ownedPath) => isOwned || isOwnedBy(path, ownedPath), false))
75+
// Report an error for any files that didn't match any owned paths.
76+
.filter(path => {
77+
if (statSync(path).isFile()) {
78+
console.error(red(`No code owner found for "${path}".`));
79+
errors++;
80+
return false;
81+
}
82+
return true;
83+
})
84+
// Get the next level of children for any directories.
85+
.map(path => getChildPaths(path)));
86+
}
87+
88+
if (errors) {
89+
throw Error(`Found ${errors} files with no owner.`);
90+
}
91+
});
92+
93+
/** Check if the given path is owned by the given owned path matcher. */
94+
function isOwnedBy(path: string, ownedPath: IMinimatch) {
95+
// If the owned path ends with `**` its safe to eliminate whole directories.
96+
if (statSync(path).isFile() || ownedPath.pattern.endsWith('**')) {
97+
return ownedPath.match('/' + path);
98+
}
99+
return false;
100+
}
101+
102+
/** Get the immediate child paths of the given path. */
103+
function getChildPaths(path: string) {
104+
return readdirSync(path).map(child => join(path, child));
105+
}
106+
49107
/** Returns a string that formats the graph of circular modules. */
50108
function formatMadgeCircularModules(circularModules: string[][]): string {
51109
return circularModules.map((modulePaths: string[]) => `\n - ${modulePaths.join(' > ')}`).join('');

0 commit comments

Comments
 (0)