git-contributor-stats
Version:
CLI to compute contributor and repository statistics from a Git repository (commits, lines added/deleted, frequency, heatmap, bus-factor), with filters and multiple output formats.
136 lines (131 loc) • 5.47 kB
JavaScript
import path from "node:path";
import process$1 from "node:process";
import { g as generateCharts } from "./features/charts.mjs";
import { h as handleStdoutOutput } from "./features/output.mjs";
import { g as generateReports } from "./features/reports.mjs";
import { g as getContributorStats } from "./features/stats.mjs";
import { g as generateWorkflow } from "./features/workflow.mjs";
import { i as isGitRepo } from "./chunks/git-BxSpsWYT.mjs";
import { s as safeReadPackageJson } from "./chunks/utils-CFufYn8A.mjs";
import { Command } from "commander";
import "node:fs";
import "./chunks/analytics-SL4YC1kG.mjs";
import "node:child_process";
function setupCLI(pkg) {
const program = new Command();
program.name("git-contributor-stats").description("Compute contributor and repository statistics from a Git repository").version(pkg.version || "0.0.0").argument("[paths...]", "Optional pathspec(s) to limit stats to certain files or directories").option("-r, --repo <repoPath>", "Path to the Git repository (default: current directory)", ".").option(
"-b, --branch <name>",
"Branch or commit range to analyze (e.g., main or main..feature)"
).option(
"--since <when>",
"Only include commits more recent than <when> (e.g., '2024-01-01', '30.days', '2.weeks')"
).option("--until <when>", "Only include commits older than <when> (e.g., '2024-06-30')").option(
"-a, --author <pattern>",
"Limit to commits by author (string or regex supported by git)"
).option("--include-merges", "Include merge commits (excluded by default)", false).option("-g, --group-by <field>", "Grouping key: email | name (default: email)", "email").option("-l, --label-by <field>", "Display label: email | name (default: name)", "name").option(
"-s, --sort-by <metric>",
"Sort by: changes | commits | additions | deletions",
"changes"
).option(
"-t, --top <n>",
"Limit to top N contributors (for table/CSV stdout)",
(v) => Number.parseInt(v, 10)
).option("-f, --format <kind>", "Output format to stdout: table | json | csv", "table").option("--json", "Print comprehensive JSON analysis to stdout", false).option("--csv <csvPath>", "Write CSV contributors summary to file").option("--md <mdPath>", "Write Markdown report to file").option("--html <htmlPath>", "Write HTML dashboard report to file").option(
"--out-dir <outDir>",
"Write selected outputs into the directory (uses default filenames)"
).option(
"--charts",
"Generate charts (defaults to SVG). Use --chart-format to switch formats.",
false
).option(
"--charts-dir <chartsDir>",
"Directory to write charts (overrides default when --charts is set)"
).option(
"--chart-format <format>",
"Chart output format: svg | png | both (default: svg)",
"svg"
).option(
"--similarity <threshold>",
"Name merge similarity threshold (0..1)",
(v) => Number.parseFloat(v),
0.85
).option("--alias-file <aliasFile>", "Path to alias mapping JSON file").option("--no-count-lines", "Skip counting total lines in repo (faster)").option("--no-top-stats", "Omit the Top stats section in Markdown/HTML and stdout table output").option(
"--top-stats <list>",
"Top stats metrics to show (comma-separated): commits, additions, deletions, net, changes"
).option(
"--generate-workflow",
"Create a sample GitHub Actions workflow under .github/workflows/",
false
).option("-v, --verbose", "Verbose logging", false).addHelpText(
"after",
`
Examples:
# Top 10 contributors in the current repo
git-contributor-stats --top 10
# Only for the last 90 days on main
git-contributor-stats -b main --since 90.days
# Stats for a specific folder, as JSON (comprehensive)
git-contributor-stats src/ --json
# Generate Markdown and HTML reports into reports/ and write charts
git-contributor-stats --out-dir reports --md reports/report.md --html reports/report.html --charts
# Merge similar contributor names (default threshold 0.85)
git-contributor-stats --similarity 0.9
`
);
return program;
}
async function main(argv) {
const pkg = safeReadPackageJson();
const program = setupCLI(pkg);
program.parse(argv);
const opts = program.opts();
const paths = program.args || [];
const repo = path.resolve(process$1.cwd(), opts.repo || ".");
if (!isGitRepo(repo)) {
console.error(`Not a Git repository: ${repo}`);
process$1.exit(2);
}
const apiOptions = {
repo,
branch: opts.branch,
since: opts.since,
until: opts.until,
author: opts.author,
includeMerges: !!opts.includeMerges,
groupBy: opts.groupBy,
labelBy: opts.labelBy,
sortBy: opts.sortBy,
top: opts.top,
similarity: opts.similarity,
aliasFile: opts.aliasFile,
countLines: opts.countLines,
paths,
verbose: opts.verbose
};
let final;
try {
final = await getContributorStats(apiOptions);
} catch (e) {
console.error(e?.message || String(e));
process$1.exit(2);
}
await generateReports(final, opts);
await generateCharts(final, opts, opts.outDir);
if (opts.generateWorkflow) {
await generateWorkflow(repo);
}
handleStdoutOutput(final, {
json: opts.json,
format: opts.format,
topStats: opts.topStats,
labelBy: opts.labelBy
});
}
try {
await main(process.argv);
} catch (err) {
console.error(err instanceof Error ? err.stack : String(err));
process.exit(2);
}
//# sourceMappingURL=cli.mjs.map