UNPKG

edm-supergulp

Version:

common build process handling for EMDdesigner repos

636 lines (549 loc) 17.3 kB
var jsonlint = require("gulp-jsonlint"); var jshint = require("gulp-jshint"); var jscs = require("gulp-jscs"); var stylish = require("gulp-jscs-stylish"); var jasmine = require("gulp-jasmine"); var reporters = require("jasmine-reporters"); var specReporter = require("jasmine-spec-reporter").SpecReporter; var istanbul = require("gulp-istanbul"); var rename = require("gulp-rename"); var babelMinify = require("gulp-babel-minify"); var buffer = require("vinyl-buffer"); var checkParams = require("superschema").check; var fsCache = require("gulp-fs-cache"); var nconf = require("nconf").argv().env(); var gulpS3 = require("gulp-s3"); var clean = require("gulp-clean"); var ejs = require("gulp-ejs"); var mergeStream = require("merge-stream"); var AWS = require("aws-sdk"); var fs = require("fs"); var mime = require("mime-types"); var sass = require("gulp-sass"); var autoprefixer = require("gulp-autoprefixer"); var cssnano = require("gulp-cssnano"); var concat = require("gulp-concat"); var gulpif = require("gulp-if"); var file = require("gulp-file"); var browserify = require("browserify"); var shim = require("browserify-global-shim"); var partialify = require("partialify"); var source = require("vinyl-source-stream"); var babelify = require('babelify'); var actEnv, files; module.exports = function createSuperGulp(dependencies) { checkParams(dependencies, { gulp: "object" }); var gulp = dependencies.gulp; // TEST // =========================================================================== function gulpJsonLint(config) { var files = config.files; gulp.task("test:jsonlint", function() { return gulp.src(files) .pipe(jsonlint()) .pipe(jsonlint.failOnError()); }); } function gulpJsHint(config) { var files = config.files; gulp.task("test:jshint", function() { return gulp.src(files) .pipe(jshint(".jshintrc")) .pipe(jshint.reporter("jshint-stylish")) .pipe(jshint.reporter("fail")); }); } function gulpJscs(config) { var files = config.files; gulp.task("test:jscs", function() { return gulp.src(files) .pipe(jscs({ configPath: ".jscsrc", fix: true })) .pipe(stylish()) .pipe(jscs.reporter("fail")); }); } function gulpJasmine(config) { var files = config.files; gulp.task("test:jasmine", function() { return gulp.src(files) .pipe(jasmine({ verbose: config.verbose, reporter: [new specReporter({spec:{displaySuccessful: config.verbose}, isVerbose: false, showColors: true}), new reporters.JUnitXmlReporter()], abortOnTestFailure: true, config: config.jasmineConfig })); }); } function gulpJasmineIntegration(config) { var files = config.files; gulp.task("test:jasmine:route", function() { return gulp.src(files) .pipe(jasmine({ verbose: config.verbose, reporter: [new specReporter({spec:{displaySuccessful: config.verbose}, isVerbose: false, showColors: true}), new reporters.JUnitXmlReporter()], abortOnTestFailure: true, config: config.jasmineConfig })); }); } function gulpPreTest(config) { var files = config.files; gulp.task("test:pre-test", function () { return gulp.src(files) // Covering files .pipe(istanbul()) // Force `require` to return covered files .pipe(istanbul.hookRequire()); }); } function gulpIstanbul(config) { var files = config.files; console.log("CURRENT MINIMAL COVERAGE: " + config.coverage + "%"); gulp.task("test:istanbul", ["test:pre-test"], function () { return gulp.src(files) .pipe(jasmine({ verbose: config.verbose, reporter: [new specReporter({spec:{displaySuccessful: config.verbose}, isVerbose: false, showColors: true}), new reporters.JUnitXmlReporter()], abortOnTestFailure: true, config: config.jasmineConfig })) // Creating the reports after tests ran .pipe(istanbul.writeReports({reporters: [ "cobertura", "text", "lcov" ]})) // Enforce a coverage of at least 90% .pipe(istanbul.enforceThresholds({ thresholds: { global: config.coverage || 90 } })); }); } function gulpTest() { gulp.task("test", ["test:jshint", "test:jsonlint", "test:jscs", "test:istanbul"]); } // PLUGIN TASKS // =========================================================================== function initCommonTasks(config) { checkParams(config, { files: { js: "array string", json: "array string", spec: "array string", source: "array string", }, jasmineConfigObject: "optional object" }); var jasmineConfig = config.jasmineConfigObject || {}; gulpJsonLint({ files: config.files.json }); gulpJsHint({ files: config.files.js }); gulpJscs({ files: config.files.js }); gulpPreTest({ files: config.files.source }); gulpIstanbul({ files: config.files.spec , coverage: config.coverage, verbose: config.verbose, jasmineConfig: jasmineConfig }); gulpJasmine({ files: config.files.spec, verbose: config.verbose, jasmineConfig: jasmineConfig }); config.files.integration && gulpJasmineIntegration({ files: config.files.integration, verbose: config.verbose, jasmineConfig: jasmineConfig }); gulpTest(); } function gulpTaskOnlyForPlugins(config) { checkParams(config, { files: { built: "optional array string", } }); config.shimConfig = config.shimConfig || { "knockout": "ko", "knob-js": "knob" }; config.resources = config.resourceConfigs && { dev: config.resourceConfigs.dev && require(config.resourceConfigs.dev), staging: config.resourceConfigs.staging && require(config.resourceConfigs.staging), prod: config.resourceConfigs.prod && require(config.resourceConfigs.prod) }; if(config.resources) { if (config.resources.dev) { config.resources.dev.statics.packageJson = config.packageJson; } if (config.resources.staging) { config.resources.staging.statics.packageJson = config.packageJson; } if (config.resources.prod) { config.resources.prod.statics.packageJson = config.packageJson; } } // CLEAN gulp.task("clean", function() { return gulp.src(config.dest || "./dist", { read: false }) .pipe(clean()); }); // COPY DEPS gulp.task("copy", ["clean"], function() { var tasks = files.copy; var stream = mergeStream(); for (var i = 0; i < tasks.length; i += 1) { stream.add(gulp.src(tasks[i].files) .on("error", function(err){ console.log(err); }) .pipe(gulp.dest(tasks[i].dest))); } return stream.isEmpty() ? null : stream; }); var preTasks = ["build:config"]; if (!nconf.get("skiptests")) { preTasks.push("test"); } // EJS gulp.task("build:ejs", preTasks, function() { var stream = mergeStream(); var tasks = files.ejs; for (var i = 0; i < tasks.length; i += 1) { stream.add(gulp.src(tasks[i].files) .on("error", function(err){ console.log(err); }) .pipe(ejs(config.resources[actEnv].statics)) .pipe(gulp.dest(tasks[i].dest))); } return stream.isEmpty() ? null : stream; }); //SASS gulp.task("build:sass", ["clean"], function() { var stream = mergeStream(); var tasks = files.sass; for (var i = 0; i < tasks.length; i += 1) { var task = tasks[i]; var hasToMinify = task.hasOwnProperty("minify") ? task.minify : actEnv !== "dev"; stream.add(gulp.src(task.files) .on("error", function(err){ console.log(err); }) .pipe(sass().on("error", sass.logError)) .pipe(autoprefixer({ browsers: ["last 2 version", "iOS 6"], cascade: false })) .pipe(concat(task.outputFileName || config.packageJson.name + ".css")) .pipe(gulp.dest(task.dest)) .pipe(gulpif(hasToMinify, cssnano())) .pipe(gulpif(hasToMinify, rename({ extname: ".min.css" }))) .pipe(gulpif(hasToMinify, gulp.dest(task.dest)))); } return stream.isEmpty() ? null : stream; }); // JS gulp.task("build:js", preTasks, function() { var stream = mergeStream(); var tasks = files.js; for (var i = 0; i < tasks.length; i += 1) { var task = tasks[i]; var hasToMinify = task.hasOwnProperty("minify") ? task.minify : actEnv !== "dev"; stream.add(createBrowserifyTask({ debug: task.debug || actEnv !== "prod", entries: task.entries, minify: hasToMinify, standaloneName: task.standaloneName || config.packageJson.name, outputFileName: task.outputFileName, shimConfig: config.shimConfig, destFolder: task.destFolder || "./dist" })); } return stream.isEmpty() ? null : stream; }); // CONFIG gulp.task("build:config", ["clean"], function() { if(!config.hasOwnProperty("resourceConfigs")){ return null; } var stream = mergeStream(); stream.add(file("edmRouteConfig.json", JSON.stringify(config.resources[actEnv].routes, null, "\t"), { src: true }) .pipe(gulp.dest(config.destFolder || "./dist"))); return stream; }); var buildTaskArray = ["clean", "copy", "build:ejs", "build:sass", "build:js"]; if (config.customBuildTasks && Array.isArray(config.customBuildTasks)) { for (var i = 0; i < config.customBuildTasks.length; i += 1) { if (buildTaskArray.indexOf(config.customBuildTasks[i]) === -1) { buildTaskArray.push(config.customBuildTasks[i]); } } } if (!nconf.get("skiptests")) { buildTaskArray.splice(1, 0, "test"); console.log(buildTaskArray); } // BUILD TASKS gulp.task("buildTask", buildTaskArray); gulp.task("build:dev", function() { actEnv = "dev"; files = prepareTasks(config, actEnv); gulp.run("buildTask"); }); gulp.task("build:staging", function() { actEnv = "staging"; files = prepareTasks(config, actEnv); gulp.run("buildTask"); }); gulp.task("build:prod", function() { actEnv = "prod"; files = prepareTasks(config, actEnv); gulp.run("buildTask"); }); // DEPLOY TASKS gulp.task("deployTask", buildTaskArray, function () { deploy({ s3key: nconf.get("s3key"), s3secret: nconf.get("s3secret"), s3region: nconf.get("s3region"), s3bucket: nconf.get("s3bucket"), deployFolder: config.deployFolder, files: config.files.deploy, overridePublishedVersion: config.overridePublishedVersion || false }); }); gulp.task("deployLatestTask", buildTaskArray, function () { deploy({ s3key: nconf.get("s3key"), s3secret: nconf.get("s3secret"), s3region: nconf.get("s3region"), s3bucket: nconf.get("s3bucket"), deployFolder: config.deployLatestFolder, files: config.files.deploy, overridePublishedVersion: true }); }); gulp.task("deploySPATask", buildTaskArray, function () { deploy({ s3key: nconf.get("s3key"), s3secret: nconf.get("s3secret"), s3region: nconf.get("s3region"), s3bucket: nconf.get("s3bucket"), deployFolder: config.deploySpaFolder, files: config.files.deploySpaIndex, overridePublishedVersion: true }); deploy({ s3key: nconf.get("s3key"), s3secret: nconf.get("s3secret"), s3region: nconf.get("s3region"), s3bucket: nconf.get("s3bucket"), deployFolder: config.deployFolder, files: config.files.deploy, overridePublishedVersion: false }); }); gulp.task("deployExampleTask", buildTaskArray, function () { deploy({ s3key: nconf.get("s3key"), s3secret: nconf.get("s3secret"), s3region: nconf.get("s3region"), s3bucket: nconf.get("s3bucket"), deployFolder: config.deployExampleFolder, files: config.files.deployExample, overridePublishedVersion: true }); }); gulp.task("deploy:staging", function() { actEnv = "staging"; files = prepareTasks(config, actEnv); gulp.run("deployTask"); }); gulp.task("deploy:prod", function() { actEnv = "prod"; files = prepareTasks(config, actEnv); gulp.run("deployTask"); }); gulp.task("deployLatest:staging", function() { actEnv = "staging"; files = prepareTasks(config, actEnv); gulp.run("deployLatestTask"); }); gulp.task("deploySPA:staging", function() { actEnv = "staging"; files = prepareTasks(config, actEnv); gulp.run("deploySPATask"); }); gulp.task("deploySPA:prod", function() { actEnv = "prod"; files = prepareTasks(config, actEnv); gulp.run("deploySPATask"); }); gulp.task("deployLatest:prod", function() { actEnv = "prod"; files = prepareTasks(config, actEnv); gulp.run("deployLatestTask"); }); gulp.task("deployExample:staging", function() { actEnv = "staging"; files = prepareTasks(config, actEnv); gulp.run("deployExampleTask"); }); gulp.task("deployExample:prod", function() { actEnv = "prod"; files = prepareTasks(config, actEnv); gulp.run("deployExampleTask"); }); } // HELPERS // =========================================================================== function prepareTasks(config, env) { var files = { copy: [], ejs: [], sass: [], js: [] }; if (config.addPluginTasks) { // Basic Tasks files.ejs.push({ files: "./src/index.html", dest: "./dist"}); files.sass.push({ files: "./src/main.scss", dest: "./dist"}); files.js.push({ minify: (env === "dev") ? false : true, entries: ["./src/main.js"], outputFileName: "main.js", standaloneName: config.packageJson.name, destFolder: "./dist/" }); // Basic Tasks - Examples files.copy.push({ files: "./examples/example.css", dest: "./dist/examples"}); files.ejs.push({ files: "./examples/index.html", dest: "./dist/examples"}); files.js.push({ minify: false, entries: ["./examples/main.js"], outputFileName: "main.js", standaloneName: config.packageJson.name + "Example", destFolder: "./dist/examples/" }); // Dev tasks if (env === "dev") { files.copy.push({ files: config.files.localDeps, dest: "./dist/lib"}); } } for (var task in config.tasks) { if (config.tasks.hasOwnProperty(task)) { var taskFiles = config.tasks[task]; if (taskFiles.constructor === Array) { files[task] = files[task].concat(taskFiles); } // COMMON if (taskFiles.common && taskFiles.common.constructor === Array) { files[task] = files[task].concat(taskFiles.common); } if (taskFiles.common && taskFiles.common.constructor !== Array) { files[task].push(taskFiles.common); } //TASKS if (taskFiles[env] && taskFiles[env].constructor === Array) { files[task] = files[task].concat(taskFiles[env]); } if (taskFiles[env] && taskFiles[env].constructor !== Array) { files[task].push(taskFiles[env]); } } } return files; } // DEPLOY function deploy(config) { if (!config.s3key || !config.s3secret || !config.s3region || !config.s3bucket) { throw new Error("s3key, s3secret, s3region and s3bucket is mandatory! Use command like this: gulp deploy:staging --s3key 'S3 KEY' --s3secret 'S3 SECRET' --s3region 'S3 region' --s3bucket 'S3 bucket'!"); } var s3 = new AWS.S3({ accessKeyId: config.s3key, secretAccessKey: config.s3secret, region: config.s3region, params: { Bucket: config.s3bucket } }); var files = config.files; config.deployFolder[config.deployFolder.length-1] === "/" ? null : config.deployFolder += "/"; function deployFiles() { gulp.src(config.files) .on("error", function(err){ console.log(err); }) .pipe(gulpS3({ key: config.s3key, secret: config.s3secret, region: config.s3region, bucket: config.s3bucket }, { uploadPath: config.deployFolder, failOnError: true })); } if (config.overridePublishedVersion) { deployFiles(); return; } s3.listObjects({ Bucket: config.s3bucket, Prefix: config.deployFolder, MaxKeys: 1 }, function (err, list) { if (list.Contents.length > 0) { throw new Error("deploy error: Version is already published! Change version before deployment! Checked folder: '" + config.deployFolder + "'."); } if (err) { throw new Error("deploy error: Returned error when testing: '" + err.code + "'"); } deployFiles(); }); } function createBrowserifyTask(config) { var jsFsCache = fsCache("tmp/jscache"); shim = shim.configure(config.shimConfig); var b = browserify({ debug: config.debug, entries: config.entries, standalone: config.standaloneName, transform: [partialify, shim], fullPaths: true }).transform("babelify", {presets: ["es2015"]}); return b.bundle() // Use vinyl-source-stream to make stream gulp compatible. Specifiy the desired output filename here. .on("error", function(err){ console.log(err); }) .pipe(source(config.outputFileName)) // Specify the output destination .pipe(buffer()) .pipe(gulp.dest(config.destFolder)) .pipe(gulpif(config.minify, jsFsCache)) .pipe(gulpif(config.minify, babelMinify({ mangle: { keepClassName: true } }) .on("error", function(e) { console.log(e); }) )) .pipe(gulpif(config.minify, jsFsCache.restore)) .pipe(gulpif(config.minify, rename({ extname: ".min.js" }))) .pipe(gulpif(config.minify, gulp.dest(config.destFolder))); } return { taskTemplates: { initBackendTasks: function(config) { initCommonTasks(config); }, initFrontendTasks: function(config) { initCommonTasks(config); gulpTaskOnlyForPlugins(config); } } }; };