Last active
March 22, 2016 17:23
-
-
Save adamrneary/a003e351b7fdf832b3ad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _ = require('lodash'); | |
const argv = require('minimist')(process.argv.slice(2)); | |
const awspublish = require('gulp-awspublish'); | |
const dotenv = require('dotenv'); | |
const del = require('del'); | |
const GitHubApi = require('github'); | |
const git = require('git-rev') | |
const gulp = require('gulp'); | |
const gutil = require('gulp-util'); | |
const path = require('path'); | |
const release = require('gulp-github-release'); | |
const rename = require('gulp-rename'); | |
const replace = require('gulp-replace'); | |
const rev = require('gulp-rev'); | |
const runSequence = require('run-sequence').use(gulp); | |
const Slack = require('slack-notify'); | |
const usemin = require('gulp-usemin'); | |
const webpack = require('webpack'); | |
const webpackConf = require('webpack-config'); | |
// These deploy environments correspond to suffixes in ./src/config/ | |
const DEPLOY_ENVS = ['smash', 'staging', 'preprod', 'demo', 'production', 'sera']; | |
// Load appropriate environment variables. | |
if (DEPLOY_ENVS.indexOf(argv.env) === -1) { | |
gutil.log('[env]', 'No/invalid deploy env specified.'); | |
gutil.log('[env]', 'Valid deploy environments are ' + DEPLOY_ENVS.join(', ')); | |
gutil.log('[env]', 'Syntax example: gulp deploy --env=production'); | |
throw new Error('No/invalid deploy env specified. Exiting.'); | |
} else { | |
gutil.log('[env]', 'Loading ' + argv.env + ' config.'); | |
// We need to hard-set this because remote envs like test will have the | |
// NODE_ENV already set. | |
process.env.NODE_ENV = argv.env; | |
dotenv.config({path: '../config/.env.' + argv.env}); | |
dotenv.config({path: './config/.env.' + argv.env}); | |
} | |
const BUILD_DIR = path.resolve('../../build/Admin'); | |
const DIST_DIR = path.resolve('../../dist/Admin'); | |
const github = new GitHubApi({ | |
// required | |
version: '3.0.0', | |
protocol: 'https', | |
host: 'api.github.com', | |
timeout: 5000, | |
headers: { | |
'user-agent': 'Parsable Deploy Agent' | |
} | |
}); | |
github.authenticate({ | |
type: 'oauth', | |
token: process.env.GITHUB_TOKEN | |
}); | |
gulp.task('set-build-number', function(cb) { | |
github.releases.listReleases({ | |
owner: 'parsable', | |
repo: 'gutenberg', | |
/*eslint-disable */ | |
per_page: 1 | |
/*eslint-enable */ | |
}, function(err, result) { | |
if (err) {throw new Error(err); } | |
const existingBuildNo = parseInt(result[0].tag_name.replace('build-', '')); | |
if (_.isNaN(existingBuildNo)) { | |
throw new Error('Existing release is not numbered as expected.'); | |
} | |
process.env.BUILD_NUMBER = Math.round(existingBuildNo) + 1; | |
cb(); | |
}); | |
}); | |
gulp.task('clean', function(cb) { | |
del([BUILD_DIR, DIST_DIR], cb); | |
}); | |
gulp.task('pack', function(cb) { | |
const conf = new webpackConf().extend('./webpack.config.js'); | |
const serverConf = conf.devServer; | |
const webpackCompiler = webpack(conf); | |
webpackCompiler.run(function(err, stats) { | |
if (err) { throw err; } | |
gutil.log('[webpack]', stats.toString(serverConf.stats)); | |
cb(); | |
}); | |
}); | |
// This replace pipeline saves us from having to process html in dev mode. | |
// Well worth the trickery, though more elegant alternatives are welcome! | |
// Ultimately, webpack can handle adding hashes to assets, and it can manage | |
// this part of the pipeline. But for now, this works fine. | |
gulp.task('pre-process-html', function() { | |
const inPlaceComment = '<!-- @built-css -->'; | |
const cssBlocks = | |
'<!-- build:css /css/app.css -->\n' + | |
' <link rel="stylesheet" href="app.css">\n' + | |
'<!-- endbuild -->\n'; | |
const vendorJsBlock = | |
'<!-- build:js1 /js/vendor.js -->\n' + | |
' <script src="vendor.js"></script>\n' + | |
'<!-- endbuild -->\n'; | |
const appJsBlock = | |
'<!-- build:js2 /js/app.js -->\n' + | |
' <script src="app.js"></script>\n' + | |
'<!-- endbuild -->\n'; | |
var buildTag = '<script>window.wiBuildNumber=' + (process.env.BUILD_NUMBER || 0) + ';</script>'; | |
var inPlaceBuildTag = '<!-- @build-tag -->'; | |
// Omitting some code from this gist… | |
return gulp.src('./index.html') | |
// .pipe(replace(inPlaceCSP, cspBlock)) | |
.pipe(replace(inPlaceBuildTag, buildTag)) | |
.pipe(replace(inPlaceComment, cssBlocks)) | |
.pipe(replace(inPlaceNewRelic, newRelicBlock)) | |
.pipe(replace(inPlaceSegment, segmentBlock)) | |
.pipe(replace(inPlaceLoggly, logglyBlock)) | |
.pipe(replace('<script src="/vendor.js"></script>', vendorJsBlock)) | |
.pipe(replace('<script src="/app.js"></script>', appJsBlock)) | |
.pipe(gulp.dest(BUILD_DIR)); | |
}); | |
gulp.task('process-html', function() { | |
return gulp.src(BUILD_DIR + '/index.html') | |
.pipe(usemin({ | |
css: [rev()], | |
js1: [uglify(), rev()], | |
js2: [uglify(), rev()], | |
html: [minifyHtml({empty: true})], | |
})) | |
.pipe(gulp.dest(DIST_DIR)) | |
.pipe(rename('index' + process.env.BUILD_NUMBER + '.html')) | |
.pipe(gulp.dest(DIST_DIR)); | |
}); | |
gulp.task('copy-images', function() { | |
return gulp.src(BUILD_DIR + '/**/!(*.html|*.js|*.css)') | |
.pipe(gulp.dest(DIST_DIR)); | |
}); | |
gulp.task('tag', function(){ | |
git.long(function (gitRev) { | |
console.log('Using git revision: ', gitRev, ' for release tag.'); | |
gulp.src(DIST_DIR + '/index.html') | |
.pipe(release({ | |
repo: 'gutenberg', | |
owner: 'parsable', | |
/*eslint-disable */ | |
target_commitish: gitRev, | |
/*eslint-enable */ | |
tag: 'build-' + process.env.BUILD_NUMBER, | |
name: 'Build ' + process.env.BUILD_NUMBER + ' released to ' + process.env.DEPLOY_ENV, | |
notes: 'Tagged via gulp deploy', | |
draft: false, | |
prerelease: false, | |
manifest: require('../../package.json') | |
})); | |
}) | |
}); | |
var publisher; | |
publisher = awspublish.create({ | |
params: {Bucket: process.env.AWS_S3_BUCKET}, | |
accessKeyId: process.env[`aws_deploy_${argv.env}_id`], | |
secretAccessKey: process.env[`aws_deploy_${argv.env}_key`], | |
region: process.env.AWS_S3_REGION | |
}); | |
gulp.task('upload:bare', function() { | |
gulp.src(DIST_DIR + '/**/*.html') | |
.pipe(awspublish.gzip()) | |
.pipe(publisher.publish({'Cache-Control': 'max-age=1'})) | |
.pipe(awspublish.reporter()); | |
}); | |
gulp.task('upload:revved', function() { | |
gulp.src([DIST_DIR + '/**/*', '!' + DIST_DIR + '/**/*.html']) | |
.pipe(awspublish.gzip()) | |
.pipe(publisher.publish({'Cache-Control': 'max-age=315360000'})) | |
.pipe(awspublish.reporter()); | |
}); | |
gulp.task('brag', function() { | |
if ( | |
process.env.SLACK_TOKEN | |
) { | |
const slack = Slack('https://hooks.slack.com/services/T0255PDBV/B07KSHJ3F/' + | |
process.env.SLACK_TOKEN | |
); | |
const message = 'Web Admin build ' + process.env.BUILD_NUMBER + ' deployed to ' + process.env.DEPLOY_ENV; | |
slack.success({ | |
username: 'Parsable Continuous Integration (via Gulp and Circle)', | |
channel: '#deploys', | |
/*eslint-disable */ | |
icon_emoji: ':doitright:', | |
/*eslint-enable */ | |
text: message | |
}, function(err, result) { | |
if (err) {throw new Error(err); } | |
console.log(result); | |
}); | |
} else { | |
throw new Error('Cannot brag. Slack token unavailable.'); | |
} | |
}); | |
// TODO: It sounds like runSequence is deprecated and we should migrate to | |
// orchestrator. Whatever. Build tools gonna build tools. | |
gulp.task('build', function() { | |
return runSequence( | |
['clean'], | |
['pack'], | |
['pre-process-html'], | |
['process-html', 'copy-images'] | |
); | |
}); | |
// TODO: It sounds like runSequence is deprecated and we should migrate to | |
// orchestrator. Whatever. Build tools gonna build tools. | |
gulp.task('default', function() { | |
return runSequence( | |
['set-build-number'], | |
['clean'], | |
['pack'], | |
['pre-process-html'], | |
['process-html', 'copy-images'], | |
['tag'], | |
['upload:bare', 'upload:revved'], | |
['brag'] | |
); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment