Skip to content

Instantly share code, notes, and snippets.

@IlanFrumer
Last active September 1, 2022 16:34
Show Gist options
  • Save IlanFrumer/0a3c432e2c32e6fd69175ba829489986 to your computer and use it in GitHub Desktop.
Save IlanFrumer/0a3c432e2c32e6fd69175ba829489986 to your computer and use it in GitHub Desktop.
Git log working hours per day
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