diff --git a/app/directives/badges/badge-tooltip.spec.js b/app/directives/badges/badge-tooltip.spec.js index bff215de8..afc066e09 100644 --- a/app/directives/badges/badge-tooltip.spec.js +++ b/app/directives/badges/badge-tooltip.spec.js @@ -1,5 +1,5 @@ /* jshint -W117, -W030 */ -describe('Badge Tooltiop Directive', function() { +describe('Badge Tooltip Directive', function() { var scope; var element; var badge = mockData.getMockBadge(); diff --git a/app/index.jade b/app/index.jade index 65b8274b9..ed2cf125e 100644 --- a/app/index.jade +++ b/app/index.jade @@ -16,7 +16,6 @@ html link(rel='stylesheet', href='../bower_components/angular-dropdowns/dist/angular-dropdowns.css') link(rel='stylesheet', href='../bower_components/intro.js/introjs.css') link(rel='stylesheet', href='../bower_components/angularjs-toaster/toaster.css') - link(rel='stylesheet', href='../bower_components/devicon/devicon.min.css') link(rel='stylesheet', href='../bower_components/fontawesome/css/font-awesome.css') link(rel='stylesheet', href='../bower_components/ng-notifications-bar/dist/ngNotificationsBar.min.css') link(rel='stylesheet', href='../bower_components/ngDialog/css/ngDialog.css') diff --git a/app/specs.html b/app/specs.html index d70c81ed1..e8b01d7cc 100644 --- a/app/specs.html +++ b/app/specs.html @@ -51,6 +51,7 @@

Spec Runner

+ @@ -167,6 +168,7 @@

Spec Runner

+ @@ -175,7 +177,6 @@

Spec Runner

- @@ -255,36 +256,35 @@

Spec Runner

- + - + - - - - + + + + - - + - + diff --git a/app/topcoder.constants.js b/app/topcoder.constants.js old mode 100755 new mode 100644 diff --git a/assets/css/account/account.scss b/assets/css/account/account.scss index fa5deea71..9f4333598 100644 --- a/assets/css/account/account.scss +++ b/assets/css/account/account.scss @@ -186,7 +186,7 @@ } .github { .ico { - background-image: url(/images/svg/github.svg); + background-image: url(/images/github.svg); background-repeat: no-repeat; color: #404041; } @@ -194,7 +194,7 @@ .facebook { margin-left: 41px; .ico { - background-image: url(/images/svg/facebook.svg); + background-image: url(/images/facebook.svg); background-repeat: no-repeat; color: #0d72b9; } @@ -202,7 +202,7 @@ .google-plus { margin-left: 43px; .ico { - background-image: url(/images/svg/gplus.svg); + background-image: url(/images/gplus.svg); background-position: center; background-repeat: no-repeat; border: 1px solid #d1d3d4; @@ -213,7 +213,7 @@ .twitter { margin-left: 40px; .ico { - background-image: url(/images/svg/twitter.svg); + background-image: url(/images/twitter.svg); background-repeat: no-repeat; color: #26a9e0; } diff --git a/assets/css/directives/external-web-link.scss b/assets/css/directives/external-web-link.scss index 6c8811045..9a49fcc4e 100644 --- a/assets/css/directives/external-web-link.scss +++ b/assets/css/directives/external-web-link.scss @@ -1,4 +1,4 @@ -@import 'tc-includes'; +@import 'topcoder/tc-includes'; external-web-link { .web-link { @@ -23,7 +23,7 @@ external-web-link { } .form-field { @include form-field; - @include ui-form-placeholder; + &:disabled { color: #B7B7B7; } @@ -31,7 +31,7 @@ external-web-link { .form-field-focused { @include form-field-focused; } - + .validation-bar.url { flex: 1; width: auto; diff --git a/assets/fonts/devicon.eot b/assets/fonts/devicon.eot deleted file mode 100755 index 8a40b765a..000000000 Binary files a/assets/fonts/devicon.eot and /dev/null differ diff --git a/assets/fonts/devicon.svg b/assets/fonts/devicon.svg deleted file mode 100755 index 68a19decf..000000000 --- a/assets/fonts/devicon.svg +++ /dev/null @@ -1,155 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/fonts/devicon.ttf b/assets/fonts/devicon.ttf deleted file mode 100755 index a7cd8f4dd..000000000 Binary files a/assets/fonts/devicon.ttf and /dev/null differ diff --git a/assets/fonts/devicon.woff b/assets/fonts/devicon.woff deleted file mode 100755 index e1e0d112d..000000000 Binary files a/assets/fonts/devicon.woff and /dev/null differ diff --git a/assets/images/svg/facebook.svg b/assets/images/facebook.svg similarity index 100% rename from assets/images/svg/facebook.svg rename to assets/images/facebook.svg diff --git a/assets/images/svg/github.svg b/assets/images/github.svg similarity index 100% rename from assets/images/svg/github.svg rename to assets/images/github.svg diff --git a/assets/images/svg/gplus.svg b/assets/images/gplus.svg similarity index 100% rename from assets/images/svg/gplus.svg rename to assets/images/gplus.svg diff --git a/assets/images/svg/twitter.svg b/assets/images/twitter.svg similarity index 100% rename from assets/images/svg/twitter.svg rename to assets/images/twitter.svg diff --git a/bower.json b/bower.json index a46e8baca..46f63e492 100644 --- a/bower.json +++ b/bower.json @@ -40,7 +40,6 @@ "angularjs-toaster": "~0.4.15", "appirio-tech-ng-iso-constants": "git@github.com:appirio-tech/ng-iso-constants#~1.0.5", "d3": "~3.5.6", - "devicon": "*", "fontawesome": "~4.3.0", "jstzdetect": "~1.0.6", "moment": "~2.10.3", diff --git a/config.js b/config.js index fe3cae590..f35fc241e 100644 --- a/config.js +++ b/config.js @@ -1,5 +1,5 @@ module.exports = function() { - var constants = { + return { 'development': { 'CONSTANTS': { API_URL: process.env.API_URL || 'https://api.topcoder-dev.com/v3', @@ -231,6 +231,4 @@ module.exports = function() { } } }; - - return constants; }; diff --git a/gulp-tasks/build.js b/gulp-tasks/build.js new file mode 100644 index 000000000..f23492923 --- /dev/null +++ b/gulp-tasks/build.js @@ -0,0 +1,44 @@ +var runSequence = require('run-sequence'); + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('build', function(done) { + utilities.log('Building everything'); + + runSequence( + 'clean', + ['optimize', 'fonts'] + ); + + utilities.clean(config.temp, done); + }); + + gulp.task('build-specs', ['templatecache', 'ngConstants'], function() { + utilities.log('Building the spec runner'); + + var wiredep = require('wiredep').stream; + var options = config.getWiredepDefaultOptions(); + options.devDependencies = true; + + return gulp + .src(config.specRunner) + .pipe(wiredep(options)) + .pipe($.inject(gulp.src(config.testlibraries), + {name: 'inject:testlibraries', read: false})) + .pipe($.inject(gulp.src(config.nonBowerScripts), + {name: 'inject:nonBowerScripts', read: false})) + .pipe($.inject( + gulp.src(config.js) + .pipe($.naturalSort()) + .pipe($.angularFilesort()) + )) + .pipe($.inject(gulp.src(config.specHelpers), + {name: 'inject:spechelpers', read: false})) + .pipe($.inject(gulp.src(config.specs), + {name: 'inject:specs', read: false})) + .pipe($.inject(gulp.src(config.temp + config.templateCache.file), + {name: 'inject:templates', read: false})) + .pipe(gulp.dest(config.app)); + }); +}; diff --git a/gulp-tasks/clean.js b/gulp-tasks/clean.js new file mode 100644 index 000000000..ca1df8777 --- /dev/null +++ b/gulp-tasks/clean.js @@ -0,0 +1,11 @@ +var del = require('del'); // rm -rf + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('clean', function(done) { + var delconfig = [].concat(config.build, config.temp); + utilities.log('Cleaning: ' + $.util.colors.blue(delconfig)); + del(delconfig, done); + }); +}; diff --git a/gulp-tasks/copy-files.js b/gulp-tasks/copy-files.js new file mode 100644 index 000000000..480ddf670 --- /dev/null +++ b/gulp-tasks/copy-files.js @@ -0,0 +1,11 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('copy-html', function() { + utilities.log('Moving app html files to .tmp'); + + return gulp + .src([config.app + '**/*.html', '!' + config.app + 'specs.html']) + .pipe(gulp.dest(config.temp)); + }); +}; diff --git a/gulp-tasks/deploy.js b/gulp-tasks/deploy.js new file mode 100644 index 000000000..4cfe8f455 --- /dev/null +++ b/gulp-tasks/deploy.js @@ -0,0 +1,54 @@ +var merge = require('merge-stream'); +var awspublishRouter = require('gulp-awspublish-router'); + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('deploy', ['build'], function() { + var awsConfig = { + params: { + Bucket: config.aws.bucket + }, + "accessKeyId": config.aws.key, + "secretAccessKey": config.aws.secret + }; + + // create a new publisher + var publisher = $.awspublish.create(awsConfig); + + utilities.log('Deploying to S3'); + + var gzip = gulp.src(['build/**/*.js', 'build/**/*.css']).pipe($.awspublish.gzip()) + .pipe(awspublishRouter({ + cache: { + cacheTime: 94608000, + allowTransform: false, + public: true + }, + routes: { + "^.+$": "$&" + } + })); + + var plain = gulp.src(['build/**/*', '!build/**/*.js', '!build/**/*.css']) + .pipe(awspublishRouter({ + cache: { + cacheTime: 94608000, + allowTransform: false, + public: true + }, + routes: { + "^.+\\.html": { + cacheTime: 0 + }, + "^.+$": "$&" + } + })); + + return merge(gzip, plain) + .pipe(publisher.cache()) + .pipe(publisher.publish()) + .pipe($.if(!config.production, publisher.sync())) + .pipe($.awspublish.reporter()); + }); +}; diff --git a/gulp-tasks/e2e.js b/gulp-tasks/e2e.js new file mode 100644 index 000000000..20a42af47 --- /dev/null +++ b/gulp-tasks/e2e.js @@ -0,0 +1,15 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('e2e', function() { + return gulp + .src(['./tests/e2e/app/*.js']) + .pipe($.angularProtractor({ + 'configFile': 'tests/e2e/conf.js', + 'args': ['--baseUrl', 'http://127.0.0.1:8000'], + 'autoStartStopServer': true, + 'debug': true + })) + .on('error', function(e) { throw e }); + }); +}; diff --git a/gulp-tasks/fonts.js b/gulp-tasks/fonts.js new file mode 100644 index 000000000..f0900d064 --- /dev/null +++ b/gulp-tasks/fonts.js @@ -0,0 +1,11 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('fonts', function() { + utilities.log('Copying fonts'); + + return gulp + .src([config.fonts, 'bower_components/fontawesome/fonts/fontawesome-webfont.*']) + .pipe(gulp.dest(config.build + 'fonts')); + }); +}; diff --git a/gulp-tasks/images.js b/gulp-tasks/images.js new file mode 100644 index 000000000..0b396b1c3 --- /dev/null +++ b/gulp-tasks/images.js @@ -0,0 +1,20 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('images', ['images:move-skills'], function() { + utilities.log('Copying and compressing the images'); + + return gulp + .src([config.images, '!' + config.assets + 'images/skills/**.*']) + .pipe($.imagemin({optimizationLevel: 4})) + .pipe(gulp.dest(config.temp + 'images')); + }); + + gulp.task('images:move-skills', function() { + utilities.log('Copying original skill icons to build folder'); + + return gulp + .src(config.assets + 'images/skills/**.*') + .pipe(gulp.dest(config.build + 'images/skills')); + }); +}; diff --git a/gulp-tasks/inject.js b/gulp-tasks/inject.js new file mode 100644 index 000000000..5d81ccbb1 --- /dev/null +++ b/gulp-tasks/inject.js @@ -0,0 +1,36 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('wiredep', ['jade'], function() { + utilities.log('Injecting bower css/js and app js files into index.jade'); + var options = config.getWiredepDefaultOptions(); + var wiredep = require('wiredep').stream; + + return gulp + .src(config.index) + .pipe(wiredep(options)) + .pipe($.inject( + gulp.src(config.js) + .pipe($.naturalSort('desc')) + .pipe($.angularFilesort()), + {relative: true})) + .pipe($.inject(gulp.src(config.nonBowerScripts, {read: false}), { + starttag: '//- inject:nonBowerScripts', + endtag: '//- endinject', + ignorePath: 'assets/' + })) + .pipe(gulp.dest(config.app)); + }); + + gulp.task('inject', ['wiredep', 'styles', 'templatecache'], function() { + utilities.log('Injecting app css into index.jade'); + + return gulp + .src(config.index) + .pipe($.inject( // Sort the css (topcoder.css, then everything else) + gulp.src(config.css, {read: false}) + .pipe($.naturalSort('desc')), + {ignorePath: '.tmp', addRootSlash: false})) + .pipe(gulp.dest(config.app)); + }); +}; diff --git a/gulp-tasks/jade.js b/gulp-tasks/jade.js new file mode 100644 index 000000000..1aee4b4e0 --- /dev/null +++ b/gulp-tasks/jade.js @@ -0,0 +1,20 @@ +var envFile = require('../config.js')(); +var envConfig = envFile[process.env.ENVIRONMENT || 'development']; + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('jade', function() { + utilities.log('Compiling Jade --> HTML'); + + return gulp + .src(config.jade) + .pipe($.plumber()) + .pipe($.data(function(file) { + return envConfig; + })) + .pipe($.jade({pretty: true})) + .pipe($.replace(/-->/g, ' -->')) + .pipe(gulp.dest(config.temp)); + }); +}; diff --git a/gulp-tasks/linters.js b/gulp-tasks/linters.js new file mode 100644 index 000000000..a83c765d6 --- /dev/null +++ b/gulp-tasks/linters.js @@ -0,0 +1,17 @@ +var args = require('yargs').argv; + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('vet', function() { + utilities.log('Analyzing source with JSHint and JSCS'); + + return gulp + .src(config.alljs) + .pipe($.if(args.verbose, $.print())) // gulp vet --verbose to trigger this line + .pipe($.jscs()) + .pipe($.jshint()) + .pipe($.jshint.reporter('jshint-stylish', {verbose: true})) + .pipe($.jshint.reporter('fail')); + }); +}; diff --git a/gulp-tasks/ng-constants.js b/gulp-tasks/ng-constants.js new file mode 100644 index 000000000..8d623190e --- /dev/null +++ b/gulp-tasks/ng-constants.js @@ -0,0 +1,18 @@ +var envFile = require('../config.js')(); +var envConfig = envFile[process.env.ENVIRONMENT || 'development']; + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('ngConstants', function() { + utilities.log('Creating ng-constants file') + + return $.ngConstant({ + name: 'CONSTANTS', + constants: envConfig, + stream: true + }) + .pipe($.rename('topcoder.constants.js')) + .pipe(gulp.dest(config.app)); + }); +}; diff --git a/gulp-tasks/optimize.js b/gulp-tasks/optimize.js new file mode 100644 index 000000000..d1b90da22 --- /dev/null +++ b/gulp-tasks/optimize.js @@ -0,0 +1,56 @@ +var envFile = require('../config.js')(); +var envConfig = envFile[process.env.ENVIRONMENT || 'development']; +var RevAll = require('gulp-rev-all'); +var merge = require('merge-stream'); + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('optimize', ['inject', 'test', 'ngConstants', 'images'], function() { + utilities.log('Optimizing the JavaScript, CSS, and HTML'); + + var assets = $.useref.assets({searchPath: ['.tmp', 'app', 'assets']}); + var templateCache = config.temp + config.templateCache.file; + var cssFilter = $.filter('**/*.css'); + var jsLibFilter = $.filter('**/' + config.optimized.vendor); + var jsAppFilter = $.filter('**/' + config.optimized.app); + + var imageStream = gulp.src(config.temp + '/**/*.{svg,png,jpg,jpeg,gif}'); + var userefStream = gulp + .src(config.indexHtml) + .pipe($.plumber()) + .pipe($.inject(gulp.src(templateCache, {read: false}), { + starttag: '', + endtag: '', + relative: true + })) + .pipe(assets) + .pipe(cssFilter) + .pipe($.csso()) + .pipe(cssFilter.restore()) + .pipe(jsLibFilter) + .pipe($.uglify()) + .pipe(jsLibFilter.restore()) + .pipe(jsAppFilter) + .pipe($.if(!config.production && !config.qa, $.sourcemaps.init())) + .pipe($.ngAnnotate()) + .pipe($.uglify()) + .pipe(jsAppFilter.restore()) + .pipe(assets.restore()) + .pipe($.useref()) + + var revAll = new RevAll({ + prefix: envConfig.CONSTANTS.ASSET_PREFIX, + dontRenameFile: [/^\/index.html/g] + }); + + return merge(userefStream, imageStream) + .pipe(revAll.revision()) + .pipe($.if(!config.production && !config.qa, $.sourcemaps.write())) + // Uncomment if you want to see the JSON file containing + // the file mapping (e.g., "{"js/app.js": "js/app-a9bae026bc.js"}") + // .pipe(gulp.dest(config.build)) + // .pipe(revAll.manifestFile()) + .pipe(gulp.dest(config.build)); + }); +}; diff --git a/gulp-tasks/scss.js b/gulp-tasks/scss.js new file mode 100644 index 000000000..3da29f550 --- /dev/null +++ b/gulp-tasks/scss.js @@ -0,0 +1,24 @@ +var envFile = require('../config.js')(); +var envConfig = envFile[process.env.ENVIRONMENT || 'development']; + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('styles', function() { + utilities.log('Compiling Sass --> CSS'); + + var assetPrefix = envConfig.CONSTANTS.ASSET_PREFIX.length ? envConfig.CONSTANTS.ASSET_PREFIX : '/'; + + return gulp + .src(config.sass, {base: './'}) + .pipe($.plumber()) + .pipe($.sass({includePaths: require('appirio-styles').includePaths})) + .pipe($.autoprefixer({browsers: ['last 2 version']})) + .pipe($.replace(/\/fonts/g, assetPrefix + 'fonts')) + .pipe(gulp.dest(config.temp)); + }); + + gulp.task('sass-watcher', function() { + gulp.watch([config.sass], ['styles']); + }); +}; diff --git a/gulp-tasks/serve.js b/gulp-tasks/serve.js new file mode 100644 index 000000000..1e36e31f3 --- /dev/null +++ b/gulp-tasks/serve.js @@ -0,0 +1,101 @@ +var browserSync = require('browser-sync'); +var histFallback = require('connect-history-api-fallback'); + +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('serve', ['inject', 'ngConstants'], function() { + gulp.watch(config.sass, ['styles']) + .on('change', function(event) { utilities.changeEvent(event); }); + + gulp.watch(config.jade, ['templatecache']) + .on('change', function(event) { utilities.changeEvent(event); }); + + var options = { + server: { + baseDir: [config.temp, config.app, config.assets], + // Enables serving index.html for Angular HTML5 mode + middleware: [histFallback()], + routes: { + '/bower_components': 'bower_components' + } + }, + files: config.watchFiles, + ghostMode: { + clicks: true, + location: false, + forms: true, + scroll: true + }, + logPrefix: 'Topcoder-Account', + notify: false, + port: 3000, + reloadDelay: 1000 + }; + + browserSync(options); + + }); + + gulp.task('serve-specs', ['build-specs'], function() { + utilities.log('Run the spec runner'); + + gulp.watch(config.sass, ['styles']) + .on('change', function(event) { utilities.changeEvent(event); }); + + gulp.watch(config.jade, ['templatecache']) + .on('change', function(event) { utilities.changeEvent(event); }); + + var options = { + server: { + baseDir: ['./'], + // Enables serving index.html for Angular HTML5 mode + middleware: [histFallback()], + routes: { + '/bower_components': 'bower_components' + } + }, + files: config.watchFiles, + ghostMode: { + clicks: true, + location: false, + forms: true, + scroll: true + }, + logPrefix: 'Topcoder-Account', + notify: false, + reloadDelay: 1000, + startPath: config.app + config.specRunnerFile + }; + + browserSync(options); + }); + + gulp.task('serve-build', ['build'], function() { + // TODO: Figure out why watch doesn't work. Jade running before wiredep? + + gulp.watch([config.sass, config.js, config.jade], ['optimize', browserSync.reload]) + .on('change', function(event) { utilities.changeEvent(event); }); + + var options = { + server: { + baseDir: config.build, + // Enables serving index.html for Angular HTML5 mode + middleware: [histFallback()] + }, + files: [], + ghostMode: { + clicks: true, + location: false, + forms: true, + scroll: true + }, + logPrefix: 'Topcoder-Account', + notify: false, + reloadDelay: 1000 + }; + + browserSync(options); + + }); +}; diff --git a/gulp-tasks/template-cache.js b/gulp-tasks/template-cache.js new file mode 100644 index 000000000..b2135367b --- /dev/null +++ b/gulp-tasks/template-cache.js @@ -0,0 +1,16 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + gulp.task('templatecache', ['jade'], function() { + utilities.log('Creating AngularJS $templateCache'); + + return gulp + .src(config.htmltemplates) + .pipe($.minifyHtml({empty: true})) + .pipe($.angularTemplatecache( + config.templateCache.file, + config.templateCache.options + )) + .pipe(gulp.dest(config.temp)); + }); +}; diff --git a/gulp-tasks/tests.js b/gulp-tasks/tests.js new file mode 100644 index 000000000..6eca779fa --- /dev/null +++ b/gulp-tasks/tests.js @@ -0,0 +1,12 @@ +module.exports = function(gulp, $, config, utilities) { + 'use strict'; + + // vet should be run before tests + gulp.task('test', ['templatecache', 'ngConstants'], function(done) { + utilities.startTests(true /* singleRun */, done); + }); + + gulp.task('autotest', ['vet', 'templatecache', 'ngConstants'], function(done) { + utilities.startTests(false, done); + }); +}; diff --git a/gulp-tasks/utilities.js b/gulp-tasks/utilities.js new file mode 100644 index 000000000..267641f12 --- /dev/null +++ b/gulp-tasks/utilities.js @@ -0,0 +1,51 @@ +var config = require('../gulp.config')(); +var util = require('gulp-util'); +var del = require('del'); // rm -rf +var path = require('path'); + +exports.changeEvent = function(event) { + var srcPattern = new RegExp('/.*(?=/' + config.source + ')/'); + this.log('File ' + event.path.replace(srcPattern, '') + ' ' + event.type); +} + +exports.clean = function(path, done) { + this.log('Cleaning: ' + util.colors.blue(path)); + del(path, done); +} + +exports.log = function(msg) { + if (typeof(msg) === 'object') { + for (var item in msg) { + if (msg.hasOwnProperty(item)) { + util.log(util.colors.blue(msg[item])); + } + } + } else { + util.log(util.colors.blue(msg)); + } +} + +exports.startTests = function(singleRun, done) { + var karma = require('karma').server; + var excludeFiles = []; + var serverSpecs = config.serverIntegrationSpecs; + + excludeFiles = serverSpecs; + + karma.start({ + configFile: path.join(__dirname,'../karma.conf.js'), + exclude: excludeFiles, + singleRun: !!singleRun + }, karmaCompleted.bind(this)); + + function karmaCompleted(karmaResult) { + this.log('Karma completed!'); + if (karmaResult === 1) { + done('karma: tests failed with code ' + karmaResult); + } else { + done(); + } + } +} + +return module.exports; diff --git a/gulpfile.js b/gulpfile.js index 29761e9e5..7e5ffe30c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,494 +1,19 @@ -var gulp = require('gulp'); -var args = require('yargs').argv; -var config = require('./gulp.config')(); -var del = require('del'); // rm -rf -var fs = require('fs'); -var $ = require('gulp-load-plugins')({lazy: true}); -var browserSync = require('browser-sync'); -var histFallback = require('connect-history-api-fallback'); -var merge = require('merge-stream'); -var RevAll = require('gulp-rev-all'); -var styleguide = require('sc5-styleguide'); -var awspublishRouter = require('gulp-awspublish-router'); +'use strict'; -var envFile = require('./config.js')(); -var envConfig = envFile[process.env.ENVIRONMENT || 'development']; +var gulp = require('gulp'); +var plugins = require('gulp-load-plugins')({lazy: true}); -gulp.task('help', $.taskListing); -gulp.task('default', ['help']); - -gulp.task('vet', function() { - log('Analyzing source with JSHint and JSCS'); - - return gulp - .src(config.alljs) - .pipe($.if(args.verbose, $.print())) // gulp vet --verbose to trigger this line - .pipe($.jscs()) - .pipe($.jshint()) - .pipe($.jshint.reporter('jshint-stylish', {verbose: true})) - .pipe($.jshint.reporter('fail')); -}); - -gulp.task('jade', ['clean-html'], function() { - log('Compiling Jade --> HTML'); - - return gulp - .src(config.jade) - .pipe($.plumber()) - .pipe($.data(function(file) { - return envConfig; - })) - .pipe($.jade({pretty: true})) - .pipe($.replace(/-->/g, ' -->')) - .pipe(gulp.dest(config.temp)); -}); - -gulp.task('styles', ['clean-styles'], function() { - log('Compiling Sass --> CSS'); - - var assetPrefix = envConfig.CONSTANTS.ASSET_PREFIX.length ? envConfig.CONSTANTS.ASSET_PREFIX : '/'; - - return gulp - .src(config.sass, {base: './'}) - .pipe($.plumber()) - .pipe($.sass({includePaths: require('appirio-styles').includePaths})) - .pipe($.autoprefixer({browsers: ['last 2 version']})) - .pipe($.replace(/\/fonts/g, assetPrefix + 'fonts')) - .pipe(gulp.dest(config.temp)); -}); - -gulp.task('sass-watcher', function() { - gulp.watch([config.sass], ['styles']); -}); +var config = require('./gulp.config')(); +var taskPath = './gulp-tasks/'; +var taskList = require('fs').readdirSync(taskPath); -gulp.task('fonts', ['clean-fonts'], function() { - log('Copying fonts'); +var utilities = require(taskPath + 'utilities'); - return gulp - .src([config.fonts, 'bower_components/fontawesome/fonts/fontawesome-webfont.*']) - .pipe(gulp.dest(config.build + 'fonts')); -}); - -gulp.task('dev-fonts', ['fonts'], function() { - log('Copying devicon fonts'); - - return gulp - .src('bower_components/devicon/fonts/**.*') - .pipe(gulp.dest(config.build + 'styles/fonts')); -}) - -gulp.task('images', ['clean-images'], function() { - log('Copying and compressing the images'); - - return gulp - .src(config.images) - .pipe($.imagemin({optimizationLevel: 4})) - .pipe(gulp.dest(config.temp + 'images')); -}); - - -gulp.task('images-orig-nav', ['build1'], function() { - log('Copying original images'); - return gulp - .src(config.assets + 'images/nav/**.*') - .pipe(gulp.dest(config.build + 'images/nav')); -}); - -gulp.task('images-orig', ['images-orig-nav'], function() { - log('Copying original images'); - return gulp - .src(config.assets + 'images/skills/**.*') - .pipe(gulp.dest(config.build + 'images/skills')); -}); - -gulp.task('clean', function(done) { - var delconfig = [].concat(config.build, config.temp); - log('Cleaning: ' + $.util.colors.blue(delconfig)); - del(delconfig, done); -}); -gulp.task('clean-fonts', function(done) { - clean(config.build + 'fonts/**/*.*', done); -}); -gulp.task('clean-images', function(done) { - clean(config.build + 'images/**/*.*', done); -}); -gulp.task('clean-styles', function(done) { - clean(config.temp + '**/*.css', done); -}); -gulp.task('clean-html', function(done) { - clean(config.temp + '**/*.html', done); -}); -gulp.task('clean-code', function(done) { - var files = [].concat( - config.temp + '**/*.js', - config.build + '**/*.html', - config.build + 'js/**/*.js', - config.build + 'styles/**/*.css' - ); - clean(files, done); -}); - -gulp.task('copy-html', function() { - log('Moving app html files to .tmp'); - - return gulp - .src([config.app + '**/*.html', '!' + config.app + 'specs.html']) - .pipe(gulp.dest(config.temp)); -}); - -gulp.task('templatecache', ['clean-code', 'jade', 'copy-html'], function() { - log('Creating AngularJS $templateCache'); - - return gulp - .src(config.htmltemplates) - .pipe($.minifyHtml({empty: true})) - .pipe($.angularTemplatecache( - config.templateCache.file, - config.templateCache.options - )) - .pipe(gulp.dest(config.temp)); -}); - -gulp.task('ngConstants', function() { - return $.ngConstant({ - name: 'CONSTANTS', - dest: 'topcoder.constants.js', - constants: envConfig, - stream: true - }) - .pipe(gulp.dest(config.app)); -}); - -gulp.task('wiredep', ['jade'], function() { - log('Injecting bower css/js and app js files into index.jade'); - var options = config.getWiredepDefaultOptions(); - var wiredep = require('wiredep').stream; - - return gulp - .src(config.index) - .pipe(wiredep(options)) - .pipe($.inject( - gulp.src(config.js) - .pipe($.naturalSort('desc')) - .pipe($.angularFilesort()), - {relative: true})) - .pipe($.inject(gulp.src(config.nonBowerScripts, {read: false}), { - starttag: '//- inject:nonBowerScripts', - endtag: '//- endinject', - ignorePath: 'assets/' - })) - .pipe(gulp.dest(config.app)); -}); - -gulp.task('inject', ['wiredep', 'styles', 'templatecache'], function() { - log('Injecting app css into index.jade'); - - return gulp - .src(config.index) - .pipe($.inject( // Sort the css (reset.css, then topcoder.css, then everything else) - gulp.src([config.temp + 'assets/css/reset.css', config.css], {read: false}) - .pipe($.naturalSort('desc')), - {ignorePath: '.tmp', addRootSlash: false})) - .pipe(gulp.dest(config.app)); -}); - -gulp.task('optimize', ['inject', 'test', 'ngConstants', 'images'], function() { - log('Optimizing the JavaScript, CSS, and HTML'); - - var assets = $.useref.assets({searchPath: ['.tmp', 'app', 'assets']}); - var templateCache = config.temp + config.templateCache.file; - var cssFilter = $.filter('**/*.css'); - var jsLibFilter = $.filter('**/' + config.optimized.vendor); - var jsAppFilter = $.filter('**/' + config.optimized.app); - - var imageStream = gulp.src(config.temp + '/**/*.{svg,png,jpg,jpeg,gif}'); - var userefStream = gulp - .src(config.indexHtml) - .pipe($.plumber()) - .pipe($.inject(gulp.src(templateCache, {read: false}), { - starttag: '', - endtag: '', - relative: true - })) - .pipe(assets) - .pipe(cssFilter) - .pipe($.csso()) - .pipe(cssFilter.restore()) - .pipe(jsLibFilter) - .pipe($.uglify()) - .pipe(jsLibFilter.restore()) - .pipe(jsAppFilter) - .pipe($.if(!config.production && !config.qa, $.sourcemaps.init())) - .pipe($.ngAnnotate()) - .pipe($.uglify()) - .pipe(jsAppFilter.restore()) - .pipe(assets.restore()) - .pipe($.useref()) - - var revAll = new RevAll({ - prefix: envConfig.CONSTANTS.ASSET_PREFIX, - dontRenameFile: [/^\/index.html/g] - }); - - return merge(userefStream, imageStream) - .pipe(revAll.revision()) - .pipe($.if(!config.production && !config.qa, $.sourcemaps.write())) - // Uncomment if you want to see the JSON file containing - // the file mapping (e.g., "{"js/app.js": "js/app-a9bae026bc.js"}") - // .pipe(gulp.dest(config.build)) - // .pipe(revAll.manifestFile()) - .pipe(gulp.dest(config.build)); -}); - -gulp.task('build1', ['optimize', 'dev-fonts'], function() { - log('Building everything'); - - var msg = { - title: 'gulp build', - subtitle: 'Deployed to the build folder', - message: 'Running `gulp serve-build`' - }; - del(config.temp); - log(msg); -}); - -gulp.task('build', ['images-orig']); - -gulp.task('build-specs', ['templatecache', 'ngConstants'], function() { - log('Building the spec runner'); - - var wiredep = require('wiredep').stream; - var options = config.getWiredepDefaultOptions(); - options.devDependencies = true; - - return gulp - .src(config.specRunner) - .pipe(wiredep(options)) - .pipe($.inject(gulp.src(config.testlibraries), - {name: 'inject:testlibraries', read: false})) - .pipe($.inject(gulp.src(config.nonBowerScripts), - {name: 'inject:nonBowerScripts', read: false})) - .pipe($.inject( - gulp.src(config.js) - .pipe($.naturalSort()) - .pipe($.angularFilesort()) - )) - .pipe($.inject(gulp.src(config.specHelpers), - {name: 'inject:spechelpers', read: false})) - .pipe($.inject(gulp.src(config.specs), - {name: 'inject:specs', read: false})) - .pipe($.inject(gulp.src(config.temp + config.templateCache.file), - {name: 'inject:templates', read: false})) - .pipe(gulp.dest(config.app)); -}); - -gulp.task('serve', ['inject', 'ngConstants'], function() { - - gulp.watch(config.sass, ['styles']) - .on('change', function(event) { changeEvent(event); }); - - gulp.watch(config.jade, ['jade']) - .on('change', function(event) { changeEvent(event); }); - - var options = { - server: { - baseDir: [config.temp, config.app, config.assets], - // Enables serving index.html for Angular HTML5 mode - middleware: [histFallback()], - routes: { - '/bower_components': 'bower_components' - } - }, - files: config.watchFiles, - ghostMode: { - clicks: true, - location: false, - forms: true, - scroll: true - }, - logPrefix: 'Topcoder-Account', - notify: false, - port: 3000, - reloadDelay: 1000 - }; - - browserSync(options); - -}); - -gulp.task('serve-specs', ['build-specs'], function() { - log('Run the spec runner'); - - gulp.watch(config.sass, ['styles']) - .on('change', function(event) { changeEvent(event); }); - - gulp.watch(config.jade, ['jade']) - .on('change', function(event) { changeEvent(event); }); - - var options = { - server: { - baseDir: ['./'], - // Enables serving index.html for Angular HTML5 mode - middleware: [histFallback()], - routes: { - '/bower_components': 'bower_components' - } - }, - files: config.watchFiles, - ghostMode: { - clicks: true, - location: false, - forms: true, - scroll: true - }, - logPrefix: 'Topcoder-Account', - notify: false, - reloadDelay: 1000, - startPath: config.app + config.specRunnerFile - }; - - browserSync(options); -}); - -gulp.task('serve-build', ['build'], function() { - // TODO: Figure out why watch doesn't work. Jade running before wiredep? - - gulp.watch([config.sass, config.js, config.jade], ['optimize', browserSync.reload]) - .on('change', function(event) { changeEvent(event); }); - - var options = { - server: { - baseDir: config.build, - // Enables serving index.html for Angular HTML5 mode - middleware: [histFallback()] - }, - files: [], - ghostMode: { - clicks: true, - location: false, - forms: true, - scroll: true - }, - logPrefix: 'Topcoder-Account', - notify: false, - reloadDelay: 1000 - }; - - browserSync(options); - -}); - -gulp.task('e2e', [], function(done) { - gulp.src(['./tests/e2e/app/*.js']) - .pipe($.angularProtractor({ - 'configFile': 'tests/e2e/conf.js', - 'args': ['--baseUrl', 'http://127.0.0.1:8000'], - 'autoStartStopServer': true, - 'debug': true - })) - .on('error', function(e) { throw e }); -}); - -// gulp.task('test', ['vet', 'templatecache'], function(done) { -gulp.task('test', ['templatecache', 'ngConstants'], function(done) { - startTests(true /* singleRun */, done); -}); - -gulp.task('autotest', ['vet', 'templatecache'], function(done) { - startTests(false /* singleRun */, done); -}); - -gulp.task('deploy', ['build'], function() { - var awsConfig = { - params: { - Bucket: config.aws.bucket - }, - "accessKeyId": config.aws.key, - "secretAccessKey": config.aws.secret - }; - - // create a new publisher - var publisher = $.awspublish.create(awsConfig); - - log('Deploying to S3'); - - var gzip = gulp.src(['build/**/*.js', 'build/**/*.css']).pipe($.awspublish.gzip()) - .pipe(awspublishRouter({ - cache: { - cacheTime: 94608000, - allowTransform: false, - public: true - }, - routes: { - "^.+$": "$&" - } - })); - - var plain = gulp.src(['build/**/*', '!build/**/*.js', '!build/**/*.css']) - .pipe(awspublishRouter({ - cache: { - cacheTime: 94608000, - allowTransform: false, - public: true - }, - routes: { - "^.+\\.html": { - cacheTime: 0 - }, - "^.+$": "$&" - } - })); - - return merge(gzip, plain) - .pipe(publisher.cache()) - .pipe(publisher.publish()) - .pipe($.if(!config.production, publisher.sync())) - .pipe($.awspublish.reporter()); -}); - -///////////////////////////////////// - -function changeEvent(event) { - var srcPattern = new RegExp('/.*(?=/' + config.source + ')/'); - log('File ' + event.path.replace(srcPattern, '') + ' ' + event.type); -} - -function clean(path, done) { - log('Cleaning: ' + $.util.colors.blue(path)); - del(path, done); -} - -function log(msg) { - if (typeof(msg) === 'object') { - for (var item in msg) { - if (msg.hasOwnProperty(item)) { - $.util.log($.util.colors.blue(msg[item])); - } - } - } else { - $.util.log($.util.colors.blue(msg)); +taskList.forEach(function(taskFile) { + if (taskFile !== 'utilities.js') { + require(taskPath + taskFile)(gulp, plugins, config, utilities); } -} - -function startTests(singleRun, done) { - var karma = require('karma').server; - var excludeFiles = []; - var serverSpecs = config.serverIntegrationSpecs; - - excludeFiles = serverSpecs; - - karma.start({ - configFile: __dirname + '/karma.conf.js', - exclude: excludeFiles, - singleRun: !!singleRun - }, karmaCompleted); +}); - function karmaCompleted(karmaResult) { - log('Karma completed!'); - if (karmaResult === 1) { - done('karma: tests failed with code ' + karmaResult); - } else { - done(); - } - } -} +gulp.task('help', plugins.taskListing); +gulp.task('default', ['help']); diff --git a/package.json b/package.json index 8e5bd18e7..b363a8595 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "gulp-ng-constant": "^0.3.0", "gulp-plumber": "^1.0.1", "gulp-print": "^1.1.0", + "gulp-rename": "^1.2.2", "gulp-replace": "^0.5.3", "gulp-replace-task": "^0.11.0", "gulp-rev": "^5.0.1", @@ -80,7 +81,7 @@ "phantomjs": "^1.9.17", "protractor-html-screenshot-reporter": "0.0.21", "protractor-linkuisref-locator": "^1.1.2", - "sc5-styleguide": "^0.3.39", + "run-sequence": "^1.1.5", "sinon": "^1.15.3", "sinon-chai": "^2.8.0", "wiredep": "^2.2.2",