git-owner
Version:
Get owners of files in git.
151 lines (145 loc) • 15.8 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('child_process')) :
typeof define === 'function' && define.amd ? define(['exports', 'child_process'], factory) :
(factory((global.gitOwner = global.gitOwner || {}),global.child_process));
}(this, (function (exports,child_process) { 'use strict';
/**
* Generates statistics about the committers for a given file.
*/
function gitBlameStats(file, callback, _spawn) {
if (_spawn === void 0) { _spawn = child_process.spawn; }
var blame = _spawn('git', ['blame', '-C', '-w', file, '--line-porcelain']);
var data = '';
var stderr = '';
blame.stdout.on('data', function (chunk) { return data += chunk; });
blame.stderr.on('data', function (chunk) { return stderr += chunk; });
blame.on('close', function (code) {
if (code !== 0) {
callback(new Error(stderr), null);
}
var committers = [];
var committersByEmail = {};
var totalLines = 0;
var pairedLines = 0;
data.split('\n').forEach(function (line) {
var emails = committerEmailsFromLine(line);
if (emails) {
totalLines++;
if (emails.length > 1) {
pairedLines++;
}
emails.forEach(function (email) {
var committer = committersByEmail[email];
if (!committer) {
committers.push(committersByEmail[email] = committer = {
email: email,
lines: 0,
percentage: 0
});
}
committer.lines++;
});
}
});
committers.forEach(function (committer) {
committer.percentage = committer.lines / totalLines;
});
callback(null, {
committers: committers,
totalLines: totalLines,
pairedLines: pairedLines
});
});
}
var COMMITTER_MAIL = 'committer-mail';
/**
* Gets the email addresses associated with this particular git-blame line.
*/
function committerEmailsFromLine(line) {
if (line.indexOf(COMMITTER_MAIL + ' ') < 0) {
return null;
}
var email = line.slice(COMMITTER_MAIL.length + 2, -1);
var match = email.match(/^git(?:hub)?\+(.+)(@.+)$/);
if (match) {
var usernames = match[1];
var athostname_1 = match[2];
return usernames.split('+').map(function (username) { return username + athostname_1; });
}
else {
return [email];
}
}
var file;
var format;
function run() {
parseArguments();
gitBlameStats(file, function (err, stats) {
if (err || !stats) {
throw err;
}
if (format === 'json') {
console.log(stats.committers);
}
else {
var maxPercentage_1 = stats.committers.reduce(function (max, committer) { return Math.max(max, committer.percentage); }, 0);
stats.committers.forEach(function (committer) {
var percentage = "" + committer.percentage * 100;
console.log('%s%s% %s', new Array(("" + maxPercentage_1 * 100).length - percentage.length + 1).join(' '), percentage, committer.email);
});
console.log();
if (stats.pairedLines > 0) {
console.log('%s lines, %s paired.', stats.totalLines, stats.pairedLines);
}
else {
console.log('%s lines.', stats.totalLines);
}
}
});
}
function parseArguments() {
var args = process.argv.slice(2);
var arg;
while ((arg = args.shift())) {
if (arg === '-h' || arg === '--help') {
usage(0);
}
else if (arg === '-f' || arg === '--format') {
var next = args.shift();
if (!next) {
usage(1);
}
else {
next = next.toLowerCase();
}
if (next !== 'json') {
usage(1);
}
format = next;
}
else if (arg[0] === '-') {
usage(1);
}
else if (!file) {
file = arg;
}
else {
usage(1);
}
}
if (!file) {
usage(1);
}
}
function usage(code) {
if (code === void 0) { code = null; }
console.error('git owner [-f JSON] FILE');
if (code !== null) {
process.exit(code);
}
}
exports.gitBlameStats = gitBlameStats;
exports.run = run;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbIi4uL2xpYi9naXRCbGFtZVN0YXRzLnRzIiwiLi4vbGliL2NsaS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBzcGF3biB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuXG5leHBvcnQgdHlwZSBCbGFtZVN0YXRzID0ge1xuICBjb21taXR0ZXJzOiBBcnJheTxDb21taXR0ZXJTdGF0cz4sXG4gIHRvdGFsTGluZXM6IG51bWJlcixcbiAgcGFpcmVkTGluZXM6IG51bWJlclxufTtcblxudHlwZSBDb21taXR0ZXJTdGF0cyA9IHtcbiAgZW1haWw6IHN0cmluZztcbiAgbGluZXM6IG51bWJlcjtcbiAgcGVyY2VudGFnZTogbnVtYmVyO1xufTtcblxudHlwZSBzcGF3bkZ1bmN0aW9uID0gdHlwZW9mIHNwYXduO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBzdGF0aXN0aWNzIGFib3V0IHRoZSBjb21taXR0ZXJzIGZvciBhIGdpdmVuIGZpbGUuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGdpdEJsYW1lU3RhdHMoZmlsZTogc3RyaW5nLCBjYWxsYmFjazogKGVycm9yOiBFcnJvciB8IG51bGwsIHN0YXRzOiBCbGFtZVN0YXRzIHwgbnVsbCkgPT4gdm9pZCwgX3NwYXduOiBzcGF3bkZ1bmN0aW9uPXNwYXduKSB7XG4gIGxldCBibGFtZSA9IF9zcGF3bignZ2l0JywgWydibGFtZScsICctQycsICctdycsIGZpbGUsICctLWxpbmUtcG9yY2VsYWluJ10pO1xuICBsZXQgZGF0YSA9ICcnO1xuICBsZXQgc3RkZXJyID0gJyc7XG5cbiAgYmxhbWUuc3Rkb3V0Lm9uKCdkYXRhJywgY2h1bmsgPT4gZGF0YSArPSBjaHVuayk7XG4gIGJsYW1lLnN0ZGVyci5vbignZGF0YScsIGNodW5rID0+IHN0ZGVyciArPSBjaHVuayk7XG5cbiAgYmxhbWUub24oJ2Nsb3NlJywgY29kZSA9PiB7XG4gICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgIGNhbGxiYWNrKG5ldyBFcnJvcihzdGRlcnIpLCBudWxsKTtcbiAgICB9XG5cbiAgICBsZXQgY29tbWl0dGVycyA9IFtdO1xuICAgIGxldCBjb21taXR0ZXJzQnlFbWFpbCA9IHt9O1xuICAgIGxldCB0b3RhbExpbmVzID0gMDtcbiAgICBsZXQgcGFpcmVkTGluZXMgPSAwO1xuXG4gICAgZGF0YS5zcGxpdCgnXFxuJykuZm9yRWFjaChsaW5lID0+IHtcbiAgICAgIGxldCBlbWFpbHMgPSBjb21taXR0ZXJFbWFpbHNGcm9tTGluZShsaW5lKTtcbiAgICAgIGlmIChlbWFpbHMpIHtcbiAgICAgICAgdG90YWxMaW5lcysrO1xuICAgICAgICBpZiAoZW1haWxzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICBwYWlyZWRMaW5lcysrO1xuICAgICAgICB9XG5cbiAgICAgICAgZW1haWxzLmZvckVhY2goZW1haWwgPT4ge1xuICAgICAgICAgIGxldCBjb21taXR0ZXIgPSBjb21taXR0ZXJzQnlFbWFpbFtlbWFpbF07XG4gICAgICAgICAgaWYgKCFjb21taXR0ZXIpIHtcbiAgICAgICAgICAgIGNvbW1pdHRlcnMucHVzaChcbiAgICAgICAgICAgICAgY29tbWl0dGVyc0J5RW1haWxbZW1haWxdID0gY29tbWl0dGVyID0ge1xuICAgICAgICAgICAgICAgIGVtYWlsLFxuICAgICAgICAgICAgICAgIGxpbmVzOiAwLFxuICAgICAgICAgICAgICAgIHBlcmNlbnRhZ2U6IDBcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29tbWl0dGVyLmxpbmVzKys7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29tbWl0dGVycy5mb3JFYWNoKGNvbW1pdHRlciA9PiB7XG4gICAgICBjb21taXR0ZXIucGVyY2VudGFnZSA9IGNvbW1pdHRlci5saW5lcyAvIHRvdGFsTGluZXM7XG4gICAgfSk7XG5cbiAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICBjb21taXR0ZXJzLFxuICAgICAgdG90YWxMaW5lcyxcbiAgICAgIHBhaXJlZExpbmVzXG4gICAgfSk7XG4gIH0pO1xufVxuXG5jb25zdCBDT01NSVRURVJfTUFJTCA9ICdjb21taXR0ZXItbWFpbCc7XG5cbi8qKlxuICogR2V0cyB0aGUgZW1haWwgYWRkcmVzc2VzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHBhcnRpY3VsYXIgZ2l0LWJsYW1lIGxpbmUuXG4gKi9cbmZ1bmN0aW9uIGNvbW1pdHRlckVtYWlsc0Zyb21MaW5lKGxpbmU6IHN0cmluZyk6IEFycmF5PHN0cmluZz4gfCBudWxsIHtcbiAgaWYgKGxpbmUuaW5kZXhPZihDT01NSVRURVJfTUFJTCArICcgJykgPCAwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBsZXQgZW1haWwgPSBsaW5lLnNsaWNlKENPTU1JVFRFUl9NQUlMLmxlbmd0aCArIDIsIC0xKTtcbiAgbGV0IG1hdGNoID0gZW1haWwubWF0Y2goL15naXQoPzpodWIpP1xcKyguKykoQC4rKSQvKTtcblxuICBpZiAobWF0Y2gpIHtcbiAgICBsZXQgdXNlcm5hbWVzID0gbWF0Y2hbMV07XG4gICAgbGV0IGF0aG9zdG5hbWUgPSBtYXRjaFsyXTtcbiAgICByZXR1cm4gdXNlcm5hbWVzLnNwbGl0KCcrJykubWFwKHVzZXJuYW1lID0+IHVzZXJuYW1lICsgYXRob3N0bmFtZSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIFtlbWFpbF07XG4gIH1cbn1cbiIsImxldCBmaWxlO1xubGV0IGZvcm1hdDtcblxuaW1wb3J0IGdpdEJsYW1lU3RhdHMgZnJvbSAnLi9naXRCbGFtZVN0YXRzJztcbmltcG9ydCB7IEJsYW1lU3RhdHMgfSBmcm9tICcuL2dpdEJsYW1lU3RhdHMnO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBydW4oKSB7XG4gIHBhcnNlQXJndW1lbnRzKCk7XG4gIGdpdEJsYW1lU3RhdHMoZmlsZSwgKGVycjogRXJyb3IgfCBudWxsLCBzdGF0czogQmxhbWVTdGF0cyB8IG51bGwpID0+IHtcbiAgICBpZiAoZXJyIHx8ICFzdGF0cykgeyB0aHJvdyBlcnI7IH1cblxuICAgIGlmIChmb3JtYXQgPT09ICdqc29uJykge1xuICAgICAgY29uc29sZS5sb2coc3RhdHMuY29tbWl0dGVycyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG1heFBlcmNlbnRhZ2UgPSBzdGF0cy5jb21taXR0ZXJzLnJlZHVjZSgobWF4LCBjb21taXR0ZXIpID0+IE1hdGgubWF4KG1heCwgY29tbWl0dGVyLnBlcmNlbnRhZ2UpLCAwKTtcblxuICAgICAgc3RhdHMuY29tbWl0dGVycy5mb3JFYWNoKGZ1bmN0aW9uKGNvbW1pdHRlcikge1xuICAgICAgICBjb25zdCBwZXJjZW50YWdlID0gYCR7Y29tbWl0dGVyLnBlcmNlbnRhZ2UgKiAxMDB9YDtcblxuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAnJXMlcyUgJXMnLFxuICAgICAgICAgIG5ldyBBcnJheSgoYCR7bWF4UGVyY2VudGFnZSAqIDEwMH1gKS5sZW5ndGggLSBwZXJjZW50YWdlLmxlbmd0aCArIDEpLmpvaW4oJyAnKSxcbiAgICAgICAgICBwZXJjZW50YWdlLFxuICAgICAgICAgIGNvbW1pdHRlci5lbWFpbFxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGNvbnNvbGUubG9nKCk7XG4gICAgICBpZiAoc3RhdHMucGFpcmVkTGluZXMgPiAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCclcyBsaW5lcywgJXMgcGFpcmVkLicsIHN0YXRzLnRvdGFsTGluZXMsIHN0YXRzLnBhaXJlZExpbmVzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCclcyBsaW5lcy4nLCBzdGF0cy50b3RhbExpbmVzKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBwYXJzZUFyZ3VtZW50cygpIHtcbiAgY29uc3QgYXJncyA9IHByb2Nlc3MuYXJndi5zbGljZSgyKTtcbiAgbGV0IGFyZztcblxuICB3aGlsZSAoKGFyZyA9IGFyZ3Muc2hpZnQoKSkpIHtcbiAgICBpZiAoYXJnID09PSAnLWgnIHx8IGFyZyA9PT0gJy0taGVscCcpIHtcbiAgICAgIHVzYWdlKDApO1xuICAgIH0gZWxzZSBpZiAoYXJnID09PSAnLWYnIHx8IGFyZyA9PT0gJy0tZm9ybWF0Jykge1xuICAgICAgbGV0IG5leHQgPSBhcmdzLnNoaWZ0KCk7XG4gICAgICBpZiAoIW5leHQpIHtcbiAgICAgICAgdXNhZ2UoMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0ID0gbmV4dC50b0xvd2VyQ2FzZSgpO1xuICAgICAgfVxuICAgICAgaWYgKG5leHQgIT09ICdqc29uJykge1xuICAgICAgICB1c2FnZSgxKTtcbiAgICAgIH1cbiAgICAgIGZvcm1hdCA9IG5leHQ7XG4gICAgfSBlbHNlIGlmIChhcmdbMF0gPT09ICctJykge1xuICAgICAgdXNhZ2UoMSk7XG4gICAgfSBlbHNlIGlmICghZmlsZSkge1xuICAgICAgZmlsZSA9IGFyZztcbiAgICB9IGVsc2Uge1xuICAgICAgdXNhZ2UoMSk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFmaWxlKSB7XG4gICAgdXNhZ2UoMSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gdXNhZ2UoY29kZTogbnVtYmVyIHwgbnVsbD1udWxsKSB7XG4gIGNvbnNvbGUuZXJyb3IoJ2dpdCBvd25lciBbLWYgSlNPTl0gRklMRScpO1xuICBpZiAoY29kZSAhPT0gbnVsbCkge1xuICAgIHByb2Nlc3MuZXhpdChjb2RlKTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQWdCQTs7O0FBR0EsdUJBQXNDLElBQVksRUFBRSxRQUFpRSxFQUFFLE1BQTJCO0lBQTNCLHlCQUFBLDRCQUEyQjtJQUNoSixJQUFJLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLGtCQUFrQixDQUFDLENBQUMsQ0FBQztJQUMzRSxJQUFJ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