Last active
September 1, 2022 16:34
-
-
Save IlanFrumer/0a3c432e2c32e6fd69175ba829489986 to your computer and use it in GitHub Desktop.
Git log working hours per day
This file contains 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
import moment from "https://deno.land/x/[email protected]/mod.ts"; | |
import { parse } from "https://deno.land/[email protected]/flags/mod.ts"; | |
export const DELIMITER = "隔"; | |
interface DailyCommits { | |
start: moment.Moment; | |
end: moment.Moment; | |
commits: number; | |
messages: string[]; | |
} | |
export class Commits { | |
days = new Map<string, DailyCommits>(); | |
add({ date, message }: { date: string; message: string }) { | |
const dateMoment = moment(new Date(date)); | |
const day = dateMoment.format("YYYY-MM-DD"); | |
const msg = `${dateMoment.format("HH:mm")} ${message}`; | |
const data = this.days.get(day); | |
if (!data) { | |
this.days.set(day, { | |
start: dateMoment, | |
end: dateMoment, | |
commits: 1, | |
messages: [msg], | |
}); | |
} else { | |
data.start = dateMoment.isBefore(data.start) ? dateMoment : data.start; | |
data.end = dateMoment.isAfter(data.end) ? dateMoment : data.end; | |
data.messages.unshift(msg); | |
data.commits++; | |
} | |
} | |
print() { | |
for (const { start, end, commits, messages } of this.days.values()) { | |
const dateStr = start.format("ddd DD/MM/YY"); | |
const rangeStr = `${start.format("HH:mm")} - ${end.format("HH:mm")}`; | |
let minutes = end.diff(start, "minutes"); | |
const diff = minutes % 30; | |
minutes = diff > 0 ? minutes + 30 - diff : minutes; | |
const hours = minutes / 60; | |
const hoursStr = hours.toString(); | |
console.log(`${dateStr} (${rangeStr})`); | |
console.log(`${commits} commits, ${hoursStr} hours`); | |
console.log(messages.join("\n")); | |
console.log("------------------------------------------------------"); | |
} | |
} | |
} | |
function getRange(range: string) { | |
let date: moment.Moment; | |
let unit: "year" | "month" = "month"; | |
if (/^\d{4}$/.test(range)) { | |
date = moment(range, "YYYY"); | |
unit = "year"; | |
} else if (/^\d{1,2}$/.test(range)) { | |
date = moment(range, "MM"); | |
} else if (/^\d{4}-\d{1,2}$/.test(range)) { | |
date = moment(range, "YYYY-MM"); | |
} else if (/^\d{2}-\d{1,2}$/.test(range)) { | |
date = moment(range, "YY-MM"); | |
} else { | |
throw new Error(`Invalid range: ${range}`); | |
} | |
return { | |
since: date.startOf(unit).format("YYYY-MM-DD"), | |
until: date.endOf(unit).format("YYYY-MM-DD"), | |
}; | |
} | |
async function gitSuperLog({ | |
cwd, | |
author, | |
range, | |
branch, | |
}: { | |
cwd: string | null; | |
author: string | null; | |
range: string | null; | |
branch: string | null; | |
}) { | |
const cmd = ["git", "log"]; | |
if (branch != null) { | |
cmd.push(branch); | |
} | |
if (author != null) { | |
cmd.push(...["--author", author]); | |
} | |
if (range != null) { | |
const { since, until } = getRange(range); | |
cmd.push(...["--since", since, "--until", until]); | |
} | |
cmd.push(`--pretty=format:%ad${DELIMITER}%s`); | |
const pr = Deno.run({ | |
cmd, | |
cwd: cwd ?? undefined, | |
stdout: "piped", | |
stderr: "piped", | |
}); | |
const output = await pr.output(); | |
pr.close(); | |
const commits = new Commits(); | |
new TextDecoder() | |
.decode(output) | |
.split("\n") | |
.filter(Boolean) | |
.map((d) => d.split(DELIMITER)) | |
.forEach(([date, message]) => { | |
commits.add({ date, message }); | |
}); | |
commits.print(); | |
} | |
const argv = parse(Deno.args, { | |
alias: { | |
cwd: "c", | |
range: "r", | |
branch: "b", | |
author: "a", | |
}, | |
string: ["cwd", "range", "branch", "author"], | |
default: { | |
cwd: null, | |
range: null, | |
branch: null, | |
author: null, | |
}, | |
}); | |
gitSuperLog(argv); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment