gulp: gulp-my-tasks, npm module for running my gulp tasks
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Mon, 24 Aug 2015 20:25:02 +0000 (22:25 +0200)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Mon, 24 Aug 2015 20:25:02 +0000 (22:25 +0200)
In this way I should be able to use the same tasks in any AngularJS project
(if it follows my patterns)

gulp/gulp-my-tasks/index.js [new file with mode: 0644]
gulp/gulp-my-tasks/package.json [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/.htmlhintrc [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/.jscsrc [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/.jshintrc [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/favicon.ico [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/karma.conf.js [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/server.config.js [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/server.js [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/tasks.config.js [new file with mode: 0644]
gulp/gulp-my-tasks/tasks/tasks.js [new file with mode: 0644]

diff --git a/gulp/gulp-my-tasks/index.js b/gulp/gulp-my-tasks/index.js
new file mode 100644 (file)
index 0000000..97958dd
--- /dev/null
@@ -0,0 +1,3 @@
+module.exports = function(gulp, config){
+  require(__dirname + '/tasks/tasks.js')(gulp, config)
+};
diff --git a/gulp/gulp-my-tasks/package.json b/gulp/gulp-my-tasks/package.json
new file mode 100644 (file)
index 0000000..16cbd2b
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "name": "gulp-my-tasks",
+  "version": "0.0.1",
+  "description": "Gulp tasks for AngularJS projects",
+  "author": {
+    "name": "Gustavo Martin Morcuende",
+    "email": "noemail@noemail.invalid",
+    "url": "http://gumartinm.name"
+  },
+  "homepage": "http://gumartinm.name",
+  "license": "Apache-2.0",
+  "main" : "index.js",
+  "dependencies": {
+    "del": "~1.2.1",
+    "express": "~4.13.3",
+    "express-http-proxy": "~0.6.0",
+    "extend": "~3.0.0",
+    "gulp-angular-filesort": "~1.1.1",
+    "gulp-angular-templatecache": "~1.7.0",
+    "gulp-batch": "~1.0.5",
+    "gulp-bytediff": "~1.0.0",
+    "gulp-filter": "~3.0.0",
+    "gulp-header": "~1.2.2",
+    "gulp-htmlhint": "~0.3.0",
+    "gulp-if": "~1.2.5",
+    "gulp-inject": "~1.5.0",
+    "gulp-jscs": "~2.0.0",
+    "gulp-jshint": "~1.11.2",
+    "gulp-load-plugins": "~1.0.0-rc.1",
+    "gulp-minify-css": "~1.2.0",
+    "gulp-minify-html": "~1.0.4",
+    "gulp-ng-annotate": "~1.1.0",
+    "gulp-ngdocs": "~0.2.13",
+    "gulp-nodemon": "~2.0.3",
+    "gulp-order": "~1.1.1",
+    "gulp-print": "~1.1.0",
+    "gulp-rev": "~5.1.0",
+    "gulp-rev-replace": "~0.4.2",
+    "gulp-task-listing": "~1.0.1",
+    "gulp-uglify": "~1.2.0",
+    "gulp-useref": "~1.3.0",
+    "gulp-util": "~3.0.6",
+    "gulp-watch": "~4.3.5",
+    "jshint-stylish": "~2.0.1",
+    "karma": "~0.13.9",
+    "karma-coverage": "~0.5.0",
+    "karma-jasmine": "~0.3.6",
+    "karma-junit-reporter": "~0.3.3",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "morgan": "~1.6.1",
+    "serve-favicon": "~2.3.0",
+    "wiredep": "~3.0.0-beta",
+    "yargs": "~3.19.0"
+  },
+  "devDependencies": {
+    "gulp": "~3.9.0"
+  }
+}
diff --git a/gulp/gulp-my-tasks/tasks/.htmlhintrc b/gulp/gulp-my-tasks/tasks/.htmlhintrc
new file mode 100644 (file)
index 0000000..dc75d5f
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "tagname-lowercase": true,
+  "attr-lowercase": true,
+  "attr-value-double-quotes": true,
+  "attr-value-not-empty": false,
+  "attr-no-duplication" : true,
+  "doctype-first": true,
+  "tag-pair": true,
+  "tag-self-close": false,
+  "spec-char-escape": true,
+  "id-unique": true,
+  "src-not-empty": true,
+  "head-script-disabled": false
+}
\ No newline at end of file
diff --git a/gulp/gulp-my-tasks/tasks/.jscsrc b/gulp/gulp-my-tasks/tasks/.jscsrc
new file mode 100644 (file)
index 0000000..194fb59
--- /dev/null
@@ -0,0 +1,79 @@
+{
+  "excludeFiles": ["node_modules/**", "bower_components/**"],
+
+  "requireCurlyBraces": [
+    "if",
+    "else",
+    "for",
+    "while",
+    "do",
+    "try",
+    "catch"
+  ],
+  "requireOperatorBeforeLineBreak": true,
+  "requireCamelCaseOrUpperCaseIdentifiers": true,
+  "maximumLineLength": {
+    "value": 120,
+    "allowComments": true,
+    "allowRegex": true
+  },
+  "validateIndentation": 2,
+  "validateQuoteMarks": "'",
+
+  "disallowMultipleLineStrings": true,
+  "disallowMixedSpacesAndTabs": true,
+  "disallowTrailingWhitespace": true,
+  "disallowSpaceAfterPrefixUnaryOperators": true,
+  "disallowMultipleVarDecl": null,
+
+  "requireSpaceAfterKeywords": [
+    "if",
+    "else",
+    "for",
+    "while",
+    "do",
+    "switch",
+    "return",
+    "try",
+    "catch"
+  ],
+  "requireSpaceBeforeBinaryOperators": [
+    "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
+    "&=", "|=", "^=", "+=",
+
+    "+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
+    "|", "^", "&&", "||", "===", "==", ">=",
+    "<=", "<", ">", "!=", "!=="
+  ],
+  "requireSpaceAfterBinaryOperators": true,
+  "requireSpacesInConditionalExpression": true,
+  "requireSpaceBeforeBlockStatements": true,
+  "requireLineFeedAtFileEnd": true,
+  "disallowSpacesInsideObjectBrackets": "all",
+  "disallowSpacesInsideArrayBrackets": "all",
+  "disallowSpacesInsideParentheses": true,
+
+  "jsDoc": {
+    "checkAnnotations": {
+      "preset": "jsdoc3",
+      "extra": {
+        "ngdoc": true
+      }
+    },
+    "checkParamNames": true,
+    "requireParamTypes": true,
+    "checkReturnTypes": true,
+    "checkTypes": true
+  },
+
+  "disallowMultipleLineBreaks": true,
+
+  "disallowCommaBeforeLineBreak": null,
+  "disallowDanglingUnderscores": null,
+  "disallowEmptyBlocks": null,
+  "disallowTrailingComma": null,
+  "requireCommaBeforeLineBreak": null,
+  "requireDotNotation": null,
+  "requireMultipleVarDecl": null,
+  "requireParenthesesAroundIIFE": true
+}
diff --git a/gulp/gulp-my-tasks/tasks/.jshintrc b/gulp/gulp-my-tasks/tasks/.jshintrc
new file mode 100644 (file)
index 0000000..2e382d2
--- /dev/null
@@ -0,0 +1,69 @@
+{
+  "bitwise": true,
+  "camelcase": true,
+  "curly": true,
+  "eqeqeq": true,
+  "es3": false,
+  "forin": true,
+  "freeze": true,
+  "immed": true,
+  "indent": 2,
+  "latedef": "nofunc",
+  "newcap": true,
+  "noarg": true,
+  "noempty": true,
+  "nonbsp": true,
+  "nonew": true,
+  "plusplus": false,
+  "quotmark": "single",
+  "undef": true,
+  "unused": false,
+  "strict": false,
+  "maxparams": 10,
+  "maxdepth": 5,
+  "maxstatements": 40,
+  "maxcomplexity": 8,
+  "maxlen": 120,
+
+  "asi": false,
+  "boss": false,
+  "debug": false,
+  "eqnull": true,
+  "esnext": false,
+  "evil": false,
+  "expr": false,
+  "funcscope": false,
+  "globalstrict": false,
+  "iterator": false,
+  "lastsemic": false,
+  "laxbreak": false,
+  "laxcomma": false,
+  "loopfunc": true,
+  "maxerr": 9999,
+  "moz": false,
+  "multistr": false,
+  "notypeof": false,
+  "proto": false,
+  "scripturl": false,
+  "shadow": false,
+  "sub": true,
+  "supernew": false,
+  "validthis": false,
+  "noyield": false,
+
+  "browser": true,
+  "node": true,
+
+  "globals": {
+    "angular": false,
+    /* Jasmine */
+    "describe"   : false,
+    "expect"     : false,
+    "inject"     : false,
+    "it"         : false,
+    "before"     : false,
+    "beforeEach" : false,
+    "after"      : false,
+    "afterEach"  : false
+  }
+}
diff --git a/gulp/gulp-my-tasks/tasks/favicon.ico b/gulp/gulp-my-tasks/tasks/favicon.ico
new file mode 100644 (file)
index 0000000..b8e4f5f
Binary files /dev/null and b/gulp/gulp-my-tasks/tasks/favicon.ico differ
diff --git a/gulp/gulp-my-tasks/tasks/karma.conf.js b/gulp/gulp-my-tasks/tasks/karma.conf.js
new file mode 100644 (file)
index 0000000..79914f5
--- /dev/null
@@ -0,0 +1,105 @@
+// Karma configuration
+// http://karma-runner.github.io/0.12/config/configuration-file.html
+// Generated on 2015-08-16 using
+// generator-karma 1.0.0
+
+module.exports = function(config) {
+  'use strict';
+
+  config.set({
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+    // base path, that will be used to resolve files and exclude
+    basePath: '',
+
+    // testing framework to use (jasmine/mocha/qunit/...)
+    // as well as any additional frameworks (requirejs/chai/sinon/...)
+    frameworks: [
+      'jasmine'
+    ],
+
+    // list of files / patterns to load in the browser
+    files: [
+      //bower:js
+      //endbower
+    ],
+
+    // list of files / patterns to exclude
+    exclude: [
+    ],
+
+    // web server port
+    port: 8080,
+
+    // Start these browsers, currently available:
+    // - Chrome
+    // - ChromeCanary
+    // - Firefox
+    // - Opera
+    // - Safari (only Mac)
+    // - PhantomJS
+    // - IE (only Windows)
+    browsers: [
+      'PhantomJS'
+    ],
+
+    // Which plugins to enable
+    plugins: [
+      'karma-phantomjs-launcher',
+      'karma-jasmine',
+      'karma-coverage',
+      'karma-junit-reporter'
+    ],
+
+    // command line argument override the configuration from the config file
+    reporters: ['progress', 'junit', 'coverage'],
+
+    junitReporter: {
+      // results will be saved as $outputDir/$browserName.xml
+      outputDir: 'report',
+      // if included, results will be saved as $outputDir/$browserName/$outputFile
+      outputFile: 'test-results.xml'
+      // suite will become the package name attribute in xml testsuite element
+      // suite: ''
+    },
+
+    preprocessors: {
+      'src/showcase/app/**/!(*.spec)+(.js)': ['coverage']
+    },
+
+    coverageReporter: {
+      // specify a common output directory
+      dir: 'report/coverage',
+      reporters: [
+        // reporters not supporting the `file` property
+        {type: 'html', subdir: 'report-html'},
+        {type: 'lcov', subdir: 'report-lcov'},
+        // reporters supporting the `file` property, use `subdir` to directly
+        // output them in the `dir` directory
+        {type: 'cobertura', subdir: '.', file: 'cobertura.txt'},
+        {type: 'lcovonly', subdir: '.', file: 'report-lcovonly.txt'},
+        {type: 'teamcity', subdir: '.', file: 'teamcity.txt'},
+        {type: 'text', subdir: '.', file: 'text.txt'},
+        {type: 'text-summary'}
+      ]
+    },
+
+    // Continuous Integration mode
+    // if true, it capture browsers, run tests and exit
+    singleRun: false,
+
+    colors: true,
+
+    // level of logging
+    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+    logLevel: config.LOG_INFO
+
+    // Uncomment the following lines if you are using grunt's server to run the tests
+    // proxies: {
+    //   '/': 'http://localhost:9000/'
+    // },
+    // URL root prevent conflicts with the site root
+    // urlRoot: '_karma_'
+  });
+};
diff --git a/gulp/gulp-my-tasks/tasks/server.config.js b/gulp/gulp-my-tasks/tasks/server.config.js
new file mode 100644 (file)
index 0000000..7f9a2ad
--- /dev/null
@@ -0,0 +1,12 @@
+module.exports = function() {
+  var main = './src/showcase/';
+  var config = {
+    main: main,
+    index: main + 'index.html',
+    port: 9000,
+    script: './server.js',
+    directory: './server/'
+  };
+
+  return config;
+};
diff --git a/gulp/gulp-my-tasks/tasks/server.js b/gulp/gulp-my-tasks/tasks/server.js
new file mode 100644 (file)
index 0000000..a0c3991
--- /dev/null
@@ -0,0 +1,50 @@
+'use strict';
+
+var currentDir = process.cwd();
+var express = require('express');
+var app = express();
+var favicon = require('serve-favicon');
+var logger = require('morgan');
+var port = 9000;
+var environment = process.env.NODE_ENV;
+var verbose = process.env.VERBOSE;
+
+app.use(favicon(__dirname + '/favicon.ico'));
+if (verbose && verbose === true) {
+  app.use(logger('dev'));
+}
+
+switch (environment) {
+  case 'production':
+    console.log('production mode');
+
+    app.use(express.static(currentDir + '/build/'));
+
+    // Deep linking
+    app.use('/*', express.static(currentDir + '/build/index.html'));
+    break;
+  case 'ngdocs':
+    console.log('ngdocs mode');
+
+    app.use(express.static(currentDir + '/docs'));
+
+    // Deep linking
+    app.use('/*', express.static(currentDir + '/docs'));
+    break;
+  default:
+    console.log('development mode');
+
+    app.use(express.static(currentDir + '/src/showcase/'));
+    app.use(express.static(currentDir + '/'));
+
+    // Deep linking
+    app.use('/*', express.static(currentDir + '/src/showcase/index.html'));
+    break;
+}
+
+app.listen(port, function() {
+  console.log('Express server listening on port ' + port);
+  console.log('env = ' + app.get('env') +
+    '\n __dirname = ' + __dirname +
+    '\n process.cwd = ' + currentDir);
+});
diff --git a/gulp/gulp-my-tasks/tasks/tasks.config.js b/gulp/gulp-my-tasks/tasks/tasks.config.js
new file mode 100644 (file)
index 0000000..8710931
--- /dev/null
@@ -0,0 +1,99 @@
+module.exports = function() {
+  var main = './src/showcase/';
+  var app = main + 'app/';
+  var bower = {
+    json: require(process.cwd() + '/bower.json'),
+    directory: process.cwd() + '/bower_components/',
+    ignorePath: '../..'
+  };
+  var $ = {
+    path: require('path')
+  };
+
+  return {
+    main: main,
+    jsAllFiles: [
+      './src/**/*.js',
+      './*.js'
+    ],
+    jsFilesWithoutSpecs: [
+      app + '**/*.module.js',
+      app + '**/*.js',
+      '!' + app + '**/*.spec.js'
+    ],
+    jsFilesStubs: [
+      main + 'stubs/**/*.js'
+    ],
+    index: main + 'index.html',
+    jsHintConfigurationFile: $.path.join(__dirname, '.jshintrc'),
+    jscsConfigurationFile: $.path.join(__dirname, '.jscsrc'),
+    htmlHintConfigurationFile: $.path.join(__dirname, '.htmlhintrc'),
+
+    karmaConf: 'karma.conf.js',
+
+    build: {
+      directory: './build/'
+    },
+
+    html: app + '**/*.html',
+    templateFile: 'templates.js',
+
+    temp: './.tmp/',
+
+    /**
+     * wiredep options for index.html
+     */
+    wiredepOptions: {
+      // The directory of your Bower packages. default: '.bowerrc'.directory || bower_components
+      bowerJson: bower.json,
+      // Your bower.json file contents. default: require('./bower.json')
+      directory: bower.directory,
+      // string or regexp to ignore from the injected filepath
+      ignorePath: bower.ignorePath,
+      dependencies: true,     // default: true
+      onError: function(err) {
+        console.log('wiredep error: ' + err.code);
+      },
+      onFileUpdated: function(filePath) {
+        console.log('wiredep updated file: ' + filePath);
+      },
+      onPathInjected: function(fileObject) {
+        console.log('wiredep injected file: ' + fileObject.block);
+        console.log('wiredep injected file: ' + fileObject.file);
+        console.log('wiredep injected file: ' + fileObject.path);
+      },
+      onMainNotFound: function(pkg) {
+        console.log('wiredep name of bower package without main: ' + pkg);
+      }
+    },
+
+    /**
+     * wiredep options for karma.conf.js
+     */
+    wiredepKarmaOptions: {
+      // The directory of your Bower packages. default: '.bowerrc'.directory || bower_components
+      bowerJson: bower.json,
+      // Your bower.json file contents. default: require('./bower.json')
+      directory: bower.directory,
+      // string or regexp to ignore from the injected filepath
+      ignorePath: bower.ignorePath,
+      dependencies: true,     // default: true
+      devDependencies: true, // default: false
+      onError: function(err) {
+        console.log('wiredep error: ' + err.code);
+      },
+      onFileUpdated: function(filePath) {
+        console.log('wiredep updated file: ' + filePath);
+      },
+      onPathInjected: function(fileObject) {
+        console.log('wiredep injected file: ' + fileObject.block);
+        console.log('wiredep injected file: ' + fileObject.file);
+        console.log('wiredep injected file: ' + fileObject.path);
+      },
+      onMainNotFound: function(pkg) {
+        console.log('wiredep name of bower package without main: ' + pkg);
+      }
+    }
+  };
+
+};
diff --git a/gulp/gulp-my-tasks/tasks/tasks.js b/gulp/gulp-my-tasks/tasks/tasks.js
new file mode 100644 (file)
index 0000000..e1415e6
--- /dev/null
@@ -0,0 +1,505 @@
+module.exports = function(gulp, customConfig) {
+
+  var args = require('yargs').argv;
+  var extend = require('extend');
+  var config = require('./tasks.config')();
+  var del = require('del');
+  var plugins = require('gulp-load-plugins')({lazy: true});
+  var currentDir = process.cwd();
+  var $ = {
+    path: require('path')
+  };
+
+  extend(true, config, customConfig);
+
+  /**
+   * Arguments:
+   *
+   * [--verbose]  : Various tasks will produce more output to the console. No verbose by default.
+   * [--stubs]    : Using stubs in index.html (for mocking services, controllers or any other stuff)
+   * No stubs by default.
+   * [--environment production|development]  : Running tasks in production or development environment.
+   * Development by default.
+   */
+
+  /**
+   * Default tasks
+   *
+   */
+  gulp.task('help', plugins.taskListing);
+  gulp.task('default', ['help']);
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * vet (evaluate) the code and create coverage report.
+   *
+   * @returns {stream}
+   */
+  gulp.task('vet', ['vet-js', 'vet-html']);
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * vet (evaluate) the JavaScript code and create coverage report.
+   *
+   * @returns {stream}
+   */
+  gulp.task('vet-js', function() {
+
+    log('*** Checking JavaScript source files with JSHint and JSCS ***');
+
+    return gulp.src(config.jsAllFiles)
+      .pipe(plugins.if(args.verbose, plugins.print()))
+      .pipe(plugins.jshint(config.jsHintConfigurationFile))
+      .pipe(plugins.jshint.reporter('jshint-stylish', {verbose: true}))
+      .pipe(plugins.jshint.reporter('fail'))
+      .pipe(plugins.jscs({
+        configPath: config.jscsConfigurationFile,
+        fix: false
+      }));
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * vet (evaluate) the HTML code and create coverage report.
+   *
+   * @returns {stream}
+   */
+  gulp.task('vet-html', function() {
+
+    log('*** Checking HTML source files with HTMLHint ***');
+
+    return gulp.src(config.html)
+      .pipe(plugins.if(args.verbose, plugins.print()))
+      .pipe(plugins.htmlhint({htmlhintrc: config.htmlHintConfigurationFile}))
+      .pipe(plugins.htmlhint.failReporter());
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * wire up bower dependencies and inject files in index.html
+   *
+   * @returns {Stream}
+   */
+  gulp.task('wireup', function() {
+
+    log('*** Wiring bower dependencies and injecting files into html ***');
+
+    var wiredep = require('wiredep').stream;
+    var jsFiles = args.stubs ? [].concat(config.jsFilesWithoutSpecs, config.jsFilesStubs) : config.jsFilesWithoutSpecs;
+
+    return gulp.src(config.index)
+      .pipe(wiredep(config.wiredepOptions))
+      .pipe(inject(jsFiles, ''))
+      .pipe(gulp.dest(config.main));
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Runs HTTP server.
+   */
+  gulp.task('server', function(done) {
+    var environment = 'development';
+
+    if (args.environment) {
+      environment = args.environment;
+    }
+
+    log('*** Starting server in ' + environment + ' mode ***');
+
+    server(environment);
+    done();
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Runs specs once and exit.
+   *
+   * @returns {Stream}
+   */
+  gulp.task('test', ['vet'], function(done) {
+
+    log('*** Run tests once ***');
+
+    startTests(true, done);
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Run specs and wait. Watch for file changes and re-run tests on each change
+   */
+  gulp.task('autotest', function(done) {
+
+    log('*** Run tests and wait ***');
+
+    startTests(false, done);
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Builds application for production.
+   *
+   * @returns {stream} The stream.
+   */
+  gulp.task('build', ['wireup', 'templatecache'], function() {
+
+    log('*** Building application for production - Optimizing assets - HTML,CSS,JS ***');
+
+    var assets = plugins.useref.assets({searchPath: './'});
+    // Filters are named for the gulp-useref path
+    var cssFilter = plugins.filter('**/*.css', {restore: true});
+    var jsAppFilter = plugins.filter('**/app.min.js', {restore: true});
+    var jslibFilter = plugins.filter('**/lib.min.js', {restore: true});
+    var templateCache = config.temp + config.templateFile;
+
+    return gulp.src(config.index)
+
+      // Inject templates
+      .pipe(inject(templateCache, 'templates'))
+
+      // Gather all assets from the html with useref
+      .pipe(assets)
+
+      // Get the css
+      .pipe(cssFilter)
+      .pipe(plugins.if(args.verbose, plugins.bytediff.start()))
+      .pipe(plugins.minifyCss())
+      .pipe(plugins.if(args.verbose, plugins.bytediff.stop(byteDiffFormat)))
+      .pipe(cssFilter.restore)
+
+      // Get the custom javascript
+      .pipe(jsAppFilter)
+      .pipe(plugins.if(args.verbose, plugins.bytediff.start()))
+      .pipe(plugins.ngAnnotate({
+        //jscs:disable
+        single_quotes: true, // jshint ignore:line
+        //jscs:enable
+        add: true
+      }))
+      .pipe(plugins.uglify({
+        compress: {
+          //jscs:disable
+          drop_console: true, // jshint ignore:line
+          drop_debugger: true // jshint ignore:line
+          //jscs:enable
+        },
+        output: {
+          //jscs:disable
+          quote_style: 3 // jshint ignore:line
+          //jscs:enable
+        }
+      }))
+      .pipe(plugins.if(args.verbose, plugins.bytediff.stop(byteDiffFormat)))
+      .pipe(getHeader())
+      .pipe(jsAppFilter.restore)
+
+      // Get the vendor javascript
+      .pipe(jslibFilter)
+      .pipe(plugins.if(args.verbose, plugins.bytediff.start()))
+      .pipe(plugins.uglify({
+        output: {
+          //jscs:disable
+          quote_style: 3 // jshint ignore:line
+          //jscs:enable
+        }
+      }))
+      .pipe(plugins.if(args.verbose, plugins.bytediff.stop(byteDiffFormat)))
+      .pipe(jslibFilter.restore)
+
+      // Take inventory of the file names for future rev numbers
+      .pipe(plugins.rev())
+
+      // Apply the concat and file replacement with useref
+      .pipe(assets.restore())
+      .pipe(plugins.useref())
+
+      // Replace the file names in the html with rev numbers
+      .pipe(plugins.revReplace())
+
+      // Output to destination
+      .pipe(gulp.dest(config.build.directory));
+
+    /**
+     * @ngdoc function
+     *
+     * @description
+     * Format and return the header for files
+     *
+     * @returns {stream} The stream.
+     */
+    function getHeader() {
+      var pkg = require($.path.join(process.cwd(), 'package.json'));
+      var banner = ['/**',
+        ' * <%= pkg.name %> - <%= pkg.description %>',
+        ' * @author <%= pkg.author.name %>',
+        ' * @email <%= pkg.author.email %>',
+        ' * @url <%= pkg.author.url %>',
+        ' * @version <%= pkg.version %>',
+        ' * @link <%= pkg.homepage %>',
+        ' * @license <%= pkg.license %>',
+        ' */',
+        ''
+      ].join('\n');
+      return plugins.header(banner, {pkg: pkg});
+    }
+
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Cleans up files in distribution directory.
+   *
+   * @returns {undefined}
+   */
+  gulp.task('clean', function(done) {
+
+    log('*** Cleans up directories ***');
+
+    del.sync([config.build.directory + '**/*', config.temp]);
+    done();
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Creates $templateCache from html templates
+   *
+   * @returns {stream}
+   */
+  gulp.task('templatecache', ['clean'], function() {
+
+    log('*** Creating AngularJS $templateCache ***');
+
+    return gulp
+      .src(config.html)
+      .pipe(plugins.if(args.verbose, plugins.bytediff.start()))
+      .pipe(plugins.minifyHtml({
+        empty: true,
+        spare: true,
+        quotes: true
+      }))
+      .pipe(plugins.if(args.verbose, plugins.bytediff.stop(byteDiffFormat)))
+      .pipe(plugins.angularTemplatecache(config.templateFile, {
+          module: 'app.core',
+          root: 'app/',
+          standalone: false
+        }
+      ))
+      .pipe(gulp.dest(config.temp));
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Generate documentation
+   *
+   * @returns {stream}
+   */
+  gulp.task('ngdocs', function() {
+    var pkg = require($.path.join(process.cwd(), 'package.json'));
+    var gulpDocs = require('gulp-ngdocs');
+    var options = {
+      html5Mode: true,
+      startPage: '/api/app',
+      title: pkg.description
+    };
+    return gulpDocs.sections({
+      api: {
+        glob:['src/**/*.js', '!src/**/*.spec.js'],
+        api: true,
+        title: 'API Documentation'
+      }})
+      .pipe(gulpDocs.process(options))
+      .pipe(gulp.dest('./docs'));
+  });
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Inject files in a sorted sequence at a specified inject label.
+   *
+   * @param {Array|string} source Source files (glob patterns)
+   * @param {string=} label The label name to be used by gulp-inject.
+   * @returns {stream} The stream.
+   */
+  function inject(source, label) {
+    var options = {relative: false};
+    if (label) {
+      options.name = 'inject:' + label;
+    }
+
+    return plugins.inject(
+      gulp.src(source)
+        .pipe(plugins.angularFilesort()), options);
+  }
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Runs HTTP server.
+   *
+   * @param  {string=} [environment='development'] development or production environments.
+   * @returns {stream} The stream
+   */
+  function server(environment) {
+    var nodeOptions = {
+      script: __dirname + '/server.js',
+      env: {
+        'NODE_ENV': environment ? environment : 'development',
+        'VERBOSE': args.verbose ? true : false
+      },
+      verbose: args.verbose ? true : false,
+      watch: [__dirname + '/server.js'],
+      delay: 250  // 250ms
+    };
+
+    return plugins.nodemon(nodeOptions)
+      .on('restart', function(ev) {
+        log('HTTP server restarted');
+        log('files changed:\n' + ev);
+      })
+      .on('start', function () {
+        log('HTTP server started');
+        synchronization(environment);
+      })
+      .on('crash', function () {
+        log('HTTP server crashed');
+      })
+      .on('exit', function () {
+        log('HTTP server exited');
+      });
+  }
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Tests runner, karma launcher.
+   *
+   * @param  {boolean} singleRun True means run once and end (continuous integration), or keep running (development)
+   * @param  {function} done Callback to fire when karma is done
+   * @returns {undefined}
+   */
+  function startTests(singleRun, done) {
+    var wiredep = require('wiredep');
+    var bowerFiles = wiredep(config.wiredepKarmaOptions)['js'];
+    var excludeFiles = [];
+    var Server = require('karma').Server;
+    var karma = new Server({
+      files: [].concat(
+        bowerFiles,
+        process.cwd() + '/src/showcase/app/**/*.module.js',
+        process.cwd() + '/src/showcase/app/**/*.js'
+      ),
+      configFile: __dirname + '/karma.conf.js',
+      exclude: excludeFiles,
+      singleRun: singleRun
+    }, doneKarma);
+
+    karma.start();
+
+    function doneKarma(result) {
+      log('Karma completed');
+      log('Karma: tests exited with code ' + result);
+      done();
+    }
+  }
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Log messages to CLI.
+   *
+   * @param  {string} message The message to be shown.
+   * @returns {undefined}
+   */
+  function log(message) {
+    plugins.util.log(plugins.util.colors.blue(message));
+  }
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Format data generated by the gulp-bytediff plugin.
+   *
+   * @param  {Object} data The data created by gulp-bytediff plugin.
+   * @returns {string}
+   */
+  function byteDiffFormat(data) {
+    var difference = (data.savings > 0) ? ' smaller.' : ' larger.';
+    return data.fileName + ' is ' + data.percent + '%' + difference;
+  }
+
+  /**
+   * @ngdoc function
+   *
+   * @description
+   * Files synchronization.
+   *
+   * @param  {string=} [environment='development'] development or production environments.
+   * @returns {undefined}
+   */
+  function synchronization(environment) {
+
+    log('Files synchronization');
+
+    var jsFiles = args.stubs ? [].concat(config.jsFilesWithoutSpecs, config.jsFilesStubs) : config.jsFilesWithoutSpecs;
+
+    switch (environment) {
+      case 'production':
+        jsFiles = jsFiles.concat(config.html);
+        plugins.watch(jsFiles, {
+          name: 'Files synchronization',
+          verbose: true,
+          readDelay: 250
+        }, plugins.batch(function (events, done) {
+          // TODO: gulp.start going to be deprecated in gulp 4.0.0 version. Alternatives?
+          gulp.start('build', done);
+        }));
+        break;
+      case 'ngdocs':
+        plugins.watch(jsFiles, {
+          name: 'Files synchronization',
+          verbose: true,
+          readDelay: 250
+        }, plugins.batch(function (events, done) {
+          // TODO: gulp.start going to be deprecated in gulp 4.0.0 version. Alternatives?
+          gulp.start('ngdocs', done);
+        }));
+        break;
+      default:
+        plugins.watch(jsFiles, {
+          name: 'Files synchronization',
+          verbose: true,
+          readDelay: 250
+        }, plugins.batch(function (events, done) {
+          // TODO: gulp.start going to be deprecated in gulp 4.0.0 version. Alternatives?
+          gulp.start('wireup', done);
+        }));
+        break;
+    }
+  }
+};