Skip to content

Commit

Permalink
feat: add --monthly flag to committers
Browse files Browse the repository at this point in the history
  • Loading branch information
marco-ippolito committed Dec 13, 2024
1 parent 05904b7 commit c534320
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 30 deletions.
94 changes: 94 additions & 0 deletions libs/report/committers/src/lib/committers-monthly.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { parseMonthly } from './parse-monthly';

describe('parseMonthly', () => {
const sampleCommits = [
{
date: new Date('2023-01-15T12:00:00Z'),
committer: 'Marco',
commitHash: 'abc123',
},
{
date: new Date('2023-01-20T12:00:00Z'),
committer: 'Marco',
commitHash: 'def456',
},
{
date: new Date('2023-02-10T12:00:00Z'),
committer: 'George',
commitHash: 'ghi789',
},
{
date: new Date('2023-02-15T12:00:00Z'),
committer: 'Marco',
commitHash: 'jkl012',
},
];

it('should group commits by month and count them per committer', () => {
const start = new Date('2023-01-01T00:00:00Z');
const end = new Date('2023-03-01T00:00:00Z');
const result = parseMonthly(start, end, sampleCommits);

expect(result).toEqual([
{
month: 'January 2023',
start,
end,
committers: {
Marco: 2,
},
},
{
month: 'February 2023',
start,
end,
committers: {
George: 1,
Marco: 1,
},
},
]);
});

it('should return an empty array if there are no commits', () => {
const result = parseMonthly(
new Date('2023-01-01T00:00:00Z'),
new Date('2023-03-01T00:00:00Z'),
[]
);
expect(result).toEqual([]);
});

it('should handle date ranges with no commits in certain months', () => {
const commits = [
{
date: new Date('2023-03-10T12:00:00Z'),
committer: 'Greg',
commitHash: 'mno345',
},
];
const start = new Date('2023-01-01T00:00:00Z');
const end = new Date('2023-04-01T00:00:00Z');
const result = parseMonthly(start, end, commits);

expect(result).toEqual([
{
month: 'March 2023',
start,
end,
committers: {
Greg: 1,
},
},
]);
});

it('should handle an empty date range', () => {
const result = parseMonthly(
new Date('2023-01-01T00:00:00Z'),
new Date('2023-01-01T00:00:00Z'),
sampleCommits
);
expect(result).toEqual([]);
});
});
24 changes: 24 additions & 0 deletions libs/report/committers/src/lib/committers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ import { parseGitLogEntries } from './parse-git-log-entries';
import { getCommitterCounts } from './get-committer-counts';
import { ArgumentsCamelCase, CommandBuilder, CommandModule } from 'yargs';
import { CommitterCount } from './types';
import {
outputMonthlyCommitters,
outputMonthlyCommittersJson,
parseMonthly,
} from './parse-monthly';

interface Options {
beforeDate: string;
afterDate: string;
exclude: string[];
json: boolean;
directory: string;
monthly: boolean;
}

export const reportCommittersCommand: CommandModule<object, Options> = {
Expand Down Expand Up @@ -50,6 +56,13 @@ export const reportCommittersCommand: CommandModule<object, Options> = {
required: false,
string: true,
},
monthly: {
alias: 'm',
boolean: true,
describe: 'Break down by calendar month, rather than by committer.',
required: false,
default: false,
},
} as CommandBuilder<unknown, Options>,
handler: run,
};
Expand Down Expand Up @@ -80,6 +93,17 @@ async function run(args: ArgumentsCamelCase<Options>): Promise<void> {
return;
}
const entries = parseGitLogEntries(rawEntries);

if (args.monthly) {
const monthly = parseMonthly(afterDate, beforeDate, entries);
if (args.json) {
outputMonthlyCommittersJson(monthly);
return;
}
outputMonthlyCommitters(monthly);
return;
}

const committerCounts = getCommitterCounts(entries);
if (args.json) {
outputCommittersJson(committerCounts);
Expand Down
58 changes: 30 additions & 28 deletions libs/report/committers/src/lib/parse-monthly.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
import {
eachMonthOfInterval,
format,
isWithinInterval,
max,
min,
} from 'date-fns';
import { MonthlyData } from './types';
import { eachMonthOfInterval, format, isWithinInterval } from 'date-fns';
import { Commit, MonthlyData } from './types';

export function parseMonthly(
startDate: Date,
endDate: Date,
entries: { commitHash: string; committer: string; date: string }[]
) {
export function parseMonthly(startDate: Date, endDate: Date, entries: Commit[]) {
const monthly: MonthlyData[] = [];
const dates = [startDate, endDate];
const ival = {
start: min(dates),
end: max(dates),
};
const range = eachMonthOfInterval(ival);
const range = eachMonthOfInterval({
start: startDate,
end: endDate,
});

for (const idxr in range) {
const idx = parseInt(idxr);
if (idx + 1 >= range.length) {
continue;
}
const [start, end] = [range[idx], range[idx + 1]];
const month: MonthlyData = {
name: format(start, 'LLLL yyyy'),
start,
end,
month: format(start, 'LLLL yyyy'),
start: startDate,
end: endDate,
committers: {},
};

for (const rec of entries) {
if (isWithinInterval(new Date(rec.date), { start, end })) {
month.committers[rec.committer] = month.committers[rec.committer] || [];
month.committers[rec.committer].push({
hash: rec.commitHash,
date: rec.date,
});
if (isWithinInterval(rec.date, { start, end })) {
month.committers[rec.committer] = (month.committers[rec.committer] || 0) + 1;
}
}

Expand All @@ -48,3 +33,20 @@ export function parseMonthly(
}
return monthly;
}

function monthlyDataHumanReadable(data: MonthlyData) {
return {
...data,
start: format(data.start, 'yyyy-MM-dd'),
end: format(data.end, 'yyyy-MM-dd'),
};
}

export function outputMonthlyCommitters(commits: MonthlyData[]) {
const mapped = commits.map((c) => monthlyDataHumanReadable(c));
console.table(mapped);
}

export function outputMonthlyCommittersJson(commits: MonthlyData[]) {
console.log(JSON.stringify(commits, null, 2));
}
4 changes: 2 additions & 2 deletions libs/report/committers/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export type CommitterCount = {
};

export type MonthlyData = {
name: string;
month: string;
start: Date;
end: Date;
committers: Record<string, { hash: string; date: string }[]>;
committers: Record<string, number>;
};

export type SortedCommitterInfo = {
Expand Down

0 comments on commit c534320

Please sign in to comment.