Skip to content

Commit 2eeefb9

Browse files
author
Test
committed
fix: include cmd/git-stats entrypoint and correct .gitignore
The git-stats binary pattern was ignoring cmd/git-stats/, breaking CI and GoReleaser builds on GitHub Actions.
1 parent 1feac7a commit 2eeefb9

3 files changed

Lines changed: 144 additions & 4 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Binaries
2-
git-stats
1+
# Binaries (root only — do not ignore cmd/git-stats/)
2+
/git-stats
33
/bin/
44
/dist/
55

‎.goreleaser.yaml‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,3 @@ release:
5151
draft: false
5252
prerelease: auto
5353

54-
snapshot:
55-
name_template: "{{ incpatch .Version }}-next"

‎cmd/git-stats/main.go‎

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"runtime"
7+
"time"
8+
9+
"github.com/loSpaccaBit/git-stats-cli/internal/analyzer"
10+
"github.com/loSpaccaBit/git-stats-cli/internal/formatter"
11+
"github.com/loSpaccaBit/git-stats-cli/internal/report"
12+
"github.com/loSpaccaBit/git-stats-cli/internal/version"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
var (
17+
noColor bool
18+
topAuthors int
19+
churn bool
20+
noChurn bool
21+
months int
22+
workers int
23+
verbose bool
24+
)
25+
26+
func main() {
27+
if err := newRootCmd().Execute(); err != nil {
28+
fmt.Fprintln(os.Stderr, err)
29+
os.Exit(1)
30+
}
31+
}
32+
33+
func newRootCmd() *cobra.Command {
34+
root := &cobra.Command{
35+
Use: "git-stats",
36+
Short: "Analyze Git repositories and generate insightful reports",
37+
Long: `git-stats reads repository history with go-git and produces production-grade statistics.
38+
39+
Performance:
40+
By default churn (line diff stats) is OFF for fast analysis on large repos.
41+
Use --churn to enable it. Parallel workers are used automatically.
42+
43+
Features:
44+
- All locally available commits (every branch/tag object in the repo)
45+
- GitHub Linguist language detection via go-enry
46+
- Author rankings, activity windows, monthly trends, and optional code churn
47+
- JSON, Markdown, and HTML export`,
48+
Version: version.Version,
49+
}
50+
51+
root.PersistentFlags().BoolVar(&noColor, "no-color", false, "disable colored terminal output")
52+
root.PersistentFlags().IntVar(&topAuthors, "top", 10, "number of top authors to display")
53+
root.PersistentFlags().BoolVar(&churn, "churn", false, "compute line churn stats (slower on large repos)")
54+
root.PersistentFlags().BoolVar(&noChurn, "no-churn", false, "skip line churn (deprecated: churn is off by default)")
55+
root.PersistentFlags().IntVar(&months, "months", 12, "number of monthly activity buckets to include")
56+
root.PersistentFlags().IntVar(&workers, "workers", runtime.GOMAXPROCS(0), "parallel workers for churn analysis")
57+
root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "print analysis duration to stderr")
58+
59+
root.AddCommand(newAnalyzeCmd())
60+
root.AddCommand(newReportCmd())
61+
62+
return root
63+
}
64+
65+
func analysisOptions() analyzer.Options {
66+
opts := analyzer.DefaultOptions()
67+
opts.TopAuthors = topAuthors
68+
opts.MonthlyBuckets = months
69+
opts.IncludeChurn = churn && !noChurn
70+
opts.Workers = workers
71+
return opts
72+
}
73+
74+
func newAnalyzeCmd() *cobra.Command {
75+
return &cobra.Command{
76+
Use: "analyze [path]",
77+
Short: "Analyze a local Git repository",
78+
Args: cobra.MaximumNArgs(1),
79+
RunE: func(cmd *cobra.Command, args []string) error {
80+
path := "."
81+
if len(args) > 0 {
82+
path = args[0]
83+
}
84+
85+
start := time.Now()
86+
data, err := analyzer.AnalyzeWithOptions(path, analysisOptions())
87+
if err != nil {
88+
return err
89+
}
90+
if verbose {
91+
fmt.Fprintf(os.Stderr, "analysis completed in %s\n", time.Since(start).Round(time.Millisecond))
92+
}
93+
return formatter.PrintTerminal(data, noColor)
94+
},
95+
}
96+
}
97+
98+
func newReportCmd() *cobra.Command {
99+
var format string
100+
var output string
101+
102+
cmd := &cobra.Command{
103+
Use: "report [path]",
104+
Short: "Generate a JSON, Markdown, or HTML report",
105+
Args: cobra.MaximumNArgs(1),
106+
RunE: func(cmd *cobra.Command, args []string) error {
107+
path := "."
108+
if len(args) > 0 {
109+
path = args[0]
110+
}
111+
112+
parsed, err := report.ParseFormat(format)
113+
if err != nil {
114+
return err
115+
}
116+
117+
start := time.Now()
118+
data, err := analyzer.AnalyzeWithOptions(path, analysisOptions())
119+
if err != nil {
120+
return err
121+
}
122+
if verbose {
123+
fmt.Fprintf(os.Stderr, "analysis completed in %s\n", time.Since(start).Round(time.Millisecond))
124+
}
125+
126+
if output != "" && output != "-" {
127+
if writeErr := report.WriteOutput(output, parsed, data); writeErr != nil {
128+
return writeErr
129+
}
130+
fmt.Fprintf(os.Stderr, "Report written to %s (%s)\n", output, formatter.FormatSummary(data))
131+
return nil
132+
}
133+
134+
return report.PrintOutput(parsed, data)
135+
},
136+
}
137+
138+
cmd.Flags().StringVarP(&format, "format", "f", "json", "output format: json, md, html")
139+
cmd.Flags().StringVarP(&output, "output", "o", "", "output file path (stdout if empty or '-')")
140+
141+
return cmd
142+
}

0 commit comments

Comments
 (0)