Created
May 21, 2018 23:52
-
-
Save zpao/58a70ce6739a909d326d703361eba68c to your computer and use it in GitHub Desktop.
Script used to generate data for https://twitter.com/zpao/status/998702031278768129
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// inspired by https://github.com/tj/git-extras/blob/master/bin/git-line-summary | |
const util = require("util"); | |
const exec = util.promisify(require("child_process").exec); | |
const execSync = require("child_process").execSync; | |
const DIR = "/Users/poshannessy/FB/code/react-clean"; | |
const REF = "origin/master"; | |
const AUTHOR = "Paul O’Shannessy"; | |
const PERIOD_DAYS = 1; | |
async function e(cmd, cwd) { | |
const { stdout, stderr } = await exec(cmd, { cwd: cwd }); | |
return stdout.trim(); | |
} | |
function eSync(cmd, cwd) { | |
let stdout = execSync(cmd, { cwd: cwd, encoding: "utf8" }); | |
return stdout.trim(); | |
} | |
async function git(cmd) { | |
return await e(`git ${cmd}`, DIR); | |
} | |
function formatDate(d) { | |
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`; | |
} | |
function getStartNextMonth(d) { | |
let rv = new Date(d); | |
rv.setMonth(d.getMonth() + 1, 1); | |
rv.setHours(0, 0, 0, 0); | |
return rv; | |
} | |
function getEndMonth(d) { | |
let rv = new Date(d); | |
rv.setMonth(d.getMonth() + 1, 0); | |
rv.setHours(23, 59, 59, 999); | |
return rv; | |
} | |
async function main() { | |
await git(`checkout ${REF}`); | |
let firstCommit = await git("rev-list --max-parents=0 HEAD"); | |
let firstCommitTimestamp = await git(`show -s --format=%cI ${firstCommit}`); | |
let firstCommitDate = new Date(firstCommitTimestamp); | |
// firstCommitDate.setDate(firstCommitDate.getDate() - 1); | |
let lastCommitTimestamp = await git(`show -s --format=%cI ${REF}`); | |
let lastCommitDate = new Date(lastCommitTimestamp); | |
lastCommitDate.setDate(lastCommitDate.getDate() + 1); | |
let workingDate = new Date(firstCommitDate); | |
workingDate.setHours(0, 0, 0, 0); | |
console.log(firstCommit, firstCommitDate); | |
console.log(REF, lastCommitDate); | |
let commitsByDate = new Map(); | |
await git(`checkout ${REF}`); | |
while (workingDate < lastCommitDate) { | |
// let endDate = new Date(workingDate); | |
// endDate.setDate(endDate.getDate() + PERIOD_DAYS); | |
let endDate = getEndMonth(workingDate); | |
let dayCommitRaw = await git( | |
`log --no-merges --since='${workingDate.toISOString()}' --until='${endDate.toISOString()}' --format='%H %cI' --reverse | head -n1` | |
); | |
let [dayCommit, dayCommitTimestamp] = dayCommitRaw.split(" "); | |
console.log(`${workingDate.toISOString()} - ${endDate.toISOString()}`); | |
if (dayCommit !== "") { | |
commitsByDate.set(new Date(dayCommitTimestamp), dayCommit); | |
} | |
// workingDate = endDate; | |
workingDate = getStartNextMonth(workingDate); | |
} | |
for (let [commitDate, commitSHA] of commitsByDate) { | |
await git(`checkout ${commitSHA}`); | |
let totalCount = 0; | |
let blameCount = 0; | |
let files = await git("ls-files"); | |
files = files | |
.split("\n") | |
.map(s => s.trim()) | |
.filter(f => { | |
try { | |
let typeText = eSync(`file ${f} | grep text`, DIR); | |
return typeText !== ""; | |
} catch (e) { | |
return false; | |
} | |
}); | |
for (file of files) { | |
let lines = await e(`wc -l ${file}`, DIR); | |
lines = parseInt(lines); | |
totalCount += lines; | |
let blameLines = await e( | |
`git blame --line-porcelain ${file} | grep "^author\ " | LC_ALL=C sed -n 's/^author //p' | grep '${AUTHOR}' | wc -l`, | |
DIR | |
); | |
blameLines = parseInt(blameLines); | |
blameCount += blameLines; | |
} | |
console.log(`${formatDate(commitDate)}\t${totalCount}\t${blameCount}`); | |
} | |
} | |
try { | |
main(); | |
} catch (e) { | |
console.error(e); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment