diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | gulpfile.js | 17 | ||||
-rw-r--r-- | package.json | 46 | ||||
-rw-r--r-- | tasks/cdn.js | 119 | ||||
-rw-r--r-- | tasks/common.js | 87 | ||||
-rw-r--r-- | tasks/config.js | 25 | ||||
-rw-r--r-- | tasks/zip.js | 140 |
7 files changed, 436 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c085d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +target diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..4277a46 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,17 @@ +"use strict"; +var gulp = require('gulp'); +require('require-dir')('./tasks'); + +var version = '0.3.0'; + +gulp.task('default', function() { + console.log('\n Use:\n gulp <stage|deploy[:cdn:zip]>\n'); +}); + +gulp.task('clean', ['clean:cdn', 'clean:zip']); + +gulp.task('deploy', ['deploy:cdn', 'deploy:zip']); + +// can't run all the verification concurrently until sauce-connect-launcher supports +// multiple tunnels +//gulp.task('verify', ['verify:cdn', 'verify:zip]); diff --git a/package.json b/package.json new file mode 100644 index 0000000..b5e0726 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "vaadin-components", + "version": "0.3.0", + "description": "A set of high-quality Web Components with a customizable Sass based theme", + "author": "Vaadin Ltd", + "license": "Apache License 2.0", + "dependencies": { + "bower": "latest", + "fs-extra": "latest", + "gulp": "latest", + "gulp-git": "latest", + "gulp-json-editor": "latest", + "gulp-markdown": "^1.0.0", + "gulp-rename": "latest", + "gulp-replace": "latest", + "gulp-util": "latest", + "web-component-tester": "3.3.10", + "yargs": "latest", + "gulp-git": "latest" + }, + "devDependencies": { + "chalk": "latest", + "gemini": "^0.12.0", + "gemini-express": "^0.9.2", + "gemini-sauce": "^0.9.1", + "gulp-bower": "0.0.10", + "gulp-download": "0.0.1", + "gulp-insert": "latest", + "gulp-rsync": "0.0.5", + "gulp-unzip": "^0.1.3", + "gulp-zip": "^2.0.3", + "lodash": "^3.5.0", + "node-ssh-exec": "^0.1.1", + "require-dir": "^0.1.0", + "scp2": "^0.2.1", + "wct-teamcity-reporter": "1.0.1" + }, + "keywords": [ + "vaadin", + "components", + "web", + "components", + "webcomponents", + "gwt" + ] +} diff --git a/tasks/cdn.js b/tasks/cdn.js new file mode 100644 index 0000000..e5aaeed --- /dev/null +++ b/tasks/cdn.js @@ -0,0 +1,119 @@ +var bower = require('gulp-bower'); +var config = require('./config'); +var common = require('./common'); +var gulp = require('gulp'); +var fs = require('fs-extra'); +var markdown = require('gulp-markdown'); +var replace = require('gulp-replace'); +var rsync = require('gulp-rsync'); +var gutil = require('gulp-util'); +var _ = require('lodash'); +var args = require('yargs').argv; +var git = require('gulp-git'); + +var stagingBasePath = config.paths.staging.cdn; +var version = args.release || args.preRelease || args.autoRevert ? config.version : config.snapshotVersion; +var stagingPath = stagingBasePath + '/' + version; +var testPath = process.cwd() + '/' + stagingPath + '/test'; + +gulp.task('clean:cdn', function() { + fs.removeSync(stagingBasePath); +}); + +gulp.task('cdn:stage-bower_components', function() { + return bower({ + directory: stagingPath, + forceLatest: true, + cmd: 'install' + }); +}); + +gulp.task('cdn:stage-vaadin-components', ['clean:cdn'], function() { + return gulp.src(['README.md', 'LICENSE.md', 'vaadin-components.html']) + .pipe(markdown()) + .pipe(gulp.dest(stagingPath + "/vaadin-components")); +}); + +gulp.task('stage:cdn', + ['cdn:stage-bower_components', + 'cdn:stage-vaadin-components']); + +gulp.task('deploy:cdn', ['stage:cdn'], function() { + common.checkArguments(['cdnUsername', 'cdnDestination']); + var hostName = args.cdnHostname || 'cdn.vaadin.com'; + + gutil.log('Uploading to cdn (rsync): ' + stagingPath + ' -> '+ args.cdnUsername + '@' + hostName + ':' + args.cdnDestination + version); + + return gulp.src(stagingPath) + .pipe(rsync({ + username: args.cdnUsername, + hostname: hostName, + root: stagingPath, + emptyDirectories: false, + recursive: true, + clean: true, + silent: true, + destination: args.cdnDestination + version + })); +}); + +gulp.task('cdn-test:clean', function() { + fs.removeSync(stagingPath + '/test'); +}); + +gulp.task('cdn-test:install-dependencies', function() { + return bower({ + directory: stagingPath, + cmd: 'install' + }, [['web-component-tester#2.2.6']]); +}); + +config.components.forEach(function (n) { + gulp.task('cdn-test:stage:' + n, ['cdn-test:clean', 'cdn-test:install-dependencies'], function(done) { + fs.mkdirsSync(testPath); + return git.clone('https://github.com/vaadin/' + n, {cwd: testPath}, function (err) { + gulp.src(testPath + '/' + n + '/test/**') + .pipe(replace(/(src|href)=("|')(.*?)\.\.\/\.\.\/(bower_components|node_modules)\/(.*?)\//mg, '$1=$2https://cdn.vaadin.com/vaadin-components/'+ version + '/$5/')) + .pipe(replace(/(src|href)=("|')(.*?)\.\.\//mg, '$1=$2https://cdn.vaadin.com/vaadin-components/'+ version +'/' + n + '/')) + .pipe(replace(/(src|href)=("|')(.*?)(web-component-tester)\//mg, '$1=$2../../web-component-tester/')) + .pipe(gulp.dest(testPath + '/' + n + '/test/')); + done(); + }); + }); +}); + +gulp.task('cdn-test:stage', _.map(config.components, function (n) { + return 'cdn-test:stage:' + n; +})); + +gulp.task('verify:cdn', ['cdn-test:stage'], function(done) { + if(args.autoRevert) { + common.checkArguments(['cdnUsername', 'cdnDestination']); + } + + // use unique browser combination because bower,cdn,zip verifications are run + // at the same time and TeamCity test results will get mixed up if same browsers are used. + common.testSauce( + ['target/cdn/' + version + '/test/**/index.html'], + ['Windows 7/firefox@36'], + 'vaadin-components / cdn.vaadin.com / ' + version, + function(err) { + common.autoRevert(err, function() { + gutil.log('Deleting folder ' + args.cdnDestination + version); + + require('node-ssh-exec')({ + host: 'cdn.vaadin.com', + username: args.cdnUsername, + privateKey: config.paths.privateKey() + }, 'rm -rf ' + args.cdnDestination + version, function (error, response) { + if (error) { + throw error; + } + + gutil.log(response); + + done(err); + }); + + }, done)}); +}); diff --git a/tasks/common.js b/tasks/common.js new file mode 100644 index 0000000..d4ba658 --- /dev/null +++ b/tasks/common.js @@ -0,0 +1,87 @@ +var args = require('yargs').argv; +var chalk = require('chalk'); +var wct = require('web-component-tester').test; +var _ = require('lodash'); +var gutil = require('gulp-util'); + +function cleanDone(done) { + return function(error) { + if (error) { + // Pretty error for gulp. + error = new Error(chalk.red(error.message || error)); + error.showStack = false; + } + done(error); + }; +} + +function checkArguments(arguments) { + _.forEach(arguments, function(a) { + if(!args.hasOwnProperty(a)) { + throw Error('Required argument \'--'+ a +'\' is missing.'); + } + }); +} + +function localAddress() { + var ip, tun, ifaces = require('os').networkInterfaces(); + Object.keys(ifaces).forEach(function (ifname) { + ifaces[ifname].forEach(function (iface) { + if ('IPv4' == iface.family && !iface.internal) { + if (!ip) ip = iface.address; + if (/tun/.test(ifname)) tun = iface.address; + } + }); + }); + return tun || ip; +} + +function test(options, done) { + wct(options, cleanDone(done)); +} + +module.exports = { + localAddress: localAddress, + test: test, + checkArguments: checkArguments, + + testSauce: function(suites, browsers, build, done) { + test( + { + suites: suites, + browserOptions: { + name: localAddress() + ' / ' + new Date(), + build: build + }, + + plugins: { + //local: { + // browsers: ['chrome'] + //}, + sauce: { + username: args.sauceUsername, + accessKey: args.sauceAccessKey, + browsers: browsers + }, + 'teamcity-reporter': args.teamcity + }, + webserver: { + hostname: localAddress() + } + }, done); + }, + + autoRevert: function(err, handler, done) { + if(err) { + gutil.log(err.toString()); + if(args.autoRevert) { + handler(); + } else { + gutil.log('No action. Use --auto-revert to revert changes.') + done(err); + } + } else { + done(); + } + } +}; diff --git a/tasks/config.js b/tasks/config.js new file mode 100644 index 0000000..bfbf19f --- /dev/null +++ b/tasks/config.js @@ -0,0 +1,25 @@ +var args = require('yargs').argv; +var fs = require('fs'); + +var userhome = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE; + +module.exports = { + components: ['vaadin-grid'], + snapshotVersion: '0.3.0-snapshot', + version: args.version || '0.3.0-snapshot', + paths: { + staging: { + bower: 'target/bower', + cdn: 'target/cdn', + zip: 'target/zip' + }, + userhome: userhome, + privateKey: function() { + try { + return fs.readFileSync(userhome + '/.ssh/id_rsa'); + } catch(error) { + return fs.readFileSync(userhome + '/.ssh/id_dsa'); + } + } + } +}; diff --git a/tasks/zip.js b/tasks/zip.js new file mode 100644 index 0000000..fc0f854 --- /dev/null +++ b/tasks/zip.js @@ -0,0 +1,140 @@ +var _ = require('lodash'); +var args = require('yargs').argv; +var bower = require('gulp-bower'); +var common = require('./common'); +var config = require('./config'); +var download = require('gulp-download'); +var fs = require('fs-extra'); +var gulp = require('gulp'); +var gutil = require('gulp-util'); +var replace = require('gulp-replace'); +var unzip = require('gulp-unzip'); +var zip = require('gulp-zip'); + +var stagingPath = config.paths.staging.zip; +var version = args.release || args.preRelease ? config.version : config.snapshotVersion; +var filename = 'vaadin-components-' + version + '.zip'; +var majorMinorVersion = version.replace(/(\d+\.\d+)(\.|-)(.*)/, '$1'); + + +gulp.task('clean:zip', function() { + fs.removeSync(stagingPath); +}); + +gulp.task('stage:zip', ['clean:zip', 'stage:cdn'], function() { + return gulp.src(config.paths.staging.cdn + '/' + version + '/**/*') + .pipe(zip(filename)) + .pipe(gulp.dest(stagingPath)); +}); + +gulp.task('zip:upload', ['stage:zip'], function(done) { + common.checkArguments(['zipUsername', 'zipDestination']); + var hostName = args.zipHostname || 'vaadin.com'; + var path = args.zipDestination + majorMinorVersion + '/' + version + '/' + filename; + + gutil.log('Uploading zip package (scp): ' + stagingPath + '/' + filename + ' -> ' + args.zipUsername + '@' + hostName + ':' + path); + + require('scp2').scp(stagingPath + '/' + filename, { + host: hostName, + username: args.zipUsername, + privateKey: config.paths.privateKey(), + path: path + }, function(err) { + done(err); + }) +}); + +function ssh(command, done) { + var hostName = args.sshHostname || 'vaadin.com'; + gutil.log('SSH: ' + hostName + ' -> ' + command); + + require('node-ssh-exec')({ + host: hostName, + username: args.zipUsername, + privateKey: config.paths.privateKey() + }, command, + function (err) { + done(err); + }); +} + +gulp.task('zip:update-references', ['zip:upload'], function(done) { + common.checkArguments(['zipUsername', 'zipDestination']); + + if(args.release) { + ssh("sed -i '1i components/" + majorMinorVersion + '/' + version + "' " + args.zipDestination + 'VERSIONS', done); + } else if(args.preRelease) { + ssh("sed -i '1i components/" + majorMinorVersion + '/' + version + "' " + args.zipDestination + 'PRERELEASES', done); + } else { + ssh('echo components/' + majorMinorVersion + '/' + version + ' > ' + args.zipDestination + 'SNAPSHOT', done); + } +}); + +gulp.task('deploy:zip', ['zip:upload', 'zip:update-references']); + +gulp.task('zip-test:clean', function() { + fs.removeSync(stagingPath + '/test'); +}); + +gulp.task('zip-test:download', ['zip-test:clean'], function() { + var url = args.zipUrl || 'https://vaadin.com/download/components'; + return download(url + '/' + majorMinorVersion +'/' + version + '/' + filename) + .pipe(gulp.dest(stagingPath + '/test')); +}); + +gulp.task('zip-test:unzip', ['zip-test:download'], function() { + return gulp.src(stagingPath + '/test/' + filename) + .pipe(unzip()) + .pipe(gulp.dest(stagingPath + '/test')); +}); + +gulp.task('zip-test:install-wct', ['zip-test:download'], function() { + return bower({ + cwd: stagingPath + '/test', + directory: '.', + cmd: 'install' + }, [['web-component-tester#2.2.6']]); +}); + +// TODO: Haven't been fixed for the new project structure. Once the tests are in use, +// apply similar changes as in cdn.js +config.components.forEach(function (n) { + gulp.task('zip-test:stage:' + n, ['zip-test:download'], function() { + return gulp.src('vaadin-components/' + n + '/test/**/*') + .pipe(replace(/(src|href)=("|')(.*?)\.\.\/\.\.\/\.\.\/\.\.\/(bower_components|node_modules)\//mg, '$1=$2../../$3')) + .pipe(replace(/(src|href)=("|')(.*?)\.\.\/\.\.\/\.\.\/(bower_components|node_modules)\//mg, '$1=$2../../$3')) + .pipe(replace(/(src|href)=("|')(.*?)\.\.\/(vaadin-)/mg, '$1=$2../../' + n + '/$3$4')) + .pipe(gulp.dest(stagingPath + '/test/test/' + n + '/')); + }); +}); + +gulp.task('zip-test:stage', _.map(config.components, function(n) { + return 'zip-test:stage:'+n; +})); + +gulp.task('verify:zip', ['zip-test:unzip', 'zip-test:install-wct', 'zip-test:stage'], function(done) { + if(args.autoRevert) { + common.checkArguments(['zipUsername', 'zipDestination']); + } + + common.testSauce( + ['target/zip/test/test/**/index.html'], + ['Windows 7/internet explorer@11'], + 'vaadin-components / vaadin.com / ' + version, + function(err) { + common.autoRevert(err, function() { + var path = args.zipDestination + majorMinorVersion + '/' + version; + + gutil.log('Deleting package ' + path); + + // remove the version from VERSIONS + ssh('grep -v "components/' + majorMinorVersion + '/' + version + '" ' + + args.zipDestination + 'VERSIONS > temp && mv temp ' + args.zipDestination + 'VERSIONS', function(error) { + if(error) done(error); + + // remove the package + ssh('rm -rf ' + path, done); + }); + }, done); + }); +}); |