git-owner
Version:
Get owners of files in git.
142 lines (138 loc) • 15.4 kB
JavaScript
import { spawn } from 'child_process';
/**
* Generates statistics about the committers for a given file.
*/
function gitBlameStats(file, callback, _spawn) {
if (_spawn === void 0) { _spawn = 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);
}
}
export { gitBlameStats, run };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbIi4uL2xpYi9naXRCbGFtZVN0YXRzLnRzIiwiLi4vbGliL2NsaS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBzcGF3biB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuXG5leHBvcnQgdHlwZSBCbGFtZVN0YXRzID0ge1xuICBjb21taXR0ZXJzOiBBcnJheTxDb21taXR0ZXJTdGF0cz4sXG4gIHRvdGFsTGluZXM6IG51bWJlcixcbiAgcGFpcmVkTGluZXM6IG51bWJlclxufTtcblxudHlwZSBDb21taXR0ZXJTdGF0cyA9IHtcbiAgZW1haWw6IHN0cmluZztcbiAgbGluZXM6IG51bWJlcjtcbiAgcGVyY2VudGFnZTogbnVtYmVyO1xufTtcblxudHlwZSBzcGF3bkZ1bmN0aW9uID0gdHlwZW9mIHNwYXduO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBzdGF0aXN0aWNzIGFib3V0IHRoZSBjb21taXR0ZXJzIGZvciBhIGdpdmVuIGZpbGUuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGdpdEJsYW1lU3RhdHMoZmlsZTogc3RyaW5nLCBjYWxsYmFjazogKGVycm9yOiBFcnJvciB8IG51bGwsIHN0YXRzOiBCbGFtZVN0YXRzIHwgbnVsbCkgPT4gdm9pZCwgX3NwYXduOiBzcGF3bkZ1bmN0aW9uPXNwYXduKSB7XG4gIGxldCBibGFtZSA9IF9zcGF3bignZ2l0JywgWydibGFtZScsICctQycsICctdycsIGZpbGUsICctLWxpbmUtcG9yY2VsYWluJ10pO1xuICBsZXQgZGF0YSA9ICcnO1xuICBsZXQgc3RkZXJyID0gJyc7XG5cbiAgYmxhbWUuc3Rkb3V0Lm9uKCdkYXRhJywgY2h1bmsgPT4gZGF0YSArPSBjaHVuayk7XG4gIGJsYW1lLnN0ZGVyci5vbignZGF0YScsIGNodW5rID0+IHN0ZGVyciArPSBjaHVuayk7XG5cbiAgYmxhbWUub24oJ2Nsb3NlJywgY29kZSA9PiB7XG4gICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgIGNhbGxiYWNrKG5ldyBFcnJvcihzdGRlcnIpLCBudWxsKTtcbiAgICB9XG5cbiAgICBsZXQgY29tbWl0dGVycyA9IFtdO1xuICAgIGxldCBjb21taXR0ZXJzQnlFbWFpbCA9IHt9O1xuICAgIGxldCB0b3RhbExpbmVzID0gMDtcbiAgICBsZXQgcGFpcmVkTGluZXMgPSAwO1xuXG4gICAgZGF0YS5zcGxpdCgnXFxuJykuZm9yRWFjaChsaW5lID0+IHtcbiAgICAgIGxldCBlbWFpbHMgPSBjb21taXR0ZXJFbWFpbHNGcm9tTGluZShsaW5lKTtcbiAgICAgIGlmIChlbWFpbHMpIHtcbiAgICAgICAgdG90YWxMaW5lcysrO1xuICAgICAgICBpZiAoZW1haWxzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICBwYWlyZWRMaW5lcysrO1xuICAgICAgICB9XG5cbiAgICAgICAgZW1haWxzLmZvckVhY2goZW1haWwgPT4ge1xuICAgICAgICAgIGxldCBjb21taXR0ZXIgPSBjb21taXR0ZXJzQnlFbWFpbFtlbWFpbF07XG4gICAgICAgICAgaWYgKCFjb21taXR0ZXIpIHtcbiAgICAgICAgICAgIGNvbW1pdHRlcnMucHVzaChcbiAgICAgICAgICAgICAgY29tbWl0dGVyc0J5RW1haWxbZW1haWxdID0gY29tbWl0dGVyID0ge1xuICAgICAgICAgICAgICAgIGVtYWlsLFxuICAgICAgICAgICAgICAgIGxpbmVzOiAwLFxuICAgICAgICAgICAgICAgIHBlcmNlbnRhZ2U6IDBcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29tbWl0dGVyLmxpbmVzKys7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29tbWl0dGVycy5mb3JFYWNoKGNvbW1pdHRlciA9PiB7XG4gICAgICBjb21taXR0ZXIucGVyY2VudGFnZSA9IGNvbW1pdHRlci5saW5lcyAvIHRvdGFsTGluZXM7XG4gICAgfSk7XG5cbiAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICBjb21taXR0ZXJzLFxuICAgICAgdG90YWxMaW5lcyxcbiAgICAgIHBhaXJlZExpbmVzXG4gICAgfSk7XG4gIH0pO1xufVxuXG5jb25zdCBDT01NSVRURVJfTUFJTCA9ICdjb21taXR0ZXItbWFpbCc7XG5cbi8qKlxuICogR2V0cyB0aGUgZW1haWwgYWRkcmVzc2VzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHBhcnRpY3VsYXIgZ2l0LWJsYW1lIGxpbmUuXG4gKi9cbmZ1bmN0aW9uIGNvbW1pdHRlckVtYWlsc0Zyb21MaW5lKGxpbmU6IHN0cmluZyk6IEFycmF5PHN0cmluZz4gfCBudWxsIHtcbiAgaWYgKGxpbmUuaW5kZXhPZihDT01NSVRURVJfTUFJTCArICcgJykgPCAwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBsZXQgZW1haWwgPSBsaW5lLnNsaWNlKENPTU1JVFRFUl9NQUlMLmxlbmd0aCArIDIsIC0xKTtcbiAgbGV0IG1hdGNoID0gZW1haWwubWF0Y2goL15naXQoPzpodWIpP1xcKyguKykoQC4rKSQvKTtcblxuICBpZiAobWF0Y2gpIHtcbiAgICBsZXQgdXNlcm5hbWVzID0gbWF0Y2hbMV07XG4gICAgbGV0IGF0aG9zdG5hbWUgPSBtYXRjaFsyXTtcbiAgICByZXR1cm4gdXNlcm5hbWVzLnNwbGl0KCcrJykubWFwKHVzZXJuYW1lID0+IHVzZXJuYW1lICsgYXRob3N0bmFtZSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIFtlbWFpbF07XG4gIH1cbn1cbiIsImxldCBmaWxlO1xubGV0IGZvcm1hdDtcblxuaW1wb3J0IGdpdEJsYW1lU3RhdHMgZnJvbSAnLi9naXRCbGFtZVN0YXRzJztcbmltcG9ydCB7IEJsYW1lU3RhdHMgfSBmcm9tICcuL2dpdEJsYW1lU3RhdHMnO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBydW4oKSB7XG4gIHBhcnNlQXJndW1lbnRzKCk7XG4gIGdpdEJsYW1lU3RhdHMoZmlsZSwgKGVycjogRXJyb3IgfCBudWxsLCBzdGF0czogQmxhbWVTdGF0cyB8IG51bGwpID0+IHtcbiAgICBpZiAoZXJyIHx8ICFzdGF0cykgeyB0aHJvdyBlcnI7IH1cblxuICAgIGlmIChmb3JtYXQgPT09ICdqc29uJykge1xuICAgICAgY29uc29sZS5sb2coc3RhdHMuY29tbWl0dGVycyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG1heFBlcmNlbnRhZ2UgPSBzdGF0cy5jb21taXR0ZXJzLnJlZHVjZSgobWF4LCBjb21taXR0ZXIpID0+IE1hdGgubWF4KG1heCwgY29tbWl0dGVyLnBlcmNlbnRhZ2UpLCAwKTtcblxuICAgICAgc3RhdHMuY29tbWl0dGVycy5mb3JFYWNoKGZ1bmN0aW9uKGNvbW1pdHRlcikge1xuICAgICAgICBjb25zdCBwZXJjZW50YWdlID0gYCR7Y29tbWl0dGVyLnBlcmNlbnRhZ2UgKiAxMDB9YDtcblxuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAnJXMlcyUgJXMnLFxuICAgICAgICAgIG5ldyBBcnJheSgoYCR7bWF4UGVyY2VudGFnZSAqIDEwMH1gKS5sZW5ndGggLSBwZXJjZW50YWdlLmxlbmd0aCArIDEpLmpvaW4oJyAnKSxcbiAgICAgICAgICBwZXJjZW50YWdlLFxuICAgICAgICAgIGNvbW1pdHRlci5lbWFpbFxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGNvbnNvbGUubG9nKCk7XG4gICAgICBpZiAoc3RhdHMucGFpcmVkTGluZXMgPiAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCclcyBsaW5lcywgJXMgcGFpcmVkLicsIHN0YXRzLnRvdGFsTGluZXMsIHN0YXRzLnBhaXJlZExpbmVzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCclcyBsaW5lcy4nLCBzdGF0cy50b3RhbExpbmVzKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBwYXJzZUFyZ3VtZW50cygpIHtcbiAgY29uc3QgYXJncyA9IHByb2Nlc3MuYXJndi5zbGljZSgyKTtcbiAgbGV0IGFyZztcblxuICB3aGlsZSAoKGFyZyA9IGFyZ3Muc2hpZnQoKSkpIHtcbiAgICBpZiAoYXJnID09PSAnLWgnIHx8IGFyZyA9PT0gJy0taGVscCcpIHtcbiAgICAgIHVzYWdlKDApO1xuICAgIH0gZWxzZSBpZiAoYXJnID09PSAnLWYnIHx8IGFyZyA9PT0gJy0tZm9ybWF0Jykge1xuICAgICAgbGV0IG5leHQgPSBhcmdzLnNoaWZ0KCk7XG4gICAgICBpZiAoIW5leHQpIHtcbiAgICAgICAgdXNhZ2UoMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXh0ID0gbmV4dC50b0xvd2VyQ2FzZSgpO1xuICAgICAgfVxuICAgICAgaWYgKG5leHQgIT09ICdqc29uJykge1xuICAgICAgICB1c2FnZSgxKTtcbiAgICAgIH1cbiAgICAgIGZvcm1hdCA9IG5leHQ7XG4gICAgfSBlbHNlIGlmIChhcmdbMF0gPT09ICctJykge1xuICAgICAgdXNhZ2UoMSk7XG4gICAgfSBlbHNlIGlmICghZmlsZSkge1xuICAgICAgZmlsZSA9IGFyZztcbiAgICB9IGVsc2Uge1xuICAgICAgdXNhZ2UoMSk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFmaWxlKSB7XG4gICAgdXNhZ2UoMSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gdXNhZ2UoY29kZTogbnVtYmVyIHwgbnVsbD1udWxsKSB7XG4gIGNvbnNvbGUuZXJyb3IoJ2dpdCBvd25lciBbLWYgSlNPTl0gRklMRScpO1xuICBpZiAoY29kZSAhPT0gbnVsbCkge1xuICAgIHByb2Nlc3MuZXhpdChjb2RlKTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBZ0JBOzs7QUFHQSx1QkFBc0MsSUFBWSxFQUFFLFFBQWlFLEVBQUUsTUFBMkI7SUFBM0IseUJBQUEsY0FBMkI7SUFDaEosSUFBSSxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7SUFDM0UsSUFBSSxJQUFJ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