Merge "Add qtip job to pod zte-virtual6"
[releng.git] / utils / test / testapi / 3rd_party / static / testapi-ui / assets / lib / bootstrap / Gruntfile.js
1 /*!
2  * Bootstrap's Gruntfile
3  * http://getbootstrap.com
4  * Copyright 2013-2015 Twitter, Inc.
5  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6  */
7
8 module.exports = function (grunt) {
9   'use strict';
10
11   // Force use of Unix newlines
12   grunt.util.linefeed = '\n';
13
14   RegExp.quote = function (string) {
15     return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
16   };
17
18   var fs = require('fs');
19   var path = require('path');
20   var npmShrinkwrap = require('npm-shrinkwrap');
21   var generateGlyphiconsData = require('./grunt/bs-glyphicons-data-generator.js');
22   var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js');
23   var getLessVarsData = function () {
24     var filePath = path.join(__dirname, 'less/variables.less');
25     var fileContent = fs.readFileSync(filePath, { encoding: 'utf8' });
26     var parser = new BsLessdocParser(fileContent);
27     return { sections: parser.parseFile() };
28   };
29   var generateRawFiles = require('./grunt/bs-raw-files-generator.js');
30   var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js');
31   var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' });
32
33   Object.keys(configBridge.paths).forEach(function (key) {
34     configBridge.paths[key].forEach(function (val, i, arr) {
35       arr[i] = path.join('./docs/assets', val);
36     });
37   });
38
39   // Project configuration.
40   grunt.initConfig({
41
42     // Metadata.
43     pkg: grunt.file.readJSON('package.json'),
44     banner: '/*!\n' +
45             ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
46             ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
47             ' * Licensed under <%= pkg.license.type %> (<%= pkg.license.url %>)\n' +
48             ' */\n',
49     jqueryCheck: configBridge.config.jqueryCheck.join('\n'),
50     jqueryVersionCheck: configBridge.config.jqueryVersionCheck.join('\n'),
51
52     // Task configuration.
53     clean: {
54       dist: 'dist',
55       docs: 'docs/dist'
56     },
57
58     jshint: {
59       options: {
60         jshintrc: 'js/.jshintrc'
61       },
62       grunt: {
63         options: {
64           jshintrc: 'grunt/.jshintrc'
65         },
66         src: ['Gruntfile.js', 'grunt/*.js']
67       },
68       core: {
69         src: 'js/*.js'
70       },
71       test: {
72         options: {
73           jshintrc: 'js/tests/unit/.jshintrc'
74         },
75         src: 'js/tests/unit/*.js'
76       },
77       assets: {
78         src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js']
79       }
80     },
81
82     jscs: {
83       options: {
84         config: 'js/.jscsrc'
85       },
86       grunt: {
87         src: '<%= jshint.grunt.src %>'
88       },
89       core: {
90         src: '<%= jshint.core.src %>'
91       },
92       test: {
93         src: '<%= jshint.test.src %>'
94       },
95       assets: {
96         options: {
97           requireCamelCaseOrUpperCaseIdentifiers: null
98         },
99         src: '<%= jshint.assets.src %>'
100       }
101     },
102
103     concat: {
104       options: {
105         banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>',
106         stripBanners: false
107       },
108       bootstrap: {
109         src: [
110           'js/transition.js',
111           'js/alert.js',
112           'js/button.js',
113           'js/carousel.js',
114           'js/collapse.js',
115           'js/dropdown.js',
116           'js/modal.js',
117           'js/tooltip.js',
118           'js/popover.js',
119           'js/scrollspy.js',
120           'js/tab.js',
121           'js/affix.js'
122         ],
123         dest: 'dist/js/<%= pkg.name %>.js'
124       }
125     },
126
127     uglify: {
128       options: {
129         preserveComments: 'some'
130       },
131       core: {
132         src: '<%= concat.bootstrap.dest %>',
133         dest: 'dist/js/<%= pkg.name %>.min.js'
134       },
135       customize: {
136         src: configBridge.paths.customizerJs,
137         dest: 'docs/assets/js/customize.min.js'
138       },
139       docsJs: {
140         src: configBridge.paths.docsJs,
141         dest: 'docs/assets/js/docs.min.js'
142       }
143     },
144
145     qunit: {
146       options: {
147         inject: 'js/tests/unit/phantom.js'
148       },
149       files: 'js/tests/index.html'
150     },
151
152     less: {
153       compileCore: {
154         options: {
155           strictMath: true,
156           sourceMap: true,
157           outputSourceFiles: true,
158           sourceMapURL: '<%= pkg.name %>.css.map',
159           sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map'
160         },
161         src: 'less/bootstrap.less',
162         dest: 'dist/css/<%= pkg.name %>.css'
163       },
164       compileTheme: {
165         options: {
166           strictMath: true,
167           sourceMap: true,
168           outputSourceFiles: true,
169           sourceMapURL: '<%= pkg.name %>-theme.css.map',
170           sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map'
171         },
172         src: 'less/theme.less',
173         dest: 'dist/css/<%= pkg.name %>-theme.css'
174       }
175     },
176
177     autoprefixer: {
178       options: {
179         browsers: configBridge.config.autoprefixerBrowsers
180       },
181       core: {
182         options: {
183           map: true
184         },
185         src: 'dist/css/<%= pkg.name %>.css'
186       },
187       theme: {
188         options: {
189           map: true
190         },
191         src: 'dist/css/<%= pkg.name %>-theme.css'
192       },
193       docs: {
194         src: 'docs/assets/css/src/docs.css'
195       },
196       examples: {
197         expand: true,
198         cwd: 'docs/examples/',
199         src: ['**/*.css'],
200         dest: 'docs/examples/'
201       }
202     },
203
204     csslint: {
205       options: {
206         csslintrc: 'less/.csslintrc'
207       },
208       dist: [
209         'dist/css/bootstrap.css',
210         'dist/css/bootstrap-theme.css'
211       ],
212       examples: [
213         'docs/examples/**/*.css'
214       ],
215       docs: {
216         options: {
217           ids: false,
218           'overqualified-elements': false
219         },
220         src: 'docs/assets/css/src/docs.css'
221       }
222     },
223
224     cssmin: {
225       options: {
226         compatibility: 'ie8',
227         keepSpecialComments: '*',
228         advanced: false
229       },
230       minifyCore: {
231         src: 'dist/css/<%= pkg.name %>.css',
232         dest: 'dist/css/<%= pkg.name %>.min.css'
233       },
234       minifyTheme: {
235         src: 'dist/css/<%= pkg.name %>-theme.css',
236         dest: 'dist/css/<%= pkg.name %>-theme.min.css'
237       },
238       docs: {
239         src: [
240           'docs/assets/css/src/docs.css',
241           'docs/assets/css/src/pygments-manni.css'
242         ],
243         dest: 'docs/assets/css/docs.min.css'
244       }
245     },
246
247     usebanner: {
248       options: {
249         position: 'top',
250         banner: '<%= banner %>'
251       },
252       files: {
253         src: 'dist/css/*.css'
254       }
255     },
256
257     csscomb: {
258       options: {
259         config: 'less/.csscomb.json'
260       },
261       dist: {
262         expand: true,
263         cwd: 'dist/css/',
264         src: ['*.css', '!*.min.css'],
265         dest: 'dist/css/'
266       },
267       examples: {
268         expand: true,
269         cwd: 'docs/examples/',
270         src: '**/*.css',
271         dest: 'docs/examples/'
272       },
273       docs: {
274         src: 'docs/assets/css/src/docs.css',
275         dest: 'docs/assets/css/src/docs.css'
276       }
277     },
278
279     copy: {
280       fonts: {
281         src: 'fonts/*',
282         dest: 'dist/'
283       },
284       docs: {
285         src: 'dist/*/*',
286         dest: 'docs/'
287       }
288     },
289
290     connect: {
291       server: {
292         options: {
293           port: 3000,
294           base: '.'
295         }
296       }
297     },
298
299     jekyll: {
300       options: {
301         config: '_config.yml'
302       },
303       docs: {},
304       github: {
305         options: {
306           raw: 'github: true'
307         }
308       }
309     },
310
311     jade: {
312       options: {
313         pretty: true,
314         data: getLessVarsData
315       },
316       customizerVars: {
317         src: 'docs/_jade/customizer-variables.jade',
318         dest: 'docs/_includes/customizer-variables.html'
319       },
320       customizerNav: {
321         src: 'docs/_jade/customizer-nav.jade',
322         dest: 'docs/_includes/nav/customize.html'
323       }
324     },
325
326     validation: {
327       options: {
328         charset: 'utf-8',
329         doctype: 'HTML5',
330         failHard: true,
331         reset: true,
332         relaxerror: [
333           'Element img is missing required attribute src.',
334           'Attribute autocomplete not allowed on element input at this point.',
335           'Attribute autocomplete not allowed on element button at this point.',
336           'Bad value separator for attribute role on element li.'
337         ]
338       },
339       files: {
340         src: '_gh_pages/**/*.html'
341       }
342     },
343
344     watch: {
345       src: {
346         files: '<%= jshint.core.src %>',
347         tasks: ['jshint:src', 'qunit', 'concat']
348       },
349       test: {
350         files: '<%= jshint.test.src %>',
351         tasks: ['jshint:test', 'qunit']
352       },
353       less: {
354         files: 'less/**/*.less',
355         tasks: 'less'
356       }
357     },
358
359     sed: {
360       versionNumber: {
361         pattern: (function () {
362           var old = grunt.option('oldver');
363           return old ? RegExp.quote(old) : old;
364         })(),
365         replacement: grunt.option('newver'),
366         recursive: true
367       }
368     },
369
370     'saucelabs-qunit': {
371       all: {
372         options: {
373           build: process.env.TRAVIS_JOB_ID,
374           throttled: 10,
375           maxRetries: 3,
376           maxPollRetries: 4,
377           urls: ['http://127.0.0.1:3000/js/tests/index.html'],
378           browsers: grunt.file.readYAML('grunt/sauce_browsers.yml')
379         }
380       }
381     },
382
383     exec: {
384       npmUpdate: {
385         command: 'npm update'
386       }
387     },
388
389     compress: {
390       main: {
391         options: {
392           archive: 'bootstrap-<%= pkg.version %>-dist.zip',
393           mode: 'zip',
394           level: 9,
395           pretty: true
396         },
397         files: [
398           {
399             expand: true,
400             cwd: 'dist/',
401             src: ['**'],
402             dest: 'bootstrap-<%= pkg.version %>-dist'
403           }
404         ]
405       }
406     }
407
408   });
409
410
411   // These plugins provide necessary tasks.
412   require('load-grunt-tasks')(grunt, { scope: 'devDependencies' });
413   require('time-grunt')(grunt);
414
415   // Docs HTML validation task
416   grunt.registerTask('validate-html', ['jekyll:docs', 'validation']);
417
418   var runSubset = function (subset) {
419     return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset;
420   };
421   var isUndefOrNonZero = function (val) {
422     return val === undefined || val !== '0';
423   };
424
425   // Test task.
426   var testSubtasks = [];
427   // Skip core tests if running a different subset of the test suite
428   if (runSubset('core') &&
429       // Skip core tests if this is a Savage build
430       process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') {
431     testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']);
432   }
433   // Skip HTML validation if running a different subset of the test suite
434   if (runSubset('validate-html') &&
435       // Skip HTML5 validator on Travis when [skip validator] is in the commit message
436       isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) {
437     testSubtasks.push('validate-html');
438   }
439   // Only run Sauce Labs tests if there's a Sauce access key
440   if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
441       // Skip Sauce if running a different subset of the test suite
442       runSubset('sauce-js-unit') &&
443       // Skip Sauce on Travis when [skip sauce] is in the commit message
444       isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) {
445     testSubtasks.push('connect');
446     testSubtasks.push('saucelabs-qunit');
447   }
448   grunt.registerTask('test', testSubtasks);
449   grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']);
450
451   // JS distribution task.
452   grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']);
453
454   // CSS distribution task.
455   grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme']);
456   grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'usebanner', 'csscomb:dist', 'cssmin:minifyCore', 'cssmin:minifyTheme']);
457
458   // Full distribution task.
459   grunt.registerTask('dist', ['clean:dist', 'dist-css', 'copy:fonts', 'dist-js']);
460
461   // Default task.
462   grunt.registerTask('default', ['clean:dist', 'copy:fonts', 'test']);
463
464   // Version numbering task.
465   // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z
466   // This can be overzealous, so its changes should always be manually reviewed!
467   grunt.registerTask('change-version-number', 'sed');
468
469   grunt.registerTask('build-glyphicons-data', function () { generateGlyphiconsData.call(this, grunt); });
470
471   // task for building customizer
472   grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']);
473   grunt.registerTask('build-customizer-html', 'jade');
474   grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () {
475     var banner = grunt.template.process('<%= banner %>');
476     generateRawFiles(grunt, banner);
477   });
478
479   grunt.registerTask('commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () {
480     var srcFiles = grunt.config.get('concat.bootstrap.src');
481     var destFilepath = 'dist/js/npm.js';
482     generateCommonJSModule(grunt, srcFiles, destFilepath);
483   });
484
485   // Docs task.
486   grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']);
487   grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']);
488   grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']);
489   grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']);
490   grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-glyphicons-data', 'build-customizer']);
491
492   grunt.registerTask('prep-release', ['jekyll:github', 'compress']);
493
494   // Task for updating the cached npm packages used by the Travis build (which are controlled by test-infra/npm-shrinkwrap.json).
495   // This task should be run and the updated file should be committed whenever Bootstrap's dependencies change.
496   grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', '_update-shrinkwrap']);
497   grunt.registerTask('_update-shrinkwrap', function () {
498     var done = this.async();
499     npmShrinkwrap({ dev: true, dirname: __dirname }, function (err) {
500       if (err) {
501         grunt.fail.warn(err);
502       }
503       var dest = 'test-infra/npm-shrinkwrap.json';
504       fs.renameSync('npm-shrinkwrap.json', dest);
505       grunt.log.writeln('File ' + dest.cyan + ' updated.');
506       done();
507     });
508   });
509 };