Files
angular.js/compare-master-to-stable.js
Caitlin Potter c5f1ca3d91 chore(compare-master-to-stable): make checks for bugfixes better
Prevent the script from alerting you if a docs fix has something like "Fixes typo in foo", which is
not how bugfixes are worded.

Closes #8801
2014-08-29 11:59:07 -04:00

169 lines
3.7 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict';
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 + ((/fix\([^\)]+\):/i.test(msg)) ? ' * ' : ' ') + 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);
});