Skip to content

Commit d230b2c

Browse files
committed
feat: Add language exclusion feature to profile stats analysis and update related tests
1 parent f195e89 commit d230b2c

File tree

5 files changed

+232
-25
lines changed

5 files changed

+232
-25
lines changed

GitInsights

33.2 KB
Binary file not shown.

README.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,13 @@ export GITHUB_TOKEN=$(gh auth token)
159159
</div>
160160

161161
```text
162-
🌙 Monday ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░ 116 commits
163-
🔥 Tuesday ██████████████████████████████ 201 commits
164-
💎 Wednesday ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░ 142 commits
162+
🌙 Monday ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░ 112 commits
163+
🔥 Tuesday ████████████████████████████░░ 188 commits
164+
💎 Wednesday ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░ 130 commits
165165
💚 Thursday ██████████████████████████████ 201 commits
166-
🎉 Friday ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░ 116 commits
166+
🎉 Friday ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░ 111 commits
167167
🌟 Saturday ▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░ 80 commits
168-
☀️ Sunday ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 45 commits
168+
☀️ Sunday ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 41 commits
169169
```
170170

171171
<div align="center">
@@ -176,25 +176,25 @@ export GITHUB_TOKEN=$(gh auth token)
176176

177177
<div align="center">
178178

179-
![JavaScript](https://img.shields.io/badge/JavaScript-87.6%25-blue?style=flat-square&logo=javascript) ![TypeScript](https://img.shields.io/badge/TypeScript-5.1%25-blue?style=flat-square&logo=typescript) ![SCSS](https://img.shields.io/badge/SCSS-2.0%25-blue?style=flat-square&logo=sass) ![Go](https://img.shields.io/badge/Go-1.7%25-blue?style=flat-square&logo=go) ![HTML](https://img.shields.io/badge/HTML-1.2%25-blue?style=flat-square&logo=html5)
179+
![TypeScript](https://img.shields.io/badge/TypeScript-44.1%25-blue?style=flat-square&logo=typescript) ![JavaScript](https://img.shields.io/badge/JavaScript-27.2%25-blue?style=flat-square&logo=javascript) ![Go](https://img.shields.io/badge/Go-15.1%25-blue?style=flat-square&logo=go) ![Elixir](https://img.shields.io/badge/Elixir-5.9%25-blue?style=flat-square&logo=elixir) ![Ruby](https://img.shields.io/badge/Ruby-3.3%25-blue?style=flat-square&logo=ruby)
180180

181181
</div>
182182

183183
<details>
184184
<summary><b>📊 Detailed Breakdown</b></summary>
185185

186186
```text
187-
🟨 JavaScript ███████████████████████████████████░░░░░ 87.64%
188-
🔷 TypeScript ▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 5.10%
189-
🎨 SCSS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1.96%
190-
🔵 Go ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1.65%
191-
🌐 HTML ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1.24%
192-
💎 Ruby ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.82%
193-
💧 Elixir ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.68%
194-
🎨 CSS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.37%
195-
🐍 Python ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.35%
196-
🟢 Vim Script ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.10%
197-
💻 Other ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.07%
187+
🔷 TypeScript ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░ 44.07%
188+
🟨 JavaScript ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 27.15%
189+
🔵 Go ▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 15.14%
190+
💧 Elixir ▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 5.91%
191+
💎 Ruby ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 3.25%
192+
🐍 Python ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2.99%
193+
🟢 Vim Script ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.91%
194+
🐚 Shell ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.26%
195+
💻 Makefile ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.21%
196+
💻 Dockerfile ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.07%
197+
💻 Other ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0.03%
198198
```
199199

200200
</details>
@@ -203,7 +203,7 @@ export GITHUB_TOKEN=$(gh auth token)
203203

204204
<div align="center">
205205

206-
<sub>📅 Last updated: Thursday, October 30, 2025 at 9:28 AM</sub>
206+
<sub>📅 Last updated: Thursday, October 30, 2025 at 10:14 AM</sub>
207207

208208
<sub>⚡ Generated with [GitInsights](https://github.com/awcodify/GitInsights)</sub>
209209

main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func main() {
1616
includeForks := flag.Bool("include-forks", false, "Include forked repositories in analysis")
1717
maxVisibleLanguages := flag.Int("max-visible-language", 10, "Maximum number of languages to display (rest grouped as 'Other')")
1818
showCredit := flag.Bool("show-credit", true, "Show GitInsight credit in the generated output")
19+
excludeLanguages := flag.String("exclude-languages", "", "Comma-separated list of languages to exclude (e.g., 'scss,html')")
1920
flag.Parse()
2021

2122
// Get GitHub token from environment
@@ -30,7 +31,7 @@ func main() {
3031
fileManager := infrastructure.NewFileManager("README.md")
3132

3233
// Initialize use case
33-
profileUseCase := usecase.NewProfileStatsUseCase(githubClient, *maxVisibleLanguages)
34+
profileUseCase := usecase.NewProfileStatsUseCase(githubClient, *maxVisibleLanguages, *excludeLanguages)
3435

3536
// Initialize presentation layer
3637
markdownGen := presentation.NewMarkdownGenerator(*showCredit)

usecase/profile_stats.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"sort"
7+
"strings"
78
"time"
89

910
"GitInsights/domain"
@@ -13,13 +14,26 @@ import (
1314
type ProfileStatsUseCase struct {
1415
githubRepo domain.GitHubRepository
1516
maxVisibleLanguages int
17+
excludeLanguages []string
1618
}
1719

1820
// NewProfileStatsUseCase creates a new instance
19-
func NewProfileStatsUseCase(githubRepo domain.GitHubRepository, maxVisibleLanguages int) *ProfileStatsUseCase {
21+
func NewProfileStatsUseCase(githubRepo domain.GitHubRepository, maxVisibleLanguages int, excludeLanguagesStr string) *ProfileStatsUseCase {
22+
var excludeLanguages []string
23+
if excludeLanguagesStr != "" {
24+
// Split by comma and trim spaces, convert to lowercase for case-insensitive matching
25+
langs := strings.Split(excludeLanguagesStr, ",")
26+
for _, lang := range langs {
27+
trimmed := strings.TrimSpace(lang)
28+
if trimmed != "" {
29+
excludeLanguages = append(excludeLanguages, strings.ToLower(trimmed))
30+
}
31+
}
32+
}
2033
return &ProfileStatsUseCase{
2134
githubRepo: githubRepo,
2235
maxVisibleLanguages: maxVisibleLanguages,
36+
excludeLanguages: excludeLanguages,
2337
}
2438
}
2539

@@ -93,14 +107,37 @@ func (uc *ProfileStatsUseCase) processLanguages(languageMap map[string]int, tota
93107

94108
maxVisibleLanguages := uc.maxVisibleLanguages
95109

110+
// Filter out excluded languages and recalculate total bytes
111+
filteredLanguageMap := make(map[string]int)
112+
filteredTotalBytes := 0
113+
for lang, bytes := range languageMap {
114+
// Check if language should be excluded (case-insensitive)
115+
excluded := false
116+
for _, excludedLang := range uc.excludeLanguages {
117+
if strings.ToLower(lang) == excludedLang {
118+
excluded = true
119+
break
120+
}
121+
}
122+
if !excluded {
123+
filteredLanguageMap[lang] = bytes
124+
filteredTotalBytes += bytes
125+
}
126+
}
127+
128+
// If all languages are excluded, return empty
129+
if filteredTotalBytes == 0 {
130+
return []domain.LanguageStats{}
131+
}
132+
96133
// Sort languages by bytes
97134
type langPair struct {
98135
name string
99136
bytes int
100137
}
101138

102139
var pairs []langPair
103-
for lang, bytes := range languageMap {
140+
for lang, bytes := range filteredLanguageMap {
104141
pairs = append(pairs, langPair{lang, bytes})
105142
}
106143

@@ -112,7 +149,7 @@ func (uc *ProfileStatsUseCase) processLanguages(languageMap map[string]int, tota
112149
if len(pairs) <= maxVisibleLanguages {
113150
var result []domain.LanguageStats
114151
for _, pair := range pairs {
115-
percentage := float64(pair.bytes) / float64(totalBytes) * 100
152+
percentage := float64(pair.bytes) / float64(filteredTotalBytes) * 100
116153
result = append(result, domain.LanguageStats{
117154
Language: pair.name,
118155
Bytes: pair.bytes,
@@ -127,7 +164,7 @@ func (uc *ProfileStatsUseCase) processLanguages(languageMap map[string]int, tota
127164
otherBytes := 0
128165

129166
for i, pair := range pairs {
130-
percentage := float64(pair.bytes) / float64(totalBytes) * 100
167+
percentage := float64(pair.bytes) / float64(filteredTotalBytes) * 100
131168
if i < maxVisibleLanguages {
132169
result = append(result, domain.LanguageStats{
133170
Language: pair.name,
@@ -144,7 +181,7 @@ func (uc *ProfileStatsUseCase) processLanguages(languageMap map[string]int, tota
144181
result = append(result, domain.LanguageStats{
145182
Language: "Other",
146183
Bytes: otherBytes,
147-
Percentage: float64(otherBytes) / float64(totalBytes) * 100,
184+
Percentage: float64(otherBytes) / float64(filteredTotalBytes) * 100,
148185
})
149186
}
150187

usecase/profile_stats_test.go

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func TestGetProfileStats(t *testing.T) {
5151
},
5252
}
5353

54-
uc := usecase.NewProfileStatsUseCase(mockRepo, 10)
54+
uc := usecase.NewProfileStatsUseCase(mockRepo, 10, "")
5555
stats, err := uc.GetProfileStats(context.Background())
5656

5757
if err != nil {
@@ -66,3 +66,172 @@ func TestGetProfileStats(t *testing.T) {
6666
t.Errorf("Expected total bytes 1500, got: %d", stats.TotalBytes)
6767
}
6868
}
69+
70+
func TestExcludeLanguages(t *testing.T) {
71+
mockRepo := &MockGitHubRepository{
72+
Username: "testuser",
73+
UserProfile: &domain.UserProfile{
74+
Username: "testuser",
75+
CreatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
76+
},
77+
LanguageStats: map[string]int{
78+
"Go": 1000,
79+
"Java": 500,
80+
"SCSS": 300,
81+
"HTML": 200,
82+
"CSS": 100,
83+
},
84+
Commits: []domain.Commit{
85+
{Date: time.Date(2023, 11, 12, 10, 0, 0, 0, time.UTC)},
86+
},
87+
}
88+
89+
// Test excluding SCSS and HTML (case-insensitive)
90+
uc := usecase.NewProfileStatsUseCase(mockRepo, 10, "scss,html")
91+
stats, err := uc.GetProfileStats(context.Background())
92+
93+
if err != nil {
94+
t.Fatalf("Expected no error, got: %v", err)
95+
}
96+
97+
// Check that SCSS and HTML are not in the languages list
98+
for _, lang := range stats.Languages {
99+
if lang.Language == "SCSS" || lang.Language == "HTML" {
100+
t.Errorf("Expected %s to be excluded, but it's in the results", lang.Language)
101+
}
102+
}
103+
104+
// Check that other languages are present
105+
expectedLanguages := map[string]bool{"Go": false, "Java": false, "CSS": false}
106+
for _, lang := range stats.Languages {
107+
if _, ok := expectedLanguages[lang.Language]; ok {
108+
expectedLanguages[lang.Language] = true
109+
}
110+
}
111+
112+
for lang, found := range expectedLanguages {
113+
if !found {
114+
t.Errorf("Expected %s to be in the results, but it's missing", lang)
115+
}
116+
}
117+
118+
// Total bytes should be 1600 (1000 + 500 + 100), excluding SCSS (300) and HTML (200)
119+
if stats.TotalBytes != 2100 {
120+
t.Errorf("Expected total bytes 2100 (original total), got: %d", stats.TotalBytes)
121+
}
122+
123+
// Check that percentages add up to ~100%
124+
totalPercentage := 0.0
125+
for _, lang := range stats.Languages {
126+
totalPercentage += lang.Percentage
127+
}
128+
if totalPercentage < 99.9 || totalPercentage > 100.1 {
129+
t.Errorf("Expected total percentage to be ~100%%, got: %.2f%%", totalPercentage)
130+
}
131+
}
132+
133+
func TestExcludeLanguagesCaseInsensitive(t *testing.T) {
134+
mockRepo := &MockGitHubRepository{
135+
Username: "testuser",
136+
UserProfile: &domain.UserProfile{
137+
Username: "testuser",
138+
CreatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
139+
},
140+
LanguageStats: map[string]int{
141+
"Go": 1000,
142+
"SCSS": 500,
143+
},
144+
Commits: []domain.Commit{
145+
{Date: time.Date(2023, 11, 12, 10, 0, 0, 0, time.UTC)},
146+
},
147+
}
148+
149+
// Test case-insensitive matching (lowercase input, uppercase language)
150+
uc := usecase.NewProfileStatsUseCase(mockRepo, 10, "scss")
151+
stats, err := uc.GetProfileStats(context.Background())
152+
153+
if err != nil {
154+
t.Fatalf("Expected no error, got: %v", err)
155+
}
156+
157+
// SCSS should be excluded
158+
for _, lang := range stats.Languages {
159+
if lang.Language == "SCSS" {
160+
t.Errorf("Expected SCSS to be excluded (case-insensitive), but it's in the results")
161+
}
162+
}
163+
164+
// Only Go should remain
165+
if len(stats.Languages) != 1 {
166+
t.Errorf("Expected 1 language, got: %d", len(stats.Languages))
167+
}
168+
169+
if stats.Languages[0].Language != "Go" {
170+
t.Errorf("Expected Go to be the only language, got: %s", stats.Languages[0].Language)
171+
}
172+
}
173+
174+
func TestExcludeLanguagesWithSpaces(t *testing.T) {
175+
mockRepo := &MockGitHubRepository{
176+
Username: "testuser",
177+
UserProfile: &domain.UserProfile{
178+
Username: "testuser",
179+
CreatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
180+
},
181+
LanguageStats: map[string]int{
182+
"Go": 1000,
183+
"Java": 500,
184+
"HTML": 200,
185+
},
186+
Commits: []domain.Commit{
187+
{Date: time.Date(2023, 11, 12, 10, 0, 0, 0, time.UTC)},
188+
},
189+
}
190+
191+
// Test with spaces around commas
192+
uc := usecase.NewProfileStatsUseCase(mockRepo, 10, "html , java ")
193+
stats, err := uc.GetProfileStats(context.Background())
194+
195+
if err != nil {
196+
t.Fatalf("Expected no error, got: %v", err)
197+
}
198+
199+
// Only Go should remain
200+
if len(stats.Languages) != 1 {
201+
t.Errorf("Expected 1 language, got: %d", len(stats.Languages))
202+
}
203+
204+
if stats.Languages[0].Language != "Go" {
205+
t.Errorf("Expected Go to be the only language, got: %s", stats.Languages[0].Language)
206+
}
207+
}
208+
209+
func TestNoExcludeLanguages(t *testing.T) {
210+
mockRepo := &MockGitHubRepository{
211+
Username: "testuser",
212+
UserProfile: &domain.UserProfile{
213+
Username: "testuser",
214+
CreatedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
215+
},
216+
LanguageStats: map[string]int{
217+
"Go": 1000,
218+
"Java": 500,
219+
},
220+
Commits: []domain.Commit{
221+
{Date: time.Date(2023, 11, 12, 10, 0, 0, 0, time.UTC)},
222+
},
223+
}
224+
225+
// Test with empty exclude string
226+
uc := usecase.NewProfileStatsUseCase(mockRepo, 10, "")
227+
stats, err := uc.GetProfileStats(context.Background())
228+
229+
if err != nil {
230+
t.Fatalf("Expected no error, got: %v", err)
231+
}
232+
233+
// All languages should be present
234+
if len(stats.Languages) != 2 {
235+
t.Errorf("Expected 2 languages, got: %d", len(stats.Languages))
236+
}
237+
}

0 commit comments

Comments
 (0)