devcommit 0.1.5.2__tar.gz → 0.1.5.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devcommit
3
- Version: 0.1.5.2
3
+ Version: 0.1.5.4
4
4
  Summary: AI-powered git commit message generator
5
5
  License: GNU GENERAL PUBLIC LICENSE
6
6
  Version 3, 29 June 2007
@@ -803,6 +803,16 @@ A command-line AI tool for autocommits.
803
803
 
804
804
  ## Usage
805
805
 
806
+ ### Quick Setup
807
+
808
+ Generate a configuration file with default settings:
809
+
810
+ ```bash
811
+ create-dcommit
812
+ ```
813
+
814
+ This creates a `.dcommit` file in your home directory (or virtual environment config folder) with all available options.
815
+
806
816
  After installation, you can start using DevCommit directly in your terminal:
807
817
 
808
818
  ```bash
@@ -1140,8 +1150,8 @@ devcommit --stageAll --changelog --files src/
1140
1150
 
1141
1151
  - **With `--stageAll`**: Changelog is generated from unstaged changes **before** staging
1142
1152
  - **Without `--stageAll`**: Changelog is generated from the last commit **after** committing
1143
- - Changelogs are saved as markdown files with datetime-based names (e.g., `2026-01-28_00-55-30.md`)
1144
- - Default directory: `changelogs/` (configurable via `CHANGELOG_DIR` in `.dcommit`)
1153
+ - Changelogs are saved as markdown files with datetime-based names inside `year/month` folders (e.g., `changelogs/2026/01/2026-01-28_00-55-30.md`)
1154
+ - Default base directory: `changelogs/` (configurable via `CHANGELOG_DIR` in `.dcommit`)
1145
1155
  - Uses Keep a Changelog format with AI-generated content
1146
1156
 
1147
1157
  **Example workflow:**
@@ -1153,7 +1163,7 @@ devcommit --stageAll --changelog --files src/
1153
1163
  # Stage all changes and generate changelog before committing
1154
1164
  devcommit --stageAll --changelog
1155
1165
 
1156
- # The changelog file is created in changelogs/ directory
1166
+ # The changelog file is created in changelogs/<year>/<month>/ directory
1157
1167
  # Then changes are staged and committed
1158
1168
  ```
1159
1169
 
@@ -98,6 +98,16 @@ A command-line AI tool for autocommits.
98
98
 
99
99
  ## Usage
100
100
 
101
+ ### Quick Setup
102
+
103
+ Generate a configuration file with default settings:
104
+
105
+ ```bash
106
+ create-dcommit
107
+ ```
108
+
109
+ This creates a `.dcommit` file in your home directory (or virtual environment config folder) with all available options.
110
+
101
111
  After installation, you can start using DevCommit directly in your terminal:
102
112
 
103
113
  ```bash
@@ -435,8 +445,8 @@ devcommit --stageAll --changelog --files src/
435
445
 
436
446
  - **With `--stageAll`**: Changelog is generated from unstaged changes **before** staging
437
447
  - **Without `--stageAll`**: Changelog is generated from the last commit **after** committing
438
- - Changelogs are saved as markdown files with datetime-based names (e.g., `2026-01-28_00-55-30.md`)
439
- - Default directory: `changelogs/` (configurable via `CHANGELOG_DIR` in `.dcommit`)
448
+ - Changelogs are saved as markdown files with datetime-based names inside `year/month` folders (e.g., `changelogs/2026/01/2026-01-28_00-55-30.md`)
449
+ - Default base directory: `changelogs/` (configurable via `CHANGELOG_DIR` in `.dcommit`)
440
450
  - Uses Keep a Changelog format with AI-generated content
441
451
 
442
452
  **Example workflow:**
@@ -448,7 +458,7 @@ devcommit --stageAll --changelog --files src/
448
458
  # Stage all changes and generate changelog before committing
449
459
  devcommit --stageAll --changelog
450
460
 
451
- # The changelog file is created in changelogs/ directory
461
+ # The changelog file is created in changelogs/<year>/<month>/ directory
452
462
  # Then changes are staged and committed
453
463
  ```
454
464
 
@@ -124,6 +124,8 @@ class OpenAIProvider(AIProvider):
124
124
  max_tokens=max_tokens,
125
125
  temperature=0.7,
126
126
  )
127
+ if not response or not response.choices:
128
+ raise ValueError("OpenAI returned empty response (no choices).")
127
129
  return response.choices[0].message.content.strip()
128
130
 
129
131
 
@@ -150,6 +152,8 @@ class GroqProvider(AIProvider):
150
152
  max_tokens=max_tokens,
151
153
  temperature=0.7,
152
154
  )
155
+ if not response or not response.choices:
156
+ raise ValueError("Groq returned empty response (no choices).")
153
157
  return response.choices[0].message.content.strip()
154
158
 
155
159
 
@@ -190,7 +194,14 @@ class OpenRouterProvider(AIProvider):
190
194
  "X-Title": "DevCommit",
191
195
  },
192
196
  )
193
- return response.choices[0].message.content.strip()
197
+ if not response or not response.choices:
198
+ raise ValueError("OpenRouter returned empty response (no choices).")
199
+
200
+ content = response.choices[0].message.content
201
+ if not content:
202
+ return ""
203
+
204
+ return content.strip()
194
205
 
195
206
 
196
207
  class AnthropicProvider(AIProvider):
@@ -284,6 +295,8 @@ class CustomProvider(AIProvider):
284
295
  max_tokens=max_tokens,
285
296
  temperature=0.7,
286
297
  )
298
+ if not response or not response.choices:
299
+ raise ValueError("Custom API returned empty response (no choices).")
287
300
  return response.choices[0].message.content.strip()
288
301
 
289
302
 
@@ -3,8 +3,9 @@
3
3
 
4
4
  import os
5
5
  from datetime import datetime
6
- from devcommit.utils.logger import config
6
+
7
7
  from devcommit.app.ai_providers import get_ai_provider
8
+ from devcommit.utils.logger import config
8
9
 
9
10
 
10
11
  def generate_changelog_prompt() -> str:
@@ -41,49 +42,50 @@ Only include sections that have changes. Do not add empty sections."""
41
42
 
42
43
  def generate_changelog(diff: str) -> str:
43
44
  """Generate changelog content from git diff using AI.
44
-
45
+
45
46
  Args:
46
47
  diff: Git diff string
47
-
48
+
48
49
  Returns:
49
50
  Formatted markdown changelog content
50
51
  """
51
52
  prompt = generate_changelog_prompt()
52
-
53
- # Get AI provider from config
53
+
54
54
  provider = get_ai_provider(config)
55
-
56
- # Generate changelog using AI
55
+
57
56
  max_tokens = config("MAX_TOKENS", default=8192, cast=int)
58
- changelog_content = provider.generate_commit_message(diff, prompt, max_tokens)
59
-
57
+ changelog_content = provider.generate_commit_message(
58
+ diff, prompt, max_tokens
59
+ )
60
+
60
61
  return changelog_content
61
62
 
62
63
 
63
64
  def save_changelog(content: str, directory: str = None) -> str:
64
65
  """Save changelog content to a file.
65
-
66
+
66
67
  Args:
67
68
  content: Changelog markdown content
68
69
  directory: Directory to save changelog (default from config)
69
-
70
+
70
71
  Returns:
71
72
  Path to the saved changelog file
72
73
  """
73
- # Get directory from config if not provided
74
74
  if directory is None:
75
75
  directory = config("CHANGELOG_DIR", default="changelogs")
76
-
77
- # Create directory if it doesn't exist
78
- os.makedirs(directory, exist_ok=True)
79
-
80
- # Generate filename with current datetime
76
+
81
77
  now = datetime.now()
78
+ year_directory = now.strftime("%Y")
79
+ month_directory = now.strftime("%m")
80
+ target_directory = os.path.join(directory, year_directory, month_directory)
81
+
82
+ # Create the year/month directory structure if it doesn't exist
83
+ os.makedirs(target_directory, exist_ok=True)
84
+
82
85
  filename = now.strftime("%Y-%m-%d_%H-%M-%S.md")
83
- filepath = os.path.join(directory, filename)
84
-
85
- # Write content to file
86
- with open(filepath, 'w', encoding='utf-8') as f:
86
+ filepath = os.path.join(target_directory, filename)
87
+
88
+ with open(filepath, "w", encoding="utf-8") as f:
87
89
  f.write(content)
88
-
90
+
89
91
  return filepath
@@ -0,0 +1,111 @@
1
+ import os
2
+
3
+
4
+ def create_dcommit():
5
+ dcommit_content = """# DevCommit Configuration File (OPTIONAL)
6
+ # This file is optional - you can use environment variables instead!
7
+ #
8
+ # Copy this file to:
9
+ # - ~/.dcommit (for global config)
10
+ # - $VIRTUAL_ENV/config/.dcommit (for venv-specific config)
11
+ #
12
+ # Or use environment variables:
13
+ # export GEMINI_API_KEY='your-api-key-here'
14
+ # export COMMIT_MODE='directory'
15
+ #
16
+ # Priority: .dcommit file > Environment Variables > Defaults
17
+
18
+ # ════════════════════════════════════════════════════════════════
19
+ # AI Provider Configuration
20
+ # ════════════════════════════════════════════════════════════════
21
+
22
+ # AI Provider (default: gemini)
23
+ # Options: gemini, openai, groq, anthropic, ollama, custom
24
+ AI_PROVIDER = gemini
25
+
26
+ # ─── Gemini (Google) ───
27
+ # Get API key from: https://aistudio.google.com/app/apikey
28
+ GEMINI_API_KEY = your-api-key-here
29
+ GEMINI_MODEL = gemini-2.0-flash-exp
30
+
31
+ # ─── OpenAI ───
32
+ # OPENAI_API_KEY = your-openai-key
33
+ # OPENAI_MODEL = gpt-4o-mini
34
+
35
+ # ─── Groq (Fast & Free) ───
36
+ # Get API key from: https://console.groq.com/
37
+ # GROQ_API_KEY = your-groq-key
38
+ # GROQ_MODEL = llama-3.3-70b-versatile
39
+
40
+ # ─── Anthropic Claude ───
41
+ # ANTHROPIC_API_KEY = your-anthropic-key
42
+ # ANTHROPIC_MODEL = claude-3-haiku-20240307
43
+
44
+ # ─── OpenRouter ───
45
+ # OPENROUTER_API_KEY = your-openrouter-key
46
+ # OPENROUTER_MODEL = meta-llama/llama-3.3-70b-instruct:free
47
+
48
+ # ─── Ollama (Local) ───
49
+ # OLLAMA_BASE_URL = http://localhost:11434
50
+ # OLLAMA_MODEL = llama3
51
+
52
+ # ─── Custom API (OpenAI-compatible) ───
53
+ # CUSTOM_API_URL = http://your-server/v1
54
+ # CUSTOM_API_KEY = your-key
55
+ # CUSTOM_MODEL = your-model-name
56
+
57
+ # ════════════════════════════════════════════════════════════════
58
+ # General Configuration
59
+ # ════════════════════════════════════════════════════════════════
60
+
61
+ # Language/locale for commit messages (default: en-US)
62
+ LOCALE = en
63
+
64
+ # Number of commit message suggestions to generate (default: 1)
65
+ MAX_NO = 1
66
+
67
+ # Type of commit messages (default: general)
68
+ # Options: general, conventional, etc.
69
+ COMMIT_TYPE = conventional
70
+
71
+ # Gemini model to use (default: gemini-1.5-flash)
72
+ MODEL_NAME = gemini-1.5-flash
73
+
74
+ # Commit mode (default: auto)
75
+ # Options:
76
+ # - auto: Prompts when multiple directories are detected
77
+ # - directory: Always use directory-based commits for multiple directories
78
+ # - global: Always create one commit for all changes
79
+ COMMIT_MODE = auto
80
+
81
+ # Files to exclude from diff (default: package-lock.json, pnpm-lock.yaml, yarn.lock, *.lock)
82
+ # Comma-separated list of file patterns
83
+ EXCLUDE_FILES = *.lock, dist/*, build/*, node_modules/*
84
+
85
+ # Directory for changelog files (default: changelogs)
86
+ # Used when --changelog flag is passed
87
+ CHANGELOG_DIR = changelogs
88
+ """
89
+
90
+ if "VIRTUAL_ENV" in os.environ:
91
+ target_directory = os.path.join(
92
+ os.environ.get("VIRTUAL_ENV", ""), "config"
93
+ )
94
+ else:
95
+ target_directory = os.path.expanduser("~/")
96
+
97
+ os.makedirs(target_directory, exist_ok=True)
98
+ dcommit_file = os.path.join(target_directory, ".dcommit")
99
+
100
+ if os.path.exists(dcommit_file):
101
+ print(f"⚠️ Config file already exists at: {dcommit_file}")
102
+ print("❌ Operation cancelled to prevent overwriting.")
103
+ return
104
+
105
+ with open(dcommit_file, "w") as file:
106
+ file.write(dcommit_content.strip())
107
+ print(f"✅ .dcommit file created at: {dcommit_file}")
108
+
109
+
110
+ if __name__ == "__main__":
111
+ create_dcommit()
@@ -358,10 +358,11 @@ def generate_relation_grouping_prompt(files: List[str], diffs: Dict[str, str]) -
358
358
  " - Example: Adding docker.yaml, kubernetes.yaml, pm2.yaml = ONE GROUP 'add-devops-commands'",
359
359
  " - Example: Schema + API + Migration + Tests for same entity = ONE GROUP",
360
360
  "",
361
- "STEP 3: ONLY SEPARATE WHEN TRULY UNRELATED",
362
- " - Separate ONLY if changes serve completely different purposes",
363
- " - A bug fix mixed with a new feature = 2 groups (one for each purpose)",
364
- " - But 10 new feature files = 1 group, not 10 groups!",
361
+ "STEP 3: SEPARATE BY DISTINCT INTENT",
362
+ " - Separate different KINDS of work (e.g. New Feature vs Bug Fix)",
363
+ " - A bug fix in module A + a new feature in module B = 2 groups",
364
+ " - Documentation updates only = separate group (unless part of a new feature)",
365
+ " - If two changes are unrelated, DO NOT force them together just to reduce groups",
365
366
  "",
366
367
  "=" * 70,
367
368
  "EXAMPLES OF CORRECT GROUPING:",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devcommit"
3
- version = "0.1.5.2"
3
+ version = "0.1.5.4"
4
4
  description = "AI-powered git commit message generator"
5
5
  readme = "README.md"
6
6
  license = {file = "COPYING"}
@@ -40,11 +40,11 @@ documentation = "https://github.com/Hordunlarmy/DevCommit#readme"
40
40
 
41
41
  [project.scripts]
42
42
  devcommit = "devcommit.main:main"
43
- create-dcommit = "scripts.create_dcommit:create_dcommit"
43
+ create-dcommit = "devcommit.create_config:create_dcommit"
44
44
 
45
45
  [tool.poetry]
46
46
  name = "devcommit"
47
- version = "0.1.4.4"
47
+ version = "0.1.5.4"
48
48
  description = "AI-powered git commit message generator"
49
49
  authors = ["Hordunlarmy <Hordunlarmy@gmail.com>"]
50
50
 
File without changes