UNPKG

ai-commit-report-generator-cli

Version:

An AI-powered CLI tool that generates weekly reports from your Git activity

166 lines (165 loc) 7.67 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.fetchCommits = fetchCommits; exports.getCommitStatistics = getCommitStatistics; exports.fetchCommitsWithStatistics = fetchCommitsWithStatistics; exports.fetchDiffs = fetchDiffs; exports.getUniqueAuthors = getUniqueAuthors; const child_process_1 = require("child_process"); const util_1 = require("util"); const date_fns_1 = require("date-fns"); function fetchCommits() { return __awaiter(this, arguments, void 0, function* ({ filters = {}, path = "." } = {}) { const execAsync = (0, util_1.promisify)(child_process_1.exec); try { // Build git log command with date range if specified let gitCommand = `cd "${path}" && git log --format="%H|%an|%ad|%s" --date=short`; if (filters.dateRange) { const afterDate = (0, date_fns_1.format)(filters.dateRange.startDate, 'yyyy-MM-dd'); const beforeDate = (0, date_fns_1.format)(filters.dateRange.endDate, 'yyyy-MM-dd'); gitCommand += ` --after="${afterDate}" --before="${beforeDate}"`; } const { stdout, stderr } = yield execAsync(gitCommand); if (stderr) { console.warn(`Git log warning: ${stderr}`); } if (!stdout || !stdout.trim()) { return []; } const commits = stdout.split('\n').filter(line => line.trim()).map(line => { const [hash, username, date, message] = line.split('|'); return { hash, username, date, message }; }); // Apply additional filters const filteredCommits = commits.filter((commit) => { const inHashes = filters.hashes ? filters.hashes.includes(commit.hash) : true; const includesHash = filters.hash ? commit.hash.includes(filters.hash) : true; const includesUsername = filters.username ? commit.username === filters.username : true; const includesMessage = filters.message ? commit.message.includes(filters.message) : true; return inHashes && includesHash && includesUsername && includesMessage; }); return filteredCommits; } catch (error) { console.error('Error fetching git commits:', error instanceof Error ? error.message : 'Unknown error'); return []; } }); } function getCommitStatistics(commit_1) { return __awaiter(this, arguments, void 0, function* (commit, path = ".") { const execAsync = (0, util_1.promisify)(child_process_1.exec); try { // Get just the stats summary using --shortstat const { stdout: globalStats, stderr } = yield execAsync(`cd "${path}" && git show --stat ${commit.hash}`); if (stderr) { console.warn(`Warning in git show: ${stderr}`); } if (!globalStats || !globalStats.trim()) { return []; } const lines = globalStats.split('\n'); if (lines.length < 8) { // Need at least header lines + 1 stat line return []; } // Ignore the commits details lines and the last line which consist of the summary const slicedGlobalStatsArray = lines.slice(6, -2); return slicedGlobalStatsArray .filter(line => line && line.trim()) // Filter out empty lines .map(line => { const segments = line.split(" ").filter(segment => segment.length > 0); if (segments.length < 4) { return null; } const [fileName, , totalChangesStr, operationsGraph] = segments; const totalChanges = parseInt(totalChangesStr, 10); if (!operationsGraph || isNaN(totalChanges)) { return null; } const plusSymbols = (operationsGraph.match(/\+/g) || []).length; const minusSymbols = (operationsGraph.match(/-/g) || []).length; const totalSymbols = plusSymbols + minusSymbols; if (totalSymbols === 0) { return { fileName, totalChanges, numberOfInsertions: 0, numberOfDeletions: 0 }; } return { fileName, totalChanges, numberOfInsertions: Math.round((plusSymbols / totalSymbols) * totalChanges), numberOfDeletions: Math.round((minusSymbols / totalSymbols) * totalChanges) }; }) .filter((entry) => entry !== null); } catch (error) { console.error('Error fetching commit diff:', error instanceof Error ? error.message : 'Unknown error'); return []; // Return empty array instead of throwing to handle gracefully } }); } function fetchCommitsWithStatistics() { return __awaiter(this, arguments, void 0, function* (params = {}) { const commits = yield fetchCommits(params); const commitStatistics = yield Promise.all(commits.map(commit => getCommitStatistics(commit, params.path))); return commits.map((commit, i) => { return { commit, statistics: commitStatistics[i] }; }); }); } function fetchDiffs(_a) { return __awaiter(this, arguments, void 0, function* ({ filePath, hash, path = "." }) { const execAsync = (0, util_1.promisify)(child_process_1.exec); try { const { stdout, stderr } = yield execAsync(`cd "${path}" && git diff ${hash} ${filePath}`); if (stderr) { throw new Error(`Git diff error: ${stderr}`); } return stdout; } catch (err) { console.error("Failed to fetch the diff:", err instanceof Error ? err.message : 'Unknown error'); throw err; } }); } function getUniqueAuthors() { return __awaiter(this, arguments, void 0, function* (path = ".") { const execAsync = (0, util_1.promisify)(child_process_1.exec); try { const { stdout, stderr } = yield execAsync(`cd "${path}" && git log --format="%an" | sort -u`); if (stderr) { console.warn(`Git log warning: ${stderr}`); } if (!stdout || !stdout.trim()) { return []; } return stdout.trim().split('\n'); } catch (error) { console.error('Error fetching git authors:', error instanceof Error ? error.message : 'Unknown error'); return []; } }); }