![]()
Cannot retrieve contributors at this time
| #!/usr/bin/env 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) { | |
| var master = tags.pop(); | |
| var stable = tags.pop(); | |
| return [ | |
| { name: stable.replace(/\d+$/, 'x'), tag: stable }, | |
| { name: 'master', tag: master} | |
| ]; | |
| }). | |
| 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); | |
| }); | |