edm-supergulp
Version:
common build process handling for EMDdesigner repos
636 lines (549 loc) • 17.3 kB
JavaScript
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);
}
}
};
};