1 | 'use strict';
|
2 |
|
3 | var gutil = require('gulp-util'),
|
4 | jshint = require('gulp-jshint'),
|
5 | stylish = require('jshint-stylish'),
|
6 | mocha = require('gulp-mocha'),
|
7 | istanbul = require('gulp-istanbul'),
|
8 | coverageEnforcer = require('gulp-istanbul-enforcer'),
|
9 | size,
|
10 | _ = require('lodash'),
|
11 | plato = require('gulp-plato'),
|
12 | fs = require('fs'),
|
13 | open = require('gulp-open'),
|
14 | path = require('path'),
|
15 | spawn = require('child_process').spawn,
|
16 | mapstream = require('map-stream'),
|
17 | nicePackage = require('gulp-nice-package'),
|
18 | shrinkwrap = require('gulp-shrinkwrap');
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | module.exports = function (gulp, options) {
|
26 |
|
27 |
|
28 | var exitCode = 0,
|
29 | totalLintErrors = 0,
|
30 | totalFelintErrors = 0;
|
31 |
|
32 |
|
33 | gulp.options = {
|
34 | istanbul: {
|
35 | includeUntested: true
|
36 | },
|
37 | istanbulWriteReports: {
|
38 | dir: './target/coverage'
|
39 | },
|
40 | istanbulEnforcer: {
|
41 | thresholds: {
|
42 | statements: 80,
|
43 | branches: 70,
|
44 | lines: 80,
|
45 | functions: 80
|
46 | },
|
47 | coverageDirectory: './target/coverage',
|
48 | rootDirectory: ''
|
49 | },
|
50 | paths: {
|
51 | lint: [
|
52 | './*.js',
|
53 | './lib/**/*.js',
|
54 | './test/**/*.js'
|
55 | ],
|
56 | felint: [
|
57 | './content/**/*.js'
|
58 | ],
|
59 | cover: [
|
60 | './lib/**/*.js'
|
61 | ],
|
62 | test: [
|
63 | './test/**/*.js'
|
64 | ]
|
65 | },
|
66 | jshintrc: {
|
67 | server: path.join(__dirname, 'lint/.jshintrc'),
|
68 | client: path.join(__dirname, 'felint/.jshintrc')
|
69 | },
|
70 | showStreamSize: false,
|
71 | complexity: {
|
72 | destDir: './target/complexity',
|
73 | options: {}
|
74 | },
|
75 | nicePackage: {
|
76 | spec: 'npm',
|
77 | options: {
|
78 | warnings: false,
|
79 | recommendations: false
|
80 | }
|
81 | }
|
82 | };
|
83 |
|
84 | _.merge(gulp.options, options, function (a, b) {
|
85 | return _.isArray(a) ? b : undefined;
|
86 | });
|
87 |
|
88 |
|
89 | if (options && options.coverageSettings) {
|
90 | _.merge(gulp.options.istanbulEnforcer, options.coverageSettings);
|
91 | if (options.coverageSettings.coverageDirectory) {
|
92 | gulp.options.istanbulWriteReports.dir = options.coverageSettings.coverageDirectory;
|
93 | }
|
94 | }
|
95 |
|
96 | size = (gulp.options.showStreamSize) ? require('gulp-size') : require('./size-fake/index.js');
|
97 |
|
98 | require('gulp-help')(gulp, { aliases: ['h', '?']});
|
99 |
|
100 | process.on('exit', function () {
|
101 | process.nextTick(function () {
|
102 | var msg = "gulp '" + gulp.seq + "' failed";
|
103 | console.log(gutil.colors.red(msg));
|
104 | process.exit(exitCode);
|
105 | });
|
106 | });
|
107 |
|
108 | function taskPassed(taskName) {
|
109 | var msg = "gulp '" + taskName + "' passed";
|
110 | console.log(gutil.colors.green(msg));
|
111 | }
|
112 |
|
113 |
|
114 | function beforeEach() {
|
115 | totalLintErrors = 0;
|
116 | totalFelintErrors = 0;
|
117 | exitCode = 0;
|
118 | }
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 | function lint() {
|
125 | beforeEach();
|
126 | return gulp.src(gulp.options.paths.lint)
|
127 | .pipe(jshint(gulp.options.jshintrc.server))
|
128 | .pipe(jshint.reporter(stylish, { verbose: true }))
|
129 | .pipe(mapstream(function (file, cb) {
|
130 | if (!file.jshint.success) {
|
131 | totalLintErrors += file.jshint.results.length;
|
132 | exitCode = 1;
|
133 | }
|
134 | cb(null, file);
|
135 | }));
|
136 | }
|
137 |
|
138 | function lintOnEnd() {
|
139 | var errString = totalLintErrors + '';
|
140 | if (exitCode) {
|
141 | console.log(gutil.colors.magenta(errString), 'errors\n');
|
142 | gutil.beep();
|
143 | } else {
|
144 | taskPassed('lint');
|
145 | }
|
146 | }
|
147 |
|
148 | gulp.task('lint', 'Lint server side js', function () {
|
149 | return lint()
|
150 | .on('end', function () {
|
151 | lintOnEnd();
|
152 | if (exitCode) {
|
153 | process.emit('exit');
|
154 | }
|
155 | })
|
156 | .pipe(size({
|
157 | title: 'lint'
|
158 | }));
|
159 | });
|
160 |
|
161 | gulp.task('lint-watch', false, function () {
|
162 | return lint()
|
163 | .on('end', lintOnEnd)
|
164 | .pipe(size({
|
165 | title: 'lint'
|
166 | }));
|
167 | });
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | function felint() {
|
174 | beforeEach();
|
175 | return gulp.src(gulp.options.paths.felint)
|
176 | .pipe(jshint(gulp.options.jshintrc.client))
|
177 | .pipe(jshint.reporter(stylish))
|
178 | .pipe(mapstream(function (file, cb) {
|
179 | if (!file.jshint.success) {
|
180 | totalFelintErrors += file.jshint.results.length;
|
181 | exitCode = 1;
|
182 | }
|
183 | cb(null, file);
|
184 | }));
|
185 | }
|
186 |
|
187 | function felintOnEnd() {
|
188 | var errString = totalFelintErrors + '';
|
189 | if (exitCode) {
|
190 | console.log(gutil.colors.magenta(errString), 'errors\n');
|
191 | gutil.beep();
|
192 | } else {
|
193 | taskPassed('felint');
|
194 | }
|
195 | }
|
196 |
|
197 | gulp.task('felint', 'Lint client side js', function () {
|
198 | return felint()
|
199 | .on('end', function () {
|
200 | felintOnEnd();
|
201 | if (exitCode) {
|
202 | process.emit('exit');
|
203 | }
|
204 | })
|
205 | .pipe(size({
|
206 | title: 'felint'
|
207 | }));
|
208 | });
|
209 |
|
210 | gulp.task('felint-watch', false, function () {
|
211 | return felint()
|
212 | .on('end', felintOnEnd)
|
213 | .pipe(size({
|
214 | title: 'felint'
|
215 | }));
|
216 | });
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 | function testErrorHandler(err) {
|
223 | gutil.beep();
|
224 | gutil.log(err.message);
|
225 | exitCode = 1;
|
226 | }
|
227 |
|
228 | function cover(cb) {
|
229 | beforeEach();
|
230 | return gulp.src(gulp.options.paths.cover)
|
231 | .pipe(istanbul(gulp.options.istanbul))
|
232 | .on('finish', cb)
|
233 | .pipe(size({
|
234 | title: 'cover'
|
235 | }));
|
236 | }
|
237 |
|
238 | function coverOnEnd() {
|
239 | gutil.log('Wrote coverage reports to', gutil.colors.magenta(gulp.options.istanbulWriteReports.dir));
|
240 |
|
241 | }
|
242 |
|
243 | gulp.task('test-cover', 'Unit tests and coverage', function () {
|
244 | return cover(function () {
|
245 | return gulp.src(gulp.options.paths.test)
|
246 | .pipe(mocha({reporter: 'dot'}))
|
247 | .on('error', function (err) {
|
248 | testErrorHandler(err);
|
249 | process.emit('exit');
|
250 | })
|
251 | .pipe(size({
|
252 | title: 'test-cover'
|
253 | }))
|
254 | .pipe(istanbul.writeReports(gulp.options.istanbulWriteReports))
|
255 | .pipe(coverageEnforcer(gulp.options.istanbulEnforcer))
|
256 | .on('error', function (err) {
|
257 | testErrorHandler(err);
|
258 | process.emit('exit');
|
259 | })
|
260 | .on('end', coverOnEnd);
|
261 | });
|
262 | });
|
263 |
|
264 | gulp.task('test-cover-watch', false, function () {
|
265 | return cover(function () {
|
266 | return gulp.src(gulp.options.paths.test)
|
267 | .pipe(mocha({reporter: 'dot'}))
|
268 | .on('error', testErrorHandler)
|
269 | .pipe(size({
|
270 | title: 'test-cover'
|
271 | }))
|
272 | .pipe(istanbul.writeReports(gulp.options.istanbulWriteReports))
|
273 | .pipe(coverageEnforcer(gulp.options.istanbulEnforcer))
|
274 | .on('error', testErrorHandler)
|
275 | .on('end', coverOnEnd);
|
276 | });
|
277 | });
|
278 |
|
279 | gulp.task('test', 'Unit tests only', function () {
|
280 | return gulp.src(gulp.options.paths.test)
|
281 | .pipe(mocha({reporter: 'dot'}))
|
282 | .on('error', function (err) {
|
283 | testErrorHandler(err);
|
284 | process.emit('exit');
|
285 | })
|
286 | .pipe(size({
|
287 | title: 'test'
|
288 | }));
|
289 | });
|
290 |
|
291 | gulp.task('test-watch', false, function (cb) {
|
292 | return gulp.src(gulp.options.paths.test)
|
293 | .pipe(mocha({
|
294 | reporter: 'min',
|
295 | growl: true
|
296 | }))
|
297 | .on('error', testErrorHandler)
|
298 | .pipe(size({
|
299 | title: 'test-watch'
|
300 | }));
|
301 | });
|
302 |
|
303 | gulp.task('test-debug', 'Run unit tests in debug mode', function (cb) {
|
304 | spawn('node', [
|
305 | '--debug-brk',
|
306 | path.join(__dirname, 'node_modules/gulp/bin/gulp.js'),
|
307 | 'test'
|
308 | ], { stdio: 'inherit' });
|
309 | });
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | gulp.task('plato', 'Generate complexity analysis reports with plato', function (cb) {
|
316 |
|
317 |
|
318 | var commentRemovalRegex = /\/\*.+?\*\/|\/\/.*(?=[\n\r])/g,
|
319 | jshintJSON;
|
320 |
|
321 | fs.readFile(gulp.options.jshintrc.server, 'utf8', function (err, data) {
|
322 | if (err) {
|
323 | throw err;
|
324 | }
|
325 | jshintJSON = JSON.parse(data.replace(commentRemovalRegex, ''));
|
326 |
|
327 | gulp.src(gulp.options.paths.cover)
|
328 | .pipe(plato(gulp.options.complexity.destDir, {
|
329 | jshint: {
|
330 | options: jshintJSON
|
331 | },
|
332 | complexity: gulp.options.complexity.options
|
333 | }));
|
334 |
|
335 | gulp.src(gulp.options.complexity.destDir + '/index.html')
|
336 | .pipe(open());
|
337 |
|
338 | cb();
|
339 | });
|
340 |
|
341 | });
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 | function validatePackageJson() {
|
348 | return gulp.src('package.json')
|
349 | .pipe(nicePackage(gulp.options.nicePackage.spec, gulp.options.nicePackage.options));
|
350 | }
|
351 |
|
352 | gulp.task('nice-package', 'Validates package.json', function () {
|
353 | var isValid = true;
|
354 | return validatePackageJson()
|
355 | .pipe(mapstream(function (file, cb) {
|
356 | isValid = file.nicePackage.valid;
|
357 | cb(null, file);
|
358 | }))
|
359 | .on('end', function () {
|
360 | if (!isValid) {
|
361 | process.emit('exit');
|
362 | }
|
363 | });
|
364 | });
|
365 |
|
366 | gulp.task('shrinkwrap', 'Cleans package.json deps and generates npm-shrinkwrap.json', function () {
|
367 | return validatePackageJson()
|
368 | .pipe(shrinkwrap())
|
369 | .pipe(gulp.dest('./'));
|
370 | });
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 | gulp.task('ci', 'Lint, tests and test coverage', ['lint', 'felint', 'test-cover', 'nice-package']);
|
377 |
|
378 | function getTestAndLintPaths() {
|
379 | var paths = gulp.options.paths.lint.concat(gulp.options.paths.test);
|
380 | return _.uniq(paths);
|
381 | }
|
382 |
|
383 |
|
384 | gulp.task('ci-watch', false, function () {
|
385 | gulp.watch(getTestAndLintPaths(), ['lint-watch', 'test-cover-watch']);
|
386 | gulp.watch(gulp.options.paths.felint, ['felint-watch']);
|
387 | });
|
388 |
|
389 | gulp.task('watch', 'Watch files and run all ci validation on change', ['ci-watch']);
|
390 |
|
391 | gulp.task('watch-test', 'Watch files and run tests on change', function () {
|
392 | gulp.watch(getTestAndLintPaths(), ['test-watch']);
|
393 | });
|
394 |
|
395 | return gulp;
|
396 | };
|