Skip to content

Commit 959c686

Browse files
authored
Merge pull request #24 from andev0x/optimization/func
feat(config, analyzer): add configurable analysis engine
2 parents 3aeafcb + da2c11b commit 959c686

9 files changed

Lines changed: 1846 additions & 257 deletions

File tree

README.md

Lines changed: 137 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ A lightweight CLI tool that analyzes your staged changes and generates professio
1414

1515
- **Intelligent Analysis** - Analyzes git status and diff to understand your changes using advanced pattern detection
1616
- **Conventional Commits** - Follows the Conventional Commits specification for standardized messages
17+
- **Configuration Hierarchy** - Local (`.gitmit.json`) → Global (`~/.gitmit.json`) → Default (Embedded) config support
18+
- **Automatic Project Profiling** - Detects project type (Go, Node.js, Python, Java, etc.) from characteristic files
19+
- **Keyword Scoring Algorithm** - Analyzes git diff content and scores keywords to determine the best commit type
20+
- **Symbol Extraction** - Uses language-aware regex to extract function, class, and variable names
21+
- **Git Porcelain Status** - Leverages `git status --porcelain` for accurate file state detection
22+
- **Diff Stat Analysis** - Infers intent based on added vs deleted lines ratio
23+
- **Commit History Context** - Maintains consistency by learning from recent commit messages
1724
- **Interactive Mode** - Enhanced interactive prompts with y/n/e/r options (yes/no/edit/regenerate)
1825
- **Smart Regeneration** - Generate alternative commit messages with diverse suggestions
1926
- **Context-Aware Scoring** - Weighted algorithm for intelligent template selection
@@ -131,6 +138,24 @@ gitmit --debug
131138

132139
### Subcommands
133140

141+
#### Initialize Configuration
142+
143+
```bash
144+
# Create local .gitmit.json in current directory
145+
gitmit init
146+
147+
# Create global ~/.gitmit.json in home directory
148+
gitmit init --global
149+
```
150+
151+
The `init` command automatically detects your project type and generates a configuration file with:
152+
- Language-specific keyword mappings
153+
- Project-appropriate topic mappings
154+
- Customizable keyword scoring weights
155+
- Diff stat analysis thresholds
156+
157+
See [CONFIGURATION.md](CONFIGURATION.md) for detailed configuration options.
158+
134159
#### Propose (Default Command)
135160

136161
```bash
@@ -147,7 +172,46 @@ If no subcommand is provided, `gitmit` defaults to `propose`.
147172

148173
Gitmit uses intelligent offline algorithms to analyze your changes:
149174

150-
1. **Pattern Detection** - Identifies code patterns like:
175+
1. **Automatic Project Profiling** - Detects project type by checking for:
176+
- `go.mod` (Go)
177+
- `package.json` (Node.js)
178+
- `requirements.txt` (Python)
179+
- And more (Java, Ruby, Rust, PHP)
180+
181+
2. **Git Porcelain Status** - Uses `git status --porcelain` to read file states:
182+
- A (Added) → prioritizes `feat` templates
183+
- M (Modified) → analyzes for `fix`, `refactor`, or `feat`
184+
- D (Deleted) → suggests `chore` or `refactor`
185+
- R (Renamed) → suggests `refactor`
186+
187+
3. **Keyword Scoring Algorithm** - Analyzes `git diff --cached` content:
188+
- Counts keyword occurrences
189+
- Multiplies by configured weights
190+
- Selects action with highest score
191+
- Example: `+ func` (weight: 3) + `+ class` (weight: 2) = 5 points for `feat`
192+
193+
4. **Symbol Extraction via Regex** - Language-aware pattern matching:
194+
- Go: Functions (`func Name(`), structs (`type Name struct`)
195+
- JavaScript: Functions, arrow functions, classes
196+
- Python: Functions (`def name(`), classes (`class Name`)
197+
- Fills `{item}` placeholder automatically
198+
199+
5. **Path-based Topic Detection** - Uses `filepath.Dir` logic:
200+
- Custom topic mappings from config
201+
- Prioritizes `internal/` or `pkg/` subdirectories
202+
- Falls back to most specific directory name
203+
204+
6. **Diff Stat Analysis** - Analyzes line change ratios:
205+
- Deleted lines > 70% → suggests `refactor` (cleanup)
206+
- Added lines > 70% with 50+ lines → suggests `feat` (new feature)
207+
- Balanced changes → suggests `refactor` (modification)
208+
209+
7. **Commit History Context** - Maintains consistency:
210+
- Retrieves most recent commit message
211+
- Extracts scope from `type(scope): message` format
212+
- Prioritizes same scope for next commit
213+
214+
8. **Pattern Detection** - Identifies code patterns like:
151215
- Error handling improvements
152216
- Test additions
153217
- API/endpoint changes
@@ -157,25 +221,19 @@ Gitmit uses intelligent offline algorithms to analyze your changes:
157221
- Configuration updates
158222
- And 15+ other patterns
159223

160-
2. **Context Analysis** - Examines:
224+
9. **Context Analysis** - Examines:
161225
- File types and extensions
162226
- Directory structure
163227
- Function/struct/method changes
164228
- Line additions and deletions
165229
- Multi-file patterns
166230

167-
3. **Weighted Scoring** - Selects templates using:
168-
- Placeholder availability (item, purpose, topic)
169-
- Pattern matching bonuses
170-
- File type context
171-
- Special case detection
172-
- Diversity algorithms for variations
173-
174-
4. **Smart Variation** - When regenerating (pressing 'r'):
175-
- Avoids previously shown suggestions
176-
- Uses similarity detection to ensure diversity
177-
- Maintains context relevance
178-
- Applies randomization for variety
231+
10. **Weighted Scoring** - Selects templates using:
232+
- Placeholder availability (item, purpose, topic)
233+
- Pattern matching bonuses
234+
- File type context
235+
- Special case detection
236+
- Diversity algorithms for variations
179237

180238
## Commit Types
181239

@@ -289,13 +347,77 @@ Choice [y/n/e/r]: y
289347

290348
## Configuration
291349

292-
Gitmit works out of the box without any configuration. All intelligence is built-in using:
350+
Gitmit works out of the box without any configuration, but you can customize its behavior using a configuration file.
351+
352+
### Configuration Hierarchy
353+
354+
1. **Local** (`.gitmit.json`) - Project-specific settings in current directory
355+
2. **Global** (`~/.gitmit.json`) - User-wide settings in home directory
356+
3. **Default** (Embedded) - Built-in defaults
357+
358+
Settings from higher priority configs override lower priority ones.
359+
360+
### Quick Start
361+
362+
```bash
363+
# Create local config with auto-detected project type
364+
gitmit init
365+
366+
# Create global config
367+
gitmit init --global
368+
```
369+
370+
The `init` command automatically:
371+
- Detects your project type (Go, Node.js, Python, etc.)
372+
- Generates language-specific keyword mappings
373+
- Creates customizable topic mappings
374+
- Sets up keyword scoring weights
375+
376+
### Configuration Options
377+
378+
**Core Features:**
379+
- **Project Type Detection** - Automatically identifies language/framework
380+
- **Keyword Scoring** - Define action-specific keywords and weights
381+
- **Topic Mappings** - Map file paths to commit scopes
382+
- **Diff Stat Threshold** - Control added/deleted line ratio analysis
383+
- **Custom Templates** - Define your own commit message patterns (coming soon)
384+
385+
**Example `.gitmit.json`:**
386+
```json
387+
{
388+
"projectType": "go",
389+
"diffStatThreshold": 0.5,
390+
"topicMappings": {
391+
"internal/api": "api",
392+
"internal/database": "db"
393+
},
394+
"keywords": {
395+
"feat": {
396+
"func": 3,
397+
"class": 2
398+
},
399+
"fix": {
400+
"bug": 3,
401+
"error": 2
402+
}
403+
}
404+
}
405+
```
406+
407+
For detailed configuration documentation, see [CONFIGURATION.md](CONFIGURATION.md).
408+
409+
### Intelligence Built-In
410+
411+
All intelligence is built-in using:
293412

294413
- **Template-based generation** with 100+ curated commit message templates
295414
- **Pattern matching algorithms** for context detection
296415
- **Weighted scoring system** for template selection
297416
- **Similarity detection** for diverse variations
298417
- **Commit history tracking** to avoid repetition
418+
- **Language-aware symbol extraction** via regex
419+
- **Keyword scoring** based on git diff analysis
420+
- **Diff stat analysis** for intent inference
299421

300422
No AI, APIs, or external services required. Everything runs locally and offline.
301423

cmd/init.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
8+
"github.com/fatih/color"
9+
"github.com/spf13/cobra"
10+
11+
"gitmit/internal/config"
12+
)
13+
14+
var (
15+
globalFlag bool
16+
17+
initCmd = &cobra.Command{
18+
Use: "init",
19+
Short: "Initialize a .gitmit.json configuration file",
20+
Long: `Generate a sample .gitmit.json configuration file with basic heuristic rules.
21+
22+
This allows you to customize gitmit's behavior without modifying source code.
23+
You can create either a local config (in the current directory) or a global config (in your home directory).`,
24+
Example: ` gitmit init # Create local .gitmit.json in current directory
25+
gitmit init --global # Create global ~/.gitmit.json in home directory`,
26+
RunE: runInit,
27+
}
28+
)
29+
30+
func init() {
31+
rootCmd.AddCommand(initCmd)
32+
initCmd.Flags().BoolVar(&globalFlag, "global", false, "Create global config in home directory (~/.gitmit.json)")
33+
}
34+
35+
func runInit(cmd *cobra.Command, args []string) error {
36+
// Detect project type automatically
37+
projectType := config.DetectProjectType()
38+
39+
// Create sample configuration
40+
sampleConfig := config.Config{
41+
ProjectType: projectType,
42+
DiffStatThreshold: 0.5,
43+
TopicMappings: map[string]string{
44+
"internal/api": "api",
45+
"internal/database": "db",
46+
"internal/auth": "auth",
47+
"internal/config": "config",
48+
"cmd": "cli",
49+
"pkg": "core",
50+
"docs": "docs",
51+
},
52+
KeywordMappings: map[string]string{
53+
"authentication": "auth",
54+
"database": "db",
55+
"configuration": "config",
56+
},
57+
Keywords: map[string]map[string]int{
58+
"feat": {
59+
"func": 3,
60+
"class": 2,
61+
"new": 2,
62+
"add": 2,
63+
"implement": 2,
64+
},
65+
"fix": {
66+
"bug": 3,
67+
"fix": 3,
68+
"error": 2,
69+
"issue": 2,
70+
"resolve": 2,
71+
"if err": 2,
72+
"try": 1,
73+
"catch": 1,
74+
},
75+
"refactor": {
76+
"refactor": 3,
77+
"restructure": 2,
78+
"rename": 2,
79+
"move": 2,
80+
},
81+
"test": {
82+
"test": 3,
83+
"Test": 3,
84+
"assert": 2,
85+
"expect": 2,
86+
"mock": 2,
87+
},
88+
"docs": {
89+
"docs": 3,
90+
"documentation": 3,
91+
"//": 1,
92+
"comment": 2,
93+
},
94+
},
95+
Templates: map[string]map[string]string{},
96+
}
97+
98+
// Add language-specific keywords based on detected project type
99+
switch projectType {
100+
case "go":
101+
sampleConfig.Keywords["feat"]["type"] = 2
102+
sampleConfig.Keywords["feat"]["struct"] = 2
103+
sampleConfig.Keywords["feat"]["interface"] = 2
104+
sampleConfig.Keywords["fix"]["if err != nil"] = 3
105+
sampleConfig.Keywords["fix"]["panic"] = 2
106+
case "nodejs":
107+
sampleConfig.Keywords["feat"]["export"] = 2
108+
sampleConfig.Keywords["feat"]["const"] = 1
109+
sampleConfig.Keywords["fix"]["throw"] = 2
110+
case "python":
111+
sampleConfig.Keywords["feat"]["def"] = 3
112+
sampleConfig.Keywords["feat"]["async def"] = 3
113+
sampleConfig.Keywords["fix"]["except"] = 2
114+
sampleConfig.Keywords["fix"]["raise"] = 2
115+
}
116+
117+
// Determine file path
118+
var configPath string
119+
if globalFlag {
120+
homeDir, err := os.UserHomeDir()
121+
if err != nil {
122+
return fmt.Errorf("error getting home directory: %w", err)
123+
}
124+
configPath = homeDir + "/.gitmit.json"
125+
} else {
126+
configPath = ".gitmit.json"
127+
}
128+
129+
// Check if config file already exists
130+
if _, err := os.Stat(configPath); err == nil {
131+
color.Yellow("⚠ Config file already exists: %s", configPath)
132+
fmt.Print("Overwrite? [y/N]: ")
133+
var answer string
134+
fmt.Scanln(&answer)
135+
if answer != "y" && answer != "Y" {
136+
color.Yellow("❌ Cancelled.")
137+
return nil
138+
}
139+
}
140+
141+
// Marshal to JSON with indentation
142+
data, err := json.MarshalIndent(sampleConfig, "", " ")
143+
if err != nil {
144+
return fmt.Errorf("error marshaling config: %w", err)
145+
}
146+
147+
// Write to file
148+
err = os.WriteFile(configPath, data, 0644)
149+
if err != nil {
150+
return fmt.Errorf("error writing config file: %w", err)
151+
}
152+
153+
color.Green("✅ Created config file: %s", configPath)
154+
color.Blue("\n📝 Detected project type: %s", projectType)
155+
fmt.Println("\nYou can now customize the configuration to fit your project's needs.")
156+
fmt.Println("\nConfiguration hierarchy:")
157+
fmt.Println(" 1. Local (.gitmit.json) - project-specific settings")
158+
fmt.Println(" 2. Global (~/.gitmit.json) - user-wide settings")
159+
fmt.Println(" 3. Default (embedded) - built-in defaults")
160+
161+
return nil
162+
}

0 commit comments

Comments
 (0)