From d30f275305f13c84c82e8d360527b959ef53982d Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Thu, 28 Feb 2013 19:45:00 +0000 Subject: [PATCH] refact(grunt) upgrade to grunt 0.4.0 --- .travis.yml | 2 +- client/build/grunt-html2js.js | 92 ++++++++++--- client/build/grunt-testacular.js | 42 ------ client/grunt.js | 139 -------------------- client/gruntFile.js | 177 ++++++++++++++++++++++++++ client/package.json | 12 +- client/src/app/app.js | 3 +- client/src/app/dashboard/dashboard.js | 2 +- client/test/config/e2e.js | 6 +- client/test/config/unit.js | 12 +- client/test/e2e/index.scenario.js | 2 +- 11 files changed, 275 insertions(+), 214 deletions(-) delete mode 100644 client/build/grunt-testacular.js delete mode 100644 client/grunt.js create mode 100644 client/gruntFile.js diff --git a/.travis.yml b/.travis.yml index cf6e5fd3..bfcd3b6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ before_script: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - - npm install --quiet -g grunt@0.3.x testacular@0.4.x + - npm install --quiet -g grunt-cli@0.1.x testacular@0.6.x - cd server - npm install --quiet - node server.js & diff --git a/client/build/grunt-html2js.js b/client/build/grunt-html2js.js index 668f1fa6..73f77578 100644 --- a/client/build/grunt-html2js.js +++ b/client/build/grunt-html2js.js @@ -1,12 +1,22 @@ -module.exports = function (grunt) { +/* + * grunt-html2js + * https://github.com/karlgoldstein/grunt-html2js + * + * Copyright (c) 2013 Karl Goldstein + * Licensed under the MIT license. + */ + +'use strict'; + +module.exports = function(grunt) { - // HTML-2-JS Templates var path = require('path'); - var TPL = 'angular.module("<%= id %>", []).run(["$templateCache", function($templateCache) {\n $templateCache.put("<%= id %>",\n "<%= content %>");\n}]);\n'; - var templateModule = "angular.module('templates', [<%= templates %>]);"; + var escapeContent = function(content) { return content.replace(/"/g, '\\"').replace(/\r?\n/g, '" +\n "'); }; + + // convert Windows file separator URL path separator var normalizePath = function(p) { if ( path.sep !== '/' ) { p = p.replace(/\\/g, '/'); @@ -14,22 +24,64 @@ module.exports = function (grunt) { return p; }; - grunt.registerTask('html2js', 'Generate js version of html template.', function() { - this.requiresConfig('html2js.src'); - var files = grunt.file.expandFiles(grunt.config.process('html2js.src')); - var base = grunt.config.process('html2js.base') || '.'; - var dest = grunt.config.process('html2js.dest') || '.'; - var templates = []; - files.forEach(function(file) { - var id = normalizePath(path.relative(base, file)); - templates.push("'" + id + "'"); - grunt.file.write(path.resolve(dest, id + '.js'), grunt.template.process(TPL, { - id: id, - content: escapeContent(grunt.file.read(file)) - })); + // Warn on and remove invalid source files (if nonull was set). + var existsFilter = function(filepath) { + + if (!grunt.file.exists(filepath)) { + grunt.log.warn('Source file "' + filepath + '" not found.'); + return false; + } else { + return true; + } + }; + + // compile a template to an angular module + var compileTemplate = function(moduleName, filepath) { + + var content = escapeContent(grunt.file.read(filepath)); + + var module = 'angular.module("' + moduleName + + '", []).run(["$templateCache", function($templateCache) ' + + '{\n $templateCache.put("' + moduleName + '",\n "' + content + + '");\n}]);\n'; + + return module; + }; + + grunt.registerMultiTask('html2js', 'Compiles Angular-JS templates to JavaScript.', function() { + + var options = this.options({ + base: 'src', + module: 'templates-' + this.target + }); + + // generate a separate module + this.files.forEach(function(f) { + + var moduleNames = []; + + var modules = f.src.filter(existsFilter).map(function(filepath) { + + var moduleName = normalizePath(path.relative(options.base, filepath)); + moduleNames.push("'" + moduleName + "'"); + + return compileTemplate(moduleName, filepath); + + }).join(grunt.util.normalizelf('\n')); + + if (moduleNames.length) { + + var target = f.module || options.module; + + var bundle = "angular.module('" + target + "', [" + + moduleNames.join(', ') + "]);\n\n" + modules; + grunt.file.write(f.dest, bundle); + grunt.log.writeln('File "' + f.dest + '" created.'); + + } else { + + grunt.log.warn('No source templates found, not creating ' + f.dest); + } }); - grunt.file.write(path.resolve(dest,'templates.js'), grunt.template.process(templateModule, { - templates: templates.join(', ') - })); }); }; \ No newline at end of file diff --git a/client/build/grunt-testacular.js b/client/build/grunt-testacular.js deleted file mode 100644 index 34b5474b..00000000 --- a/client/build/grunt-testacular.js +++ /dev/null @@ -1,42 +0,0 @@ -module.exports = function(grunt) { - - // Testacular stuff - var testacularCmd = process.platform === 'win32' ? 'testacular.cmd' : 'testacular'; - var runTestacular = function(testConfigFile, options) { - var args = ['start', testConfigFile, '--reporters=dots'].concat(options); - var done = grunt.task.current.async(); - var child = grunt.utils.spawn({ - cmd: testacularCmd, - args: args - }, function(err, result, code) { - if (code) { - done(false); - } else { - done(); - } - }); - child.stdout.pipe(process.stdout); - child.stderr.pipe(process.stderr); - }; - - grunt.registerTask('test-watch', 'watch file changes and test', function() { - var options = ['--auto-watch', '--no-single-run']; - runTestacular('test/config/unit.js', options); - }); - - grunt.registerTask('test', 'run testacular tests', function() { - var options = ['--single-run', '--no-auto-watch']; - if (process.env.TRAVIS) { - options.push('--browsers=Firefox'); - } - runTestacular('test/config/unit.js', options); - }); - - grunt.registerTask('e2e', 'run testacular e2e tests', function() { - var options = ['--single-run', '--no-auto-watch']; - if (process.env.TRAVIS) { - options.push('--browsers=Firefox'); - } - runTestacular('test/config/e2e.js', options); - }); -}; \ No newline at end of file diff --git a/client/grunt.js b/client/grunt.js deleted file mode 100644 index 9075f8a7..00000000 --- a/client/grunt.js +++ /dev/null @@ -1,139 +0,0 @@ -module.exports = function (grunt) { - - grunt.loadNpmTasks('grunt-recess'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadTasks('build'); - - // Project configuration. - grunt.initConfig({ - distdir: 'dist', - pkg:'', - meta:{ - banner:'/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + - '<%= grunt.template.today("yyyy-mm-dd") %>\n' + - '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' + - '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' + - ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */' - }, - src: { - js: ['src/**/*.js', 'dist/tmp/**/*.js'], - html: ['src/index.html'], - tpl: ['src/app/**/*.tpl.html'], - less: ['src/less/stylesheet.less'] // recess:build doesn't accept ** in its file patterns - }, - clean: ['<%= distdir %>/*'], - copy: { - assets: { - files: {'<%= distdir %>/': 'src/assets/**'} - } - }, - test: { - unit: ['test/unit/**/*Spec.js'], - e2e: ['test/e2e/**/*Scenario.js'] - }, - lint:{ - files:['grunt.js', '', '', ''] - }, - html2js: { - src: [''], - base: 'src/app', - dest: 'dist/tmp' - }, - concat:{ - dist:{ - src:['', ''], - dest:'<%= distdir %>/<%= pkg.name %>.js' - }, - angular: { - src:['vendor/angular/angular.js'], - dest: '<%= distdir %>/angular.js' - }, - mongo: { - src:['vendor/mongolab/*.js'], - dest: '<%= distdir %>/mongolab.js' - }, - bootstrap: { - src:['vendor/bootstrap/*.js'], - dest: '<%= distdir %>/bootstrap.js' - }, - jquery: { - src:['vendor/jquery/*.js'], - dest: '<%= distdir %>/jquery.js' - } - }, - min: { - dist:{ - src:['', ''], - dest:'<%= distdir %>/<%= pkg.name %>.js' - }, - angular: { - src:[''], - dest: '<%= distdir %>/angular.js' - }, - mongo: { - src:['vendor/mongolab/*.js'], - dest: '<%= distdir %>/mongolab.js' - }, - bootstrap: { - src:['vendor/bootstrap/*.js'], - dest: '<%= distdir %>/bootstrap.js' - }, - jquery: { - src:['vendor/jquery/*.js'], - dest: '<%= distdir %>/jquery.js' - } - }, - recess: { - build: { - src: [''], - dest: '<%= distdir %>/<%= pkg.name %>.css', - options: { - compile: true - } - }, - min: { - src: [''], - dest: '', - options: { - compress: true - } - } - }, - watch:{ - files:['', '', '', '', ''], - tasks:'default timestamp' - }, - jshint:{ - options:{ - curly:true, - eqeqeq:true, - immed:true, - latedef:true, - newcap:true, - noarg:true, - sub:true, - boss:true, - eqnull:true - }, - globals:{} - }, - uglify:{} - }); - - // Default task. - grunt.registerTask('default', 'lint build test:unit'); - grunt.registerTask('build', 'clean html2js concat recess:build index copy'); - grunt.registerTask('release', 'clean html2js min lint test recess:min index copy e2e'); - - // HTML stuff - grunt.registerTask('index', 'Process index.html', function(){ - grunt.file.copy('src/index.html', 'dist/index.html', {process:grunt.template.process}); - }); - - // Print a timestamp (useful for when watching) - grunt.registerTask('timestamp', function() { - grunt.log.subhead(Date()); - }); - -}; \ No newline at end of file diff --git a/client/gruntFile.js b/client/gruntFile.js new file mode 100644 index 00000000..e222e29d --- /dev/null +++ b/client/gruntFile.js @@ -0,0 +1,177 @@ +module.exports = function (grunt) { + + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-recess'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-testacular'); + grunt.loadTasks('build'); + + // Default task. + grunt.registerTask('default', ['jshint','build','testacular:unit']); + grunt.registerTask('build', ['clean','html2js','concat','recess:build','copy:assets']); + grunt.registerTask('release', ['clean','html2js','uglify','jshint','testacular:unit','concat:index', 'recess:min','copy:assets','testacular:e2e']); + + // Print a timestamp (useful for when watching) + grunt.registerTask('timestamp', function() { + grunt.log.subhead(Date()); + }); + + var testacularConfig = function(configFile) { + var options = { + configFile: configFile, + keepalive: true + }; + if ( process.env.TRAVIS ) { + options.browsers = ['Firefox']; + } + return options; + }; + + // Project configuration. + grunt.initConfig({ + distdir: 'dist', + pkg: grunt.file.readJSON('package.json'), + banner: + '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + + '<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' + + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' + + ' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n', + src: { + js: ['src/**/*.js', '<%= distdir %>/templates/**/*.js'], + specs: ['test/**/*.spec.js'], + scenarios: ['test/**/*.scenario.js'], + html: ['src/index.html'], + tpl: { + app: ['src/app/**/*.tpl.html'], + common: ['src/common/**/*.tpl.html'] + }, + less: ['src/less/stylesheet.less'] // recess:build doesn't accept ** in its file patterns + }, + clean: ['<%= distdir %>/*'], + copy: { + assets: { + files: [{ dest: '<%= distdir %>', src : '**', expand: true, cwd: 'src/assets/' }] + } + }, + testacular: { + unit: { options: testacularConfig('test/config/unit.js') }, + e2e: { options: testacularConfig('test/config/e2e.js') } + }, + html2js: { + app: { + options: { + base: 'src/app' + }, + src: ['<%= src.tpl.app %>'], + dest: '<%= distdir %>/templates/app.js', + module: 'templates.app' + }, + common: { + options: { + base: 'src/common' + }, + src: ['<%= src.tpl.common %>'], + dest: '<%= distdir %>/templates/common.js', + module: 'templates.common' + } + }, + concat:{ + dist:{ + options: { + banner: "<%= banner %>" + }, + src:['<%= src.js %>'], + dest:'<%= distdir %>/<%= pkg.name %>.js' + }, + index: { + src: ['src/index.html'], + dest: '<%= distdir %>/index.html', + options: { + process: true + } + }, + angular: { + src:['vendor/angular/angular.js'], + dest: '<%= distdir %>/angular.js' + }, + mongo: { + src:['vendor/mongolab/*.js'], + dest: '<%= distdir %>/mongolab.js' + }, + bootstrap: { + src:['vendor/angular-ui/bootstrap/*.js'], + dest: '<%= distdir %>/bootstrap.js' + }, + jquery: { + src:['vendor/jquery/*.js'], + dest: '<%= distdir %>/jquery.js' + } + }, + uglify: { + dist:{ + options: { + banner: "<%= banner %>" + }, + src:['<%= src.js %>'], + dest:'<%= distdir %>/<%= pkg.name %>.js' + }, + angular: { + src:['<%= concat.angular.src %>'], + dest: '<%= distdir %>/angular.js' + }, + mongo: { + src:['vendor/mongolab/*.js'], + dest: '<%= distdir %>/mongolab.js' + }, + bootstrap: { + src:['vendor/angular-ui/bootstrap/*.js'], + dest: '<%= distdir %>/bootstrap.js' + }, + jquery: { + src:['vendor/jquery/*.js'], + dest: '<%= distdir %>/jquery.js' + } + }, + recess: { + build: { + files: { + '<%= distdir %>/<%= pkg.name %>.css': + ['<%= src.less %>'] }, + options: { + compile: true + } + }, + min: { + files: { + '<%= distdir %>/<%= pkg.name %>.css': ['<%= src.less %>'] + }, + options: { + compress: true + } + } + }, + watch:{ + files:['<%= src.js %>', '<%= test.unit %>', '<%= src.less =>', '<%= src.tpl %>', '<%= src.html %>'], + tasks:'default timestamp' + }, + jshint:{ + files:['grunt.js', '<%= src.js %>', '<%= src.specs %>', '<%= src.scenarios %>'], + options:{ + curly:true, + eqeqeq:true, + immed:true, + latedef:true, + newcap:true, + noarg:true, + sub:true, + boss:true, + eqnull:true, + globals:{} + } + } + }); + +}; \ No newline at end of file diff --git a/client/package.json b/client/package.json index 4d233085..caeb9010 100644 --- a/client/package.json +++ b/client/package.json @@ -21,9 +21,13 @@ }, "dependencies": {}, "devDependencies": { - "grunt": "~0.3.17", - "grunt-recess": "~0.1.0", - "grunt-contrib-clean": "~0.3.0", - "grunt-contrib-copy": "~0.3.0" + "grunt": "~0.4.0", + "grunt-recess": "~0.3", + "grunt-contrib-clean": "~0.4.0", + "grunt-contrib-copy": "~0.4.0", + "grunt-contrib-jshint": "~0.2.0", + "grunt-contrib-concat": "~0.1.3", + "grunt-contrib-uglify": "~0.1.1", + "grunt-testacular": "~0.3.0" } } diff --git a/client/src/app/app.js b/client/src/app/app.js index 637e979e..63061787 100644 --- a/client/src/app/app.js +++ b/client/src/app/app.js @@ -8,7 +8,8 @@ angular.module('app', [ 'services.i18nNotifications', 'services.httpRequestTracker', 'directives.crud', - 'templates']); + 'templates.app', + 'templates.common']); angular.module('app').constant('MONGOLAB_CONFIG', { baseUrl: 'http://localhost:3000/databases/', diff --git a/client/src/app/dashboard/dashboard.js b/client/src/app/dashboard/dashboard.js index d4cc0651..96bc9d3a 100644 --- a/client/src/app/dashboard/dashboard.js +++ b/client/src/app/dashboard/dashboard.js @@ -1,4 +1,4 @@ -angular.module('dashboard', ['resources.projects', 'resources.tasks', 'services.authentication']) +angular.module('dashboard', ['resources.projects', 'resources.tasks']) .config(['$routeProvider', function ($routeProvider) { $routeProvider.when('/dashboard', { diff --git a/client/test/config/e2e.js b/client/test/config/e2e.js index 5426e4be..6efce844 100644 --- a/client/test/config/e2e.js +++ b/client/test/config/e2e.js @@ -46,4 +46,8 @@ autoWatchInterval = 0; // - Opera // - Safari // - PhantomJS -browsers = []; \ No newline at end of file +browsers = ['Chrome']; + +// Continuous Integration mode +// if true, it capture browsers, run tests and exit +singleRun = true; \ No newline at end of file diff --git a/client/test/config/unit.js b/client/test/config/unit.js index 59f685ae..06b9ebec 100644 --- a/client/test/config/unit.js +++ b/client/test/config/unit.js @@ -10,7 +10,7 @@ files = [ 'test/vendor/angular/angular-mocks.js', 'src/**/*.js', 'test/unit/**/*.spec.js', - 'dist/tmp/**/*.js' + 'dist/templates/**/*.js' ]; // use dots reporter, as travis terminal does not support escaping sequences @@ -20,10 +20,10 @@ reporters = 'progress'; // these are default values, just to show available options // web server port -port = 8080; +port = 8089; // cli runner port -runnerPort = 9100; +runnerPort = 9109; urlRoot = '/__testacular/'; @@ -47,4 +47,8 @@ autoWatchInterval = 0; // - Opera // - Safari // - PhantomJS -browsers = ['Chrome']; \ No newline at end of file +browsers = ['Chrome']; + +// Continuous Integration mode +// if true, it capture browsers, run tests and exit +singleRun = true; diff --git a/client/test/e2e/index.scenario.js b/client/test/e2e/index.scenario.js index cbbd55c5..1476d333 100644 --- a/client/test/e2e/index.scenario.js +++ b/client/test/e2e/index.scenario.js @@ -4,7 +4,7 @@ describe('my app', function() { browser().navigateTo('/'); }); - it('publicly accessible and default route to be /projectsinfo', function() { + it('should be publicly accessible and default route to be /projectsinfo', function() { expect(browser().location().path()).toBe("/projectsinfo"); }); }); \ No newline at end of file