Skip to content

Commit

Permalink
[added] Release task to push and tag docs and bower repos
Browse files Browse the repository at this point in the history
  • Loading branch information
mtscout6 committed Feb 16, 2015
1 parent 0193046 commit 13baeaa
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ cjs/*
amd/*
ie8/bundle.js
lib/*
tmp-bower-repo/
tmp-docs-repo/
11 changes: 9 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ module.exports = function (grunt) {
dest: 'amd/',
cwd: 'tools/amd',
expand: true
},
{
src: ['.gitignore-template'],
dest: 'amd/',
cwd: 'tools/amd',
expand: true
}
]
},
Expand Down Expand Up @@ -156,8 +162,7 @@ module.exports = function (grunt) {
src: 'amd/<%= pkg.name %>.js',
dest: 'amd/<%= pkg.name %>.min.js'
}
}

},
});

grunt.loadNpmTasks('grunt-contrib-uglify');
Expand All @@ -183,6 +188,8 @@ module.exports = function (grunt) {
'clean:transpiled'
]);

require('./tools/release/tasks')(grunt);

grunt.registerTask('default', ['build']);

};
11 changes: 11 additions & 0 deletions docs/.gitignore-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
*~
node_modules/
.DS_Store
npm-debug.log
.idea
examples/
src/
build.js
client.js
server.js
package.json
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
"scripts": {
"build": "./node_modules/.bin/grunt build",
"test-watch": "./node_modules/.bin/grunt watch 2>&1 >/dev/null & ./node_modules/karma/bin/karma start karma.dev.js",
"test": "./node_modules/.bin/grunt build && ./node_modules/karma/bin/karma start karma.ci.js",
"prepublish": "./node_modules/.bin/grunt build"
"test": "./node_modules/.bin/grunt build && ./node_modules/karma/bin/karma start karma.ci.js"
},
"main": "lib/main.js",
"directories": {
Expand All @@ -29,6 +28,7 @@
"react": ">=0.12"
},
"devDependencies": {
"async": "~0.2.9",
"envify": "~1.2.1",
"grunt": "~0.4.2",
"grunt-amd-wrap": "^1.0.1",
Expand Down Expand Up @@ -58,6 +58,7 @@
"react-async": "~2.0.0",
"react-router-component": "git://github.com/STRML/react-router-component#react-0.12",
"requirejs": "~2.1.9",
"semver": "~2.0.7",
"sinon": "^1.10.3"
}
}
Empty file added tools/amd/.gitignore-template
Empty file.
22 changes: 22 additions & 0 deletions tools/release/exec-series.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
var async = require('async'),
spawnCommand = require('./spawn-command.js');

module.exports = function execSeries(args, cb, options) {
async.eachSeries(
args,
function(args, callback) {
console.log(args[0] + ' ' + args[1].join(' '));
spawnCommand.apply(this, args.concat(options))
.on('error', function(err) {
throw err;
})
.on('exit', function(code) {
if (code) {
throw new Error('Failed executing ' + args);
} else {
callback();
}
});
},
cb);
};
18 changes: 18 additions & 0 deletions tools/release/spawn-command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var spawn = require('child_process').spawn;
var win32 = process.platform === 'win32';

// Normalize a command across OS and spawn it
//
// - command - A String containing a command to run
// - arguments - An Array of arguments to pass the command
//
// Returns ChildProcess object (of the spawned command)
module.exports = function spawnCommand(command, args, options) {
var winCommand = win32 ? 'cmd' : command;
var winArgs = win32 ? ['/c ' + command + ' ' + args.join(' ')] : args;

options = options || {};
options.stdio = 'inherit';

return spawn(winCommand, winArgs, options);
};
227 changes: 227 additions & 0 deletions tools/release/tasks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
var fs = require('fs');
var async = require('async');
var childProcess = require('child_process');
var path = require('path');
var semver = require('semver');
var execSeries = require('./exec-series.js');
var spawnCommand = require('./spawn-command.js');

module.exports = function(grunt) {
grunt.registerTask('release', function(type) {
var complete = this.async();

var filesToCopy = grunt.config.get('release-component.options.copy');
var bowerRepo = 'git@github.com:react-bootstrap/react-bootstrap-bower.git';
var docsRepo = 'git@github.com:react-bootstrap/react-bootstrap.github.io.git';

// Grunt is kind enough to change cwd to the directory the Gruntfile is in
// but double check just in case
var repoRoot = process.cwd();
var libRoot = path.join(repoRoot, 'lib/');
var bowerRoot = path.join(repoRoot, 'amd/');
var docsRoot = path.join(repoRoot, 'docs/');
var tmpBowerRepo = path.join(repoRoot, 'tmp-bower-repo');
var tmpDocsRepo = path.join(repoRoot, 'tmp-docs-repo');

var version;

async.series([
// Ensure git repo is actually ready to release
ensureClean,
ensureFetched,

// Clean build output
function(next) {
execSeries([
['rm', ['-rf', bowerRoot]],
['rm', ['-rf', libRoot]],
], next);
},

// Bump versions
function(next) {
modifyJSONSync(path.join(repoRoot, 'package.json'), function(packageJSON) {
var oldVersion = packageJSON.version;
if (!type) {
type = 'patch';
}
if (['major', 'minor', 'patch'].indexOf(type) === -1) {
version = type;
} else {
version = semver.inc(packageJSON.version, type || 'patch');
}
console.log('version changed from ' + oldVersion + ' to ' + version);
packageJSON.version = version;
});
next();
},

// Add and commit
function(next) {
execSeries([
['git', ['add', path.join(repoRoot, 'package.json')]],
['git', ['commit', '-m', '"Release v' + version + '"']]
], next);
},

// Build src
function(next) {
execSeries([
['grunt', ['build']]
], next);
},

// Build docs
function(next) {
execSeries([
['rm', ['-rf', path.join(docsRoot, 'node_modules')]],
['git', ['clean', '-dfx']],
['npm', ['install']],
['npm', ['run', 'build']]
], next, {
cwd: docsRoot
});
},

// Tag
function(next) {
tag('v' + version, next);
},

// Push
function(next) {
execSeries([
['git', ['push']],
['git', ['push', '--tags']]
], next);
},

// Publish to npm
function(next) {
execSeries([
['npm', ['publish']]
], next);
},

function(next) {
ReleaseRepo(bowerRepo, bowerRoot, tmpBowerRepo, version, next);
},

function(next) {
ReleaseRepo(docsRepo, docsRoot, tmpDocsRepo, version, next);
},

], complete);
});
};

function ReleaseRepo(repo, srcFolder, tmpFolder, version, callback) {
async.series([
// Clone repo into tmpFolder and copy built files into it
function(next) {
var commands = [
['rm', ['-rf', tmpFolder]],
['git', ['clone', repo, tmpFolder]]
];
execSeries(commands, function() {
var additionalCommands = fs.readdirSync(tmpFolder)
.filter(function(f) { return f !== '.git'; })
.map(function(f) { return ['rm', ['-rf', path.join(tmpFolder, f)]] });

additionalCommands.push(['cp', ['-R', srcFolder, tmpFolder]]);
additionalCommands.push(['mv', [path.join(tmpFolder, '.gitignore-template'), path.join(tmpFolder, '.gitignore')]]);

execSeries(additionalCommands, next)
});
},

// Add and commit in repo
function(next) {
var commands = [
['git', ['add', '-A', '.']],
['git', ['commit', '-m', '"Release v' + version + '"']]
];
execSeries(commands, next, {
cwd: tmpFolder
});
},

// Tag in repo
function(next) {
tag('v' + version, next, {
cwd: tmpFolder
});
},

// Push in repo
function(next) {
execSeries([
['git', ['push']],
['git', ['push', '--tags']]
], next, {
cwd: tmpFolder
});
},

// Delete repo
function(next) {
execSeries([
['rm', ['-rf', tmpFolder]]
], next);
}
], callback);
}

function ensureClean(callback) {
childProcess.exec('git diff-index --name-only HEAD --', function(err, stdout, stderr) {
if (err) {
throw err;
}

if (stdout.length) {
throw new Error('Git repository must be clean');
} else {
callback();
}
});
}

function tag(name, callback, options) {
spawnCommand('git', ['tag', '-a', '--message=' + name, name], options)
.on('error', function(err) {
throw err;
})
.on('exit', function(code) {
if (code) {
throw new Error('Failed tagging ' + name + ' code: ' + code);
} else {
callback();
}
});
}

function ensureFetched(callback) {
childProcess.exec('git fetch', function(err, stdout, stderr) {
if (err) {
throw err;
}

childProcess.exec('git branch -v --no-color | grep -e "^\\*"', function(err, stdout, stderr) {
if (err) {
throw err;
}

if (/\[behind (.*)\]/.test(stdout)) {
throw new Error('Your repo is behind by ' + RegExp.$1 + ' commits');
}

callback();
});
});
}

function modifyJSONSync(JSONPath, callback) {
var json = JSON.parse(fs.readFileSync(JSONPath).toString());
callback(json);
fs.writeFileSync(JSONPath, JSON.stringify(json, null, 2));
}

0 comments on commit 13baeaa

Please sign in to comment.