UNPKG

git-spark

Version:

Git repository analytics and reporting tool for analyzing commit patterns and contributor activity

869 lines 24.7 kB
/** * Core types and interfaces for git-spark */ export interface GitSparkConfig { version: string; analysis: AnalysisConfig; output: OutputConfig; performance: PerformanceConfig; } export interface AnalysisConfig { excludePaths: string[]; includeAuthors: string[]; excludeAuthors: string[]; thresholds: AnalysisThresholds; weights: AnalysisWeights; } export interface AnalysisThresholds { largeCommitLines: number; smallCommitLines: number; staleBranchDays: number; largeFileKB: number; hotspotAuthorThreshold: number; } export interface AnalysisWeights { risk: RiskWeights; governance: GovernanceWeights; } export interface RiskWeights { churn: number; recency: number; ownership: number; entropy: number; coupling: number; } export interface GovernanceWeights { conventional: number; traceability: number; length: number; wipPenalty: number; revertPenalty: number; shortPenalty: number; } export interface OutputConfig { defaultFormat: OutputFormat; outputDir: string; includeCharts: boolean; redactEmails: boolean; theme: string; fileFiltering: FileFilteringConfig; } export interface FileFilteringConfig { /** Extensions considered source code files for hotspot analysis */ sourceCodeExtensions: string[]; /** Extensions considered configuration/output files (excluded from hotspots) */ configExtensions: string[]; /** File patterns to exclude from hotspot analysis */ excludePatterns: string[]; /** Maximum number of files to show in hotspots */ maxHotspots: number; } export interface PerformanceConfig { maxBuffer: number; enableCaching: boolean; cacheDir: string; chunkSize: number; } export type OutputFormat = 'html' | 'json' | 'console' | 'markdown' | 'csv'; export interface GitSparkOptions { repoPath?: string; since?: string; until?: string; days?: number; branch?: string; author?: string; path?: string; format?: OutputFormat; output?: string; config?: string; heavy?: boolean; logLevel?: LogLevel; noCache?: boolean; compare?: string; watch?: boolean; /** Redact author emails in all outputs */ redactEmails?: boolean; } export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose'; export interface CommitData { hash: string; shortHash: string; author: string; authorEmail: string; date: Date; message: string; subject: string; body: string; insertions: number; deletions: number; filesChanged: number; isMerge: boolean; isCoAuthored: boolean; coAuthors: string[]; files: FileChange[]; } export interface FileChange { path: string; insertions: number; deletions: number; status: 'added' | 'modified' | 'deleted' | 'renamed' | 'copied'; oldPath?: string; } export interface AuthorStats { name: string; email: string; commits: number; insertions: number; deletions: number; churn: number; filesChanged: number; firstCommit: Date; lastCommit: Date; activeDays: number; avgCommitSize: number; largestCommit: number; workPatterns: WorkPattern; detailed: AuthorDetailedMetrics; } export interface WorkPattern { hourDistribution: number[]; dayDistribution: number[]; burstDays: number; afterHours: number; weekends: number; } export interface AuthorDetailedMetrics { contribution: AuthorContributionMetrics; collaboration: AuthorCollaborationMetrics; workPattern: AuthorWorkPatternMetrics; quality: AuthorQualityMetrics; comparative: AuthorComparativeMetrics; insights: AuthorInsights; } export interface AuthorContributionMetrics { totalCommits: number; commitFrequency: number; activeDaysCount: number; longestStreak: number; commitSizeDistribution: { micro: number; small: number; medium: number; large: number; veryLarge: number; }; largestCommitDetails: { size: number; hash: string; date: Date; message: string; filesCount: number; }; codeVolumeMetrics: { totalLinesChanged: number; netChange: number; churnTotal: number; avgCommitSize: number; }; filesAndScope: { uniqueFiles: number; avgFilesPerCommit: number; fileDiversityScore: number; mostModifiedFiles: Array<{ path: string; commits: number; percentage: number; }>; directoryFocus: Array<{ directory: string; percentage: number; }>; sourceVsPublishedRatio: { sourceCommits: number; sourceLines: { insertions: number; deletions: number; }; publishedCommits: number; publishedLines: { insertions: number; deletions: number; }; }; fileTypeBreakdown: FileTypeBreakdown; }; } export interface FileTypeBreakdown { /** File types by extension with activity metrics */ byExtension: Array<{ extension: string; language: string; commits: number; files: number; churn: number; percentage: number; }>; /** Summary categories */ categories: { sourceCode: { files: number; commits: number; churn: number; percentage: number; }; documentation: { files: number; commits: number; churn: number; percentage: number; }; configuration: { files: number; commits: number; churn: number; percentage: number; }; tests: { files: number; commits: number; churn: number; percentage: number; }; other: { files: number; commits: number; churn: number; percentage: number; }; }; /** Total activity for percentage calculations */ totals: { files: number; commits: number; churn: number; }; } export interface AuthorCollaborationMetrics { coAuthorshipRate: number; coAuthors: Array<{ name: string; count: number; }>; prIntegrationRate: number; prBreakdown: { mergeCommits: number; squashMerges: number; directCommits: number; }; fileOwnership: { exclusiveFiles: number; sharedFiles: number; highTrafficFiles: number; ownershipStyle: 'collaborative' | 'specialized' | 'balanced'; }; knowledgeSharingIndex: number; } export interface AuthorWorkPatternMetrics { commitTiming: { mostActiveDay: { day: string; percentage: number; }; mostActiveTime: { timeRange: string; percentage: number; }; workPattern: 'weekday-focused' | 'weekend-warrior' | 'distributed'; afterHoursRate: number; }; temporalPatterns: { burstDetection: Array<{ date: Date; commitCount: number; timeSpan: string; }>; longestGap: { days: number; startDate: Date; endDate: Date; }; averageGap: number; consistencyScore: number; velocityTrend: 'increasing' | 'stable' | 'decreasing'; }; workLifeBalance: { afterHoursPercentage: number; weekendPercentage: number; lateNightCommits: number; vacationBreaks: Array<{ startDate: Date; endDate: Date; days: number; }>; }; } export interface AuthorQualityMetrics { codeQuality: { revertRate: number; fixToFeatureRatio: number; wipCommitFrequency: number; refactoringActivity: { refactorCommits: number; linesRefactored: number; percentage: number; }; documentationContributions: { docCommits: number; docLinesChanged: number; percentage: number; }; }; riskAndOwnership: { highRiskFileContributions: number; ownershipDominance: number; hotspotInvolvement: number; legacyCodeInteraction: number; }; } export interface AuthorComparativeMetrics { teamContext: { relativeContribution: number; commitRank: number; linesChangedRank: number; filesRank: number; messageQualityRank: number; percentileRankings: { commits: number; linesChanged: number; filesTouched: number; messageQuality: number; }; }; specialization: { focusIndex: number; specializationLevel: 'highly-specialized' | 'moderate' | 'generalist'; }; growth: { periodOverPeriodGrowth: { commits: number; linesChanged: number; filesTouched: number; messageQuality: number; }; complexityTrajectory: { avgLinesPerCommitGrowth: number; avgFilesPerCommitGrowth: number; }; technologyBreadth: { languages: Array<{ language: string; commits: number; percentage: number; }>; diversityScore: number; trend: 'expanding' | 'stable' | 'narrowing'; }; }; } export interface AuthorInsights { positivePatterns: string[]; growthAreas: string[]; neutralObservations: string[]; concerningPatterns: string[]; automatedInsights: { workLifeBalance: 'healthy' | 'concerning' | 'excellent'; collaboration: 'highly-collaborative' | 'moderate' | 'isolated'; codeQuality: 'excellent' | 'good' | 'needs-improvement'; consistency: 'very-consistent' | 'consistent' | 'irregular'; expertise: 'senior' | 'mid-level' | 'junior' | 'specialist'; }; recommendations: string[]; } export interface FileStats { path: string; commits: number; authors: string[]; churn: number; insertions: number; deletions: number; firstChange: Date; lastChange: Date; riskScore: number; hotspotScore: number; ownership: { [author: string]: number; }; language?: string; size?: number; } export interface RepositoryStats { totalCommits: number; totalAuthors: number; totalFiles: number; totalChurn: number; firstCommit: Date; lastCommit: Date; activeDays: number; avgCommitsPerDay: number; languages: { [language: string]: number; }; busFactor: number; healthScore: number; governanceScore: number; } export interface CurrentRepositoryState { /** Total files currently in the repository */ totalFiles: number; /** Total size of all files in bytes */ totalSizeBytes: number; /** Breakdown by file extension with counts */ byExtension: Array<{ extension: string; language: string; fileCount: number; totalSizeBytes: number; percentage: number; averageFileSize: number; }>; /** Breakdown by file category */ categories: { sourceCode: { fileCount: number; totalSizeBytes: number; percentage: number; }; documentation: { fileCount: number; totalSizeBytes: number; percentage: number; }; configuration: { fileCount: number; totalSizeBytes: number; percentage: number; }; tests: { fileCount: number; totalSizeBytes: number; percentage: number; }; other: { fileCount: number; totalSizeBytes: number; percentage: number; }; }; /** Top directories by file count */ topDirectories: Array<{ path: string; fileCount: number; percentage: number; }>; /** Analysis timestamp */ analyzedAt: Date; } export interface AnalysisReport { metadata: ReportMetadata; repository: RepositoryStats; /** Current state of files in the repository (filesystem-based, not Git history) */ currentState: CurrentRepositoryState; timeline: TimelineData[]; authors: AuthorStats[]; files: FileStats[]; hotspots: FileStats[]; risks: RiskAnalysis; governance: GovernanceAnalysis; teamScore: TeamScore; summary: ReportSummary; /** Daily trending metrics for comprehensive trend analysis */ dailyTrends?: DailyTrendsData | undefined; } export interface ReportMetadata { generatedAt: Date; version: string; repoPath: string; analysisOptions: GitSparkOptions; processingTime: number; gitVersion: string; commit: string; branch: string; /** CLI arguments used to generate this report */ cliArguments?: string[]; /** Non-fatal issues encountered during analysis */ warnings?: string[]; /** Derived configuration snapshot (after resolution/merge) */ resolvedConfig?: Partial<GitSparkConfig>; } export interface TimelineData { date: Date; commits: number; authors: number; churn: number; files: number; } export interface RiskAnalysis { highRiskFiles: FileStats[]; riskFactors: { [factor: string]: number; }; recommendations: string[]; overallRisk: 'low' | 'medium' | 'high'; } export interface GovernanceAnalysis { conventionalCommits: number; traceabilityScore: number; avgMessageLength: number; wipCommits: number; revertCommits: number; shortMessages: number; score: number; recommendations: string[]; } export interface TeamScore { overall: number; collaboration: TeamCollaborationMetrics; consistency: TeamConsistencyMetrics; workLifeBalance: TeamWorkLifeBalanceMetrics; insights: TeamInsights; recommendations: string[]; } export interface TeamCollaborationMetrics { score: number; crossTeamInteraction: number; knowledgeDistribution: number; fileOwnershipDistribution: { exclusive: number; shared: number; collaborative: number; }; limitations: { dataSource: 'git-file-authorship-only'; knownLimitations: string[]; }; } export interface TeamConsistencyMetrics { score: number; velocityConsistency: number; busFactorPercentage: number; activeContributorRatio: number; deliveryCadence: number; contributionDistribution: { giniCoefficient: number; topContributorDominance: number; }; } export interface TeamQualityMetrics { score: number; refactoringActivity: number; bugFixRatio: number; documentationContribution: number; testFileDetection: { hasTestFiles: boolean; testFiles: number; testFileToSourceRatio: number; limitations: { note: string; recommendedTools: string[]; }; }; limitations: { qualityMeasurement: 'commit-message-pattern-analysis'; testCoverageNote: 'File detection only, not execution coverage'; knownLimitations: string[]; }; } export interface TeamWorkLifeBalanceMetrics { score: number; commitTimePatterns: number; afterHoursCommitFrequency: number; weekendCommitActivity: number; commitTimingIndicators: { highVelocityDays: number; consecutiveCommitDays: number; afterHoursCommits: number; }; teamActiveCoverage: { multiContributorDays: number; soloContributorDays: number; coveragePercentage: number; note: string; }; limitations: { timezoneWarning: string; workPatternNote: string; burnoutDetection: string; recommendedApproach: string; knownLimitations: string[]; }; } export interface TeamFileTypeMetrics { /** Team-wide file type breakdown across all contributors */ teamFileTypeBreakdown: FileTypeBreakdown; /** Individual contributor file type specializations */ authorSpecializations: Array<{ authorName: string; authorEmail: string; primaryFileTypes: Array<{ extension: string; language: string; percentage: number; commits: number; }>; specializationScore: number; }>; /** Cross-pollination metrics */ crossPollinationMetrics: { generalMultiLanguageAuthors: number; languageSpecialists: number; averageLanguagesPerAuthor: number; }; } export interface TeamInsights { strengths: string[]; improvements: string[]; risks: string[]; teamDynamics: 'highly-collaborative' | 'balanced' | 'siloed' | 'fragmented'; maturityLevel: 'nascent' | 'developing' | 'mature' | 'optimized'; sustainabilityRating: 'excellent' | 'good' | 'concerning' | 'critical'; } /** * Daily trending metrics computed exclusively from Git commit data * * All metrics are objective, observable patterns derived from Git history. * No speculation about team performance, code quality, or individual productivity. */ /** * GitHub-style contributions graph data */ export interface ContributionGraphData { /** Calendar data by date */ calendar: ContributionDay[]; /** Maximum commits in a single day (for scaling colors) */ maxCommits: number; /** Total commits in the period */ totalCommits: number; /** Weeks structure for display */ weeks: ContributionWeek[]; } export interface ContributionDay { /** Date in YYYY-MM-DD format */ date: string; /** Number of commits on this day */ count: number; /** Intensity level (0-4) for color coding */ intensity: number; /** ISO day of week (1=Monday, 7=Sunday) */ dayOfWeek: number; } export interface ContributionWeek { /** Week number in the year */ weekNumber: number; /** Days in this week */ days: ContributionDay[]; } export interface DailyTrendsData { /** Metadata about the trend analysis */ analysisMetadata: DailyTrendsMetadata; /** Daily flow and throughput metrics */ flowMetrics: DailyFlowMetrics[]; /** Daily stability and risk indicators */ stabilityMetrics: DailyStabilityMetrics[]; /** Daily ownership and knowledge distribution */ ownershipMetrics: DailyOwnershipMetrics[]; /** Daily architectural coupling indicators */ couplingMetrics: DailyCouplingMetrics[]; /** Daily hygiene and documentation patterns */ hygieneMetrics: DailyHygieneMetrics[]; /** GitHub-style contributions graph data */ contributionsGraph: ContributionGraphData; /** Analysis limitations and warnings */ limitations: DailyTrendsLimitations; } export interface DailyTrendsMetadata { /** Time zone used for day grouping (e.g., 'America/Chicago') */ timezone: string; /** Analysis start date */ startDate: Date; /** Analysis end date */ endDate: Date; /** Total days analyzed */ totalDays: number; /** Days with commit activity */ activeDays: number; /** Working hours used for out-of-hours calculation */ workingHours: { start: number; end: number; weekdays: boolean; }; } export interface DailyFlowMetrics { /** Date (local timezone) */ date: Date; /** Calendar day (YYYY-MM-DD) */ day: string; /** Commits authored that day */ commitsPerDay: number; /** Unique authors that day */ uniqueAuthorsPerDay: number; /** Total lines changed (insertions + deletions) */ grossLinesChangedPerDay: number; /** Lines inserted */ insertionsPerDay: number; /** Lines deleted */ deletionsPerDay: number; /** Unique files touched */ filesTouchedPerDay: number; /** Commit size distribution percentiles */ commitSizeDistribution: { p50: number; p90: number; }; } export interface DailyStabilityMetrics { /** Date (local timezone) */ date: Date; /** Calendar day (YYYY-MM-DD) */ day: string; /** Commits with 'revert' in message */ revertsPerDay: number; /** Ratio of merge commits to total commits */ mergeRatioPerDay: number; /** Files changed today that were also changed in last K days */ retouchRate: number; /** File renames/moves detected */ renamesPerDay: number; /** Percentage of commits outside working hours */ outOfHoursShare: number; } export interface DailyOwnershipMetrics { /** Date (local timezone) */ date: Date; /** Calendar day (YYYY-MM-DD) */ day: string; /** New files created (first appearance in history) */ newFilesCreatedPerDay: number; /** Files touched today with only 1 author in trailing 90 days */ singleOwnerFilesTouched: number; /** Total files touched today */ filesTouchedToday: number; /** Percentage of single-owner files among today's changes */ singleOwnerShare: number; /** Average authors per file (trailing 90-day window) */ avgAuthorsPerFile: number; } export interface DailyCouplingMetrics { /** Date (local timezone) */ date: Date; /** Calendar day (YYYY-MM-DD) */ day: string; /** Average number of file pairs co-changed per commit */ coChangeDensityPerDay: number; /** Total file pairs co-changed */ totalCoChangePairs: number; /** Commits with multiple file changes */ multiFileCommits: number; } export interface DailyHygieneMetrics { /** Date (local timezone) */ date: Date; /** Calendar day (YYYY-MM-DD) */ day: string; /** Median commit message length (characters) */ medianCommitMessageLength: number; /** Commits with messages shorter than threshold */ shortMessages: number; /** Commits with conventional commit format */ conventionalCommits: number; } export interface DailyTrendsLimitations { /** Data source description */ dataSource: 'git-commit-history-only'; /** Timezone handling warnings */ timezoneWarnings: string[]; /** Calculation method explanations */ calculationMethods: Record<string, string>; /** Known limitations of Git-only analysis */ knownLimitations: string[]; /** Recommended complementary tools/approaches */ recommendedSupplementalData: string[]; } export interface ReportSummary { healthRating: 'excellent' | 'good' | 'fair' | 'poor'; keyMetrics: { [metric: string]: string | number; }; insights: string[]; actionItems: string[]; } export interface ComparisonReport { base: AnalysisReport; compare: AnalysisReport; differences: ComparisonDifferences; } export interface ComparisonDifferences { commits: { added: number; removed: number; net: number; }; authors: { added: string[]; removed: string[]; common: string[]; }; files: { added: string[]; removed: string[]; modified: string[]; }; metrics: { [key: string]: { base: number; compare: number; change: number; changePercent: number; }; }; } export interface ProgressCallback { (phase: string, progress: number, total: number): void; } export interface CacheEntry { key: string; data: any; timestamp: number; ttl: number; } export interface GitCommand { command: string; args: string[]; options?: { cwd?: string; maxBuffer?: number; timeout?: number; }; } export interface ValidationResult { isValid: boolean; errors: string[]; warnings: string[]; } export declare class GitSparkError extends Error { code?: string | undefined; cause?: Error | undefined; constructor(message: string, code?: string | undefined, cause?: Error | undefined); } export declare class ValidationError extends GitSparkError { field?: string | undefined; constructor(message: string, field?: string | undefined); } export declare class GitError extends GitSparkError { gitCommand?: string | undefined; constructor(message: string, gitCommand?: string | undefined); } export declare class PerformanceError extends GitSparkError { constructor(message: string); } //# sourceMappingURL=index.d.ts.map