aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcompare-master-to-stable.js163
-rw-r--r--package.json4
2 files changed, 166 insertions, 1 deletions
diff --git a/compare-master-to-stable.js b/compare-master-to-stable.js
new file mode 100755
index 00000000..404383b0
--- /dev/null
+++ b/compare-master-to-stable.js
@@ -0,0 +1,163 @@
+#!/usr/local/bin/node
+
+var util = require('util');
+var cp = require('child_process');
+
+var Q = require('q');
+var _ = require('lodash');
+var semver = require('semver');
+
+var exec = function (cmd) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments, 0);
+ args.unshift(cmd);
+ var fullCmd = util.format.apply(util, args);
+ return Q.nfcall(cp.exec, fullCmd).then(function (out) {
+ return out[0].split('\n');
+ });
+ };
+};
+
+var andThen = function (fn, after) {
+ return function () {
+ return fn.apply(this, arguments).then(after);
+ };
+};
+
+var oneArg = function (fn) {
+ return function (arg) {
+ return fn(arg);
+ };
+};
+
+var oneLine = function (lines) {
+ return lines[0].trim();
+};
+
+var noArgs = function (fn) {
+ return function () {
+ return fn();
+ };
+};
+
+var identity = function (i) { return i; };
+
+// like Q.all, but runs the comands in series
+// useful for ensuring env state (like which branch is checked out)
+var allInSeries = function (fn) {
+ return function (args) {
+ var results = [];
+ var def;
+ while (args.length > 0) {
+ (function (arg) {
+ if (def) {
+ def = def.then(function () {
+ return fn(arg);
+ });
+ } else {
+ def = fn(arg);
+ }
+ def = def.then(function (res) {
+ results.push(res);
+ });
+ }(args.pop()));
+ }
+ return def.then(function () {
+ return results;
+ });
+ };
+};
+
+var compareBranches = function (left, right) {
+ console.log('# These commits are in ' + left.name + ' but not in ' + right.name + '\n');
+ console.log(_(left.log).
+ difference(right.log).
+ map(function (line) {
+ return left.full[left.log.indexOf(line)]; // lol O(n^2)
+ }).
+ value().
+ join('\n'));
+};
+
+var checkout = oneArg(exec('git checkout %s'));
+
+var getCurrentBranch = andThen(noArgs(exec('git rev-parse --abbrev-ref HEAD')), oneLine);
+var getTags = noArgs(exec('git tag'));
+var getShaOfTag = oneArg(exec('git rev-list %s | head -n 1'));
+var getTheLog = oneArg(exec('git log --pretty=oneline %s..HEAD | cat'));
+
+// remember this so we can restore state
+var currentBranch;
+
+getCurrentBranch().
+then(function (branch) {
+ currentBranch = branch;
+}).
+then(getTags).
+then(function (tags) {
+ return tags.
+ filter(semver.valid).
+ map(semver.clean).
+ sort(semver.rcompare);
+}).
+then(function (tags) {
+ var major = tags[0].split('.')[0] + '.x';
+ return tags.
+ filter(function (ver) {
+ return semver.satisfies(ver, major);
+ });
+}).
+then(function (tags) {
+ return _(tags).
+ groupBy(function (tag) {
+ return tag.split('.')[1];
+ }).
+ map(function (group) {
+ return _.first(group);
+ }).
+ map(function (tag) {
+ return 'v' + tag;
+ }).
+ value();
+}).
+then(function (tags) {
+ return [
+ { name: 'v1.0.x', tag: tags[0] },
+ { name: 'master', tag: tags[1] }
+ ];
+}).
+then(allInSeries(function (branch) {
+ return checkout(branch.name).
+ then(function () {
+ return getTheLog(branch.tag);
+ }).
+ then(function (log) {
+ return log.
+ filter(identity);
+ }).
+ then(function (log) {
+ branch.full = log.map(function (line) {
+ line = line.split(' ');
+ var sha = line.shift();
+ var msg = line.join(' ');
+ return sha + (msg.toLowerCase().indexOf('fix') === -1 ? ' ' : ' * ') + msg;
+ });
+ branch.log = log.map(function (line) {
+ return line.substr(41)
+ });
+ return branch;
+ });
+})).
+then(function (pairs) {
+ compareBranches(pairs[0], pairs[1]);
+ console.log('\n');
+ compareBranches(pairs[1], pairs[0]);
+ return pairs;
+}).
+then(function () {
+ return checkout(currentBranch);
+}).
+catch(function (e) {
+ console.log(e.stack);
+});
+
diff --git a/package.json b/package.json
index 8cc184cb..2cc6daf4 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,9 @@
"grunt-ddescribe-iit": "~0.0.1",
"grunt-merge-conflict": "~0.0.1",
"promises-aplus-tests": "~1.3.2",
- "grunt-shell": "~0.3.1"
+ "grunt-shell": "~0.3.1",
+ "semver": "~2.1.0",
+ "lodash": "~1.3.1"
},
"licenses": [
{