Skip to content

Commit 0ba5beb

Browse files
petebacondarwinIgorMinar
authored andcommitted
build: modularize the gulp file to be easier to maintain (angular#14259)
This is a precursor to bringing in some of the gulp tasks from angular.io, which could lead to the gulpfile becoming unwieldy.
1 parent a909643 commit 0ba5beb

14 files changed

+354
-264
lines changed

gulpfile.js

Lines changed: 22 additions & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -16,271 +16,29 @@ require('./tools/check-environment')({
1616
});
1717

1818
const gulp = require('gulp');
19-
const path = require('path');
20-
const os = require('os');
2119

22-
// clang-format entry points
23-
const srcsToFmt = [
24-
'modules/@angular/**/*.{js,ts}',
25-
'modules/benchmarks/**/*.{js,ts}',
26-
'modules/e2e_util/**/*.{js,ts}',
27-
'modules/playground/**/*.{js,ts}',
28-
'tools/**/*.{js,ts}',
29-
'!tools/public_api_guard/**/*.d.ts',
30-
'./*.{js,ts}',
31-
'!shims_for_IE.js',
32-
];
33-
34-
// Check source code for formatting errors (clang-format)
35-
gulp.task('format:enforce', () => {
36-
const format = require('gulp-clang-format');
37-
const clangFormat = require('clang-format');
38-
return gulp.src(srcsToFmt).pipe(
39-
format.checkFormat('file', clangFormat, {verbose: true, fail: true}));
40-
});
41-
42-
// Format the source code with clang-format (see .clang-format)
43-
gulp.task('format', () => {
44-
const format = require('gulp-clang-format');
45-
const clangFormat = require('clang-format');
46-
return gulp.src(srcsToFmt, {base: '.'})
47-
.pipe(format.format('file', clangFormat))
48-
.pipe(gulp.dest('.'));
49-
});
50-
51-
const entrypoints = [
52-
'dist/packages-dist/core/index.d.ts',
53-
'dist/packages-dist/core/testing/index.d.ts',
54-
'dist/packages-dist/common/index.d.ts',
55-
'dist/packages-dist/common/testing/index.d.ts',
56-
// The API surface of the compiler is currently unstable - all of the important APIs are exposed
57-
// via @angular/core, @angular/platform-browser or @angular/platform-browser-dynamic instead.
58-
//'dist/packages-dist/compiler/index.d.ts',
59-
//'dist/packages-dist/compiler/testing.d.ts',
60-
'dist/packages-dist/upgrade/index.d.ts',
61-
'dist/packages-dist/upgrade/static.d.ts',
62-
'dist/packages-dist/platform-browser/index.d.ts',
63-
'dist/packages-dist/platform-browser/testing/index.d.ts',
64-
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
65-
'dist/packages-dist/platform-browser-dynamic/testing/index.d.ts',
66-
'dist/packages-dist/platform-webworker/index.d.ts',
67-
'dist/packages-dist/platform-webworker-dynamic/index.d.ts',
68-
'dist/packages-dist/platform-server/index.d.ts',
69-
'dist/packages-dist/platform-server/testing/index.d.ts',
70-
'dist/packages-dist/http/index.d.ts',
71-
'dist/packages-dist/http/testing/index.d.ts',
72-
'dist/packages-dist/forms/index.d.ts',
73-
'dist/packages-dist/router/index.d.ts',
74-
];
75-
const publicApiDir = path.normalize('tools/public_api_guard');
76-
const publicApiArgs = [
77-
'--rootDir',
78-
'dist/packages-dist',
79-
'--stripExportPattern',
80-
'^__',
81-
'--allowModuleIdentifiers',
82-
'jasmine',
83-
'--allowModuleIdentifiers',
84-
'protractor',
85-
'--allowModuleIdentifiers',
86-
'angular',
87-
'--onStabilityMissing',
88-
'error',
89-
].concat(entrypoints);
90-
91-
// Build angular
92-
gulp.task('build.sh', (done) => {
93-
const childProcess = require('child_process');
94-
95-
childProcess.exec(path.join(__dirname, 'build.sh'), done);
96-
});
97-
98-
// Enforce that the public API matches the golden files
99-
// Note that these two commands work on built d.ts files instead of the source
100-
gulp.task('public-api:enforce', (done) => {
101-
const childProcess = require('child_process');
102-
103-
childProcess
104-
.spawn(
105-
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
106-
['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
107-
.on('close', (errorCode) => {
108-
if (errorCode !== 0) {
109-
done(new Error(
110-
'Public API differs from golden file. Please run `gulp public-api:update`.'));
111-
} else {
112-
done();
113-
}
114-
});
115-
});
116-
117-
// Generate the public API golden files
118-
gulp.task('public-api:update', ['build.sh'], (done) => {
119-
const childProcess = require('child_process');
120-
121-
childProcess
122-
.spawn(
123-
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
124-
['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
125-
.on('close', done);
126-
});
127-
128-
// Check the coding standards and programming errors
129-
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
130-
const tslint = require('gulp-tslint');
131-
// Built-in rules are at
132-
// https://palantir.github.io/tslint/rules/
133-
const tslintConfig = require('./tslint.json');
134-
return gulp
135-
.src([
136-
// todo(vicb): add .js files when supported
137-
// see https://github.com/palantir/tslint/pull/1515
138-
'./modules/**/*.ts',
139-
'./tools/**/*.ts',
140-
'./*.ts',
141-
142-
// Ignore TypeScript mocks because it's not managed by us
143-
'!./tools/@angular/tsc-wrapped/test/typescript.mocks.ts',
144-
145-
// Ignore generated files due to lack of copyright header
146-
// todo(alfaproject): make generated files lintable
147-
'!**/*.d.ts',
148-
'!**/*.ngfactory.ts',
149-
])
150-
.pipe(tslint({
151-
tslint: require('tslint').default,
152-
configuration: tslintConfig,
153-
formatter: 'prose',
154-
}))
155-
.pipe(tslint.report({emitError: true}));
156-
});
157-
158-
gulp.task('validate-commit-messages', () => {
159-
const validateCommitMessage = require('./tools/validate-commit-message');
160-
const childProcess = require('child_process');
161-
162-
// We need to fetch origin explicitly because it might be stale.
163-
// I couldn't find a reliable way to do this without fetch.
164-
childProcess.exec(
165-
'git fetch origin master && git log --reverse --format=%s HEAD ^origin/master',
166-
(error, stdout, stderr) => {
167-
if (error) {
168-
console.log(stderr);
169-
process.exit(1);
170-
}
171-
172-
let someCommitsInvalid = false;
173-
let commitsByLine = stdout.trim().split(/\n/);
174-
175-
console.log(`Examining ${commitsByLine.length} commits between HEAD and master`);
176-
177-
if (commitsByLine.length == 0) {
178-
console.log('There are zero new commits between this HEAD and master');
179-
}
180-
181-
someCommitsInvalid = !commitsByLine.every(validateCommitMessage);
182-
183-
if (someCommitsInvalid) {
184-
console.log('Please fix the failing commit messages before continuing...');
185-
console.log(
186-
'Commit message guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines');
187-
process.exit(1);
188-
}
189-
});
190-
});
191-
192-
gulp.task('tools:build', (done) => { tsc('tools/', done); });
193-
194-
// Check for circular dependency in the source code
195-
gulp.task('check-cycle', (done) => {
196-
const madge = require('madge');
197-
198-
const dependencyObject = madge(['dist/all/'], {
199-
format: 'cjs',
200-
extensions: ['.js'],
201-
onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, '//'); }
202-
});
203-
const circularDependencies = dependencyObject.circular().getArray();
204-
if (circularDependencies.length > 0) {
205-
console.log('Found circular dependencies!');
206-
console.log(circularDependencies);
207-
process.exit(1);
208-
}
209-
done();
210-
});
211-
212-
// Serve the built files
213-
gulp.task('serve', () => {
214-
const connect = require('gulp-connect');
215-
const cors = require('cors');
216-
217-
connect.server({
218-
root: `${__dirname}/dist`,
219-
port: 8000,
220-
livereload: false,
221-
open: false,
222-
middleware: (connect, opt) => [cors()],
223-
});
224-
});
225-
226-
// Serve the examples
227-
gulp.task('serve-examples', () => {
228-
const connect = require('gulp-connect');
229-
const cors = require('cors');
230-
231-
connect.server({
232-
root: `${__dirname}/dist/examples`,
233-
port: 8001,
234-
livereload: false,
235-
open: false,
236-
middleware: (connect, opt) => [cors()],
237-
});
238-
});
239-
240-
241-
// Update the changelog with the latest changes
242-
gulp.task('changelog', () => {
243-
const conventionalChangelog = require('gulp-conventional-changelog');
244-
245-
return gulp.src('CHANGELOG.md')
246-
.pipe(conventionalChangelog({preset: 'angular', releaseCount: 1}, {
247-
// Conventional Changelog Context
248-
// We have to manually set version number so it doesn't get prefixed with `v`
249-
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
250-
currentTag: require('./package.json').version
251-
}))
252-
.pipe(gulp.dest('./'));
253-
});
20+
// See `tools/gulp-tasks/README.md` for information about task loading.
21+
function loadTask(fileName, taskName) {
22+
const taskModule = require('./tools/gulp-tasks/' + fileName);
23+
const task = taskName ? taskModule[taskName] : taskModule;
24+
return task(gulp);
25+
}
25426

27+
gulp.task('format:enforce', loadTask('format', 'enforce'));
28+
gulp.task('format', loadTask('format', 'format'));
29+
gulp.task('build.sh', loadTask('build'));
30+
gulp.task('public-api:enforce', loadTask('public-api', 'enforce'));
31+
gulp.task('public-api:update', ['build.sh'], loadTask('public-api', 'update'));
32+
gulp.task('lint', ['format:enforce', 'tools:build'], loadTask('lint'));
33+
gulp.task('validate-commit-messages', loadTask('validate-commit-message'));
34+
gulp.task('tools:build', loadTask('tools-build'));
35+
gulp.task('check-cycle', loadTask('check-cycle'));
36+
gulp.task('serve', loadTask('serve', 'default'));
37+
gulp.task('serve-examples', loadTask('serve', 'examples'));
38+
gulp.task('changelog', loadTask('changelog'));
25539
gulp.task('docs', ['doc-gen', 'docs-app']);
256-
gulp.task('doc-gen', () => {
257-
const Dgeni = require('dgeni');
258-
const angularDocsPackage = require(path.resolve(__dirname, 'tools/docs/angular.io-package'));
259-
const dgeni = new Dgeni([angularDocsPackage]);
260-
return dgeni.generate();
261-
});
262-
gulp.task('docs-app', () => { gulp.src('docs/src/**/*').pipe(gulp.dest('dist/docs')); });
263-
264-
gulp.task('docs-test', ['doc-gen-test', 'docs-app-test']);
265-
gulp.task('doc-gen-test', () => {
266-
const execSync = require('child_process').execSync;
267-
execSync(
268-
'node dist/tools/cjs-jasmine/index-tools ../../tools/docs/**/*.spec.js',
269-
{stdio: ['inherit', 'inherit', 'inherit']});
270-
});
40+
gulp.task('doc-gen', loadTask('docs', 'generate'));
41+
gulp.task('doc-gen-test', loadTask('docs', 'test'));
42+
gulp.task('docs-app', loadTask('docs-app'));
27143
gulp.task('docs-app-test', () => {});
272-
273-
function tsc(projectPath, done) {
274-
const childProcess = require('child_process');
275-
276-
childProcess
277-
.spawn(
278-
path.normalize(platformScriptPath(`${__dirname}/node_modules/.bin/tsc`)),
279-
['-p', path.join(__dirname, projectPath)], {stdio: 'inherit'})
280-
.on('close', done);
281-
}
282-
283-
// returns the script path for the current platform
284-
function platformScriptPath(path) {
285-
return /^win/.test(os.platform()) ? `${path}.cmd` : path;
286-
}
44+
gulp.task('docs-test', ['doc-gen-test', 'docs-app-test']);

tools/gulp-tasks/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Gulp Tasks folder
2+
3+
This folder contains one file for each task (or group of related tasks) for the project's gulpfile.
4+
The dependencies between the tasks is kept in the gulpfile.
5+
6+
## Task File Structure
7+
Each task is defined by a factory function that accepts `gulp` as a parameter.
8+
Each file exports either one factory or an object of factories.
9+
10+
E.g. The `build.js` file contains only one task:
11+
12+
```js
13+
module.exports = (gulp) => (done) => {
14+
...
15+
};
16+
```
17+
18+
E.g. The `format.js` file contains two tasks:
19+
20+
```js
21+
module.exports = {
22+
// Check source code for formatting errors (clang-format)
23+
enforce: (gulp) => () => {
24+
...
25+
},
26+
27+
// Format the source code with clang-format (see .clang-format)
28+
format: (gulp) => () => {
29+
...
30+
}
31+
};
32+
33+
```
34+
35+
## Loading Tasks
36+
37+
The tasks are loaded in the gulp file, by requiring them. There is a helper called `loadTask(fileName, taskName)`
38+
will do this for us, where the `taskName` is optional if the file only exports one task.
39+
40+
E.g. Loading the task that will run the build, from a task file that contans only one task.
41+
42+
```js
43+
gulp.task('build.sh', loadTask('build'));
44+
```
45+
46+
E.g. Loading the task that will enforce formatting, from a task file that contains more than one task:
47+
48+
```js
49+
gulp.task('format:enforce', loadTask('format', 'enforce'));
50+
```
51+
52+
E.g. Loading a task that has dependencies:
53+
54+
```js
55+
gulp.task('lint', ['format:enforce', 'tools:build'], loadTask('lint'));
56+
```

tools/gulp-tasks/build.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
module.exports = (gulp) => (done) => {
3+
const path = require('path');
4+
const childProcess = require('child_process');
5+
childProcess.exec(path.join(__dirname, '../../build.sh'), done);
6+
};

tools/gulp-tasks/changelog.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = (gulp) => () => {
2+
const conventionalChangelog = require('gulp-conventional-changelog');
3+
return gulp.src('CHANGELOG.md')
4+
.pipe(conventionalChangelog({preset: 'angular', releaseCount: 1}, {
5+
// Conventional Changelog Context
6+
// We have to manually set version number so it doesn't get prefixed with `v`
7+
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
8+
currentTag: require('../../package.json').version
9+
}))
10+
.pipe(gulp.dest('./'));
11+
};

tools/gulp-tasks/check-cycle.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = (gulp) => (done) => {
2+
const madge = require('madge');
3+
4+
const dependencyObject = madge(['dist/all/'], {
5+
format: 'cjs',
6+
extensions: ['.js'],
7+
onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, '//'); }
8+
});
9+
const circularDependencies = dependencyObject.circular().getArray();
10+
if (circularDependencies.length > 0) {
11+
console.log('Found circular dependencies!');
12+
console.log(circularDependencies);
13+
process.exit(1);
14+
}
15+
done();
16+
};

tools/gulp-tasks/docs-app.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = (gulp) => () => {
2+
gulp.src('docs/src/**/*').pipe(gulp.dest('dist/docs'));
3+
};

0 commit comments

Comments
 (0)