commitgpt-nikesh 1.0.0__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.
- commitgpt_nikesh-1.0.0/PKG-INFO +272 -0
- commitgpt_nikesh-1.0.0/README.md +246 -0
- commitgpt_nikesh-1.0.0/commitgpt/__init__.py +2 -0
- commitgpt_nikesh-1.0.0/commitgpt/ai.py +46 -0
- commitgpt_nikesh-1.0.0/commitgpt/cli.py +78 -0
- commitgpt_nikesh-1.0.0/commitgpt/git.py +40 -0
- commitgpt_nikesh-1.0.0/commitgpt/prompts.py +5 -0
- commitgpt_nikesh-1.0.0/commitgpt_nikesh.egg-info/PKG-INFO +272 -0
- commitgpt_nikesh-1.0.0/commitgpt_nikesh.egg-info/SOURCES.txt +13 -0
- commitgpt_nikesh-1.0.0/commitgpt_nikesh.egg-info/dependency_links.txt +1 -0
- commitgpt_nikesh-1.0.0/commitgpt_nikesh.egg-info/entry_points.txt +2 -0
- commitgpt_nikesh-1.0.0/commitgpt_nikesh.egg-info/requires.txt +4 -0
- commitgpt_nikesh-1.0.0/commitgpt_nikesh.egg-info/top_level.txt +1 -0
- commitgpt_nikesh-1.0.0/setup.cfg +4 -0
- commitgpt_nikesh-1.0.0/setup.py +31 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: commitgpt-nikesh
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AI-powered commit messages, standups and PR descriptions from your git diff
|
|
5
|
+
Home-page: https://github.com/nikeshsundar/commitgpt
|
|
6
|
+
Author: Nikesh Sundar
|
|
7
|
+
Author-email: nikeshsundar@users.noreply.github.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: click
|
|
14
|
+
Requires-Dist: openai>=1.0.0
|
|
15
|
+
Requires-Dist: pyperclip
|
|
16
|
+
Requires-Dist: python-dotenv
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# commitgpt ⚡
|
|
28
|
+
|
|
29
|
+
> AI-powered commit messages, standups, and PR descriptions — generated from your git diff in 2 seconds.
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## The problem
|
|
38
|
+
|
|
39
|
+
Every day as a developer you waste time writing:
|
|
40
|
+
|
|
41
|
+
- `git commit -m "fix"` — lazy, meaningless commit messages
|
|
42
|
+
- Standup updates — "what did I do yesterday??"
|
|
43
|
+
- PR descriptions — explaining your changes all over again
|
|
44
|
+
|
|
45
|
+
**commitgpt fixes all 3 with one command.**
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Demo
|
|
50
|
+
```
|
|
51
|
+
$ git add .
|
|
52
|
+
$ cmt
|
|
53
|
+
|
|
54
|
+
✨ feat(auth): add Google OAuth2 login with session timeout
|
|
55
|
+
|
|
56
|
+
- Implemented OAuth2 flow using Google provider
|
|
57
|
+
- Sessions expire after 30 mins of inactivity
|
|
58
|
+
- Fixed bug where users stayed logged in after password change
|
|
59
|
+
- Added redirect to dashboard on successful login
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
```bash
|
|
66
|
+
pip install commitgpt
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Setup
|
|
72
|
+
|
|
73
|
+
You only need ONE of these. Pick whichever you prefer:
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### Option 1 — GitHub Token (FREE, recommended)
|
|
78
|
+
|
|
79
|
+
Best for beginners. No credit card. 150 requests/day free.
|
|
80
|
+
|
|
81
|
+
- Go to [github.com](https://github.com) → Settings
|
|
82
|
+
- Click **Developer Settings** → **Personal Access Tokens** → **Tokens (classic)**
|
|
83
|
+
- Click **Generate new token (classic)**
|
|
84
|
+
- Give it any name, no scopes needed
|
|
85
|
+
- Copy the token starting with `ghp_`
|
|
86
|
+
|
|
87
|
+
Create a `.env` file in your project:
|
|
88
|
+
```
|
|
89
|
+
GITHUB_TOKEN=ghp_your_token_here
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Option 2 — Gemini (FREE, best free option)
|
|
95
|
+
|
|
96
|
+
Best free option. 1,500 requests/day free. No credit card.
|
|
97
|
+
|
|
98
|
+
- Go to [aistudio.google.com](https://aistudio.google.com)
|
|
99
|
+
- Click **Get API Key** → **Create API key**
|
|
100
|
+
- Copy the key starting with `AIza`
|
|
101
|
+
|
|
102
|
+
Create a `.env` file in your project:
|
|
103
|
+
```
|
|
104
|
+
GEMINI_API_KEY=AIza_your_key_here
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### Option 3 — OpenAI (Paid)
|
|
110
|
+
|
|
111
|
+
Best quality. Costs roughly $0.001 per request.
|
|
112
|
+
|
|
113
|
+
- Go to [platform.openai.com](https://platform.openai.com)
|
|
114
|
+
- Click **API Keys** → **Create new secret key**
|
|
115
|
+
- Copy the key starting with `sk-proj-`
|
|
116
|
+
|
|
117
|
+
Create a `.env` file in your project:
|
|
118
|
+
```
|
|
119
|
+
OPENAI_API_KEY=sk-proj-your_key_here
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### Option 4 — Anthropic Claude (Paid)
|
|
125
|
+
|
|
126
|
+
Great quality. Costs roughly $0.001 per request.
|
|
127
|
+
|
|
128
|
+
- Go to [console.anthropic.com](https://console.anthropic.com)
|
|
129
|
+
- Click **API Keys** → **Create Key**
|
|
130
|
+
- Copy the key starting with `sk-ant-`
|
|
131
|
+
|
|
132
|
+
Create a `.env` file in your project:
|
|
133
|
+
```
|
|
134
|
+
ANTHROPIC_API_KEY=sk-ant-your_key_here
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Make your token permanent
|
|
140
|
+
|
|
141
|
+
So you never have to set it again every time you open terminal:
|
|
142
|
+
|
|
143
|
+
**Mac/Linux:**
|
|
144
|
+
```bash
|
|
145
|
+
echo 'export GITHUB_TOKEN=ghp_yourtoken' >> ~/.zshrc
|
|
146
|
+
source ~/.zshrc
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Windows:**
|
|
150
|
+
```bash
|
|
151
|
+
setx GITHUB_TOKEN "ghp_yourtoken"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Usage
|
|
157
|
+
|
|
158
|
+
### Commit message
|
|
159
|
+
```bash
|
|
160
|
+
git add .
|
|
161
|
+
cmt
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Daily standup
|
|
165
|
+
```bash
|
|
166
|
+
cmt standup
|
|
167
|
+
```
|
|
168
|
+
Output:
|
|
169
|
+
```
|
|
170
|
+
Yesterday: Implemented OAuth2 login flow, fixed session expiry bug
|
|
171
|
+
Today: Writing tests for auth middleware, reviewing PR #42
|
|
172
|
+
Blockers: None
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### PR description
|
|
176
|
+
```bash
|
|
177
|
+
cmt pr
|
|
178
|
+
```
|
|
179
|
+
Output:
|
|
180
|
+
```
|
|
181
|
+
## What changed
|
|
182
|
+
Added Google OAuth2 login with automatic session timeout after 30 minutes.
|
|
183
|
+
|
|
184
|
+
## Why
|
|
185
|
+
Users were being kept logged in indefinitely, creating a security risk.
|
|
186
|
+
|
|
187
|
+
## Testing
|
|
188
|
+
- Manual: tested login, logout, session expiry
|
|
189
|
+
- Unit: auth middleware coverage at 94%
|
|
190
|
+
- Edge: concurrent login sessions handled correctly
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Extra flags
|
|
194
|
+
```bash
|
|
195
|
+
cmt --emoji # adds emoji to commit message
|
|
196
|
+
cmt --copy # copies output to clipboard automatically
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## How the tool picks your API
|
|
202
|
+
|
|
203
|
+
You don't need to configure anything. Just put your key in `.env` and the tool automatically detects it in this order:
|
|
204
|
+
```
|
|
205
|
+
GITHUB_TOKEN → GitHub Models (gpt-4o-mini)
|
|
206
|
+
GEMINI_API_KEY → Gemini 2.0 Flash
|
|
207
|
+
OPENAI_API_KEY → OpenAI gpt-4o-mini
|
|
208
|
+
ANTHROPIC_API_KEY → Claude Haiku
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
First key found = that provider gets used.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Requirements
|
|
216
|
+
|
|
217
|
+
- Python 3.8+
|
|
218
|
+
- Git installed
|
|
219
|
+
- Any one API key from the options above
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Troubleshooting
|
|
224
|
+
|
|
225
|
+
**`cmt: command not found`**
|
|
226
|
+
```bash
|
|
227
|
+
pip install commitgpt
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**`Error: No API key found`**
|
|
231
|
+
Make sure your `.env` file exists with one of these:
|
|
232
|
+
```
|
|
233
|
+
GITHUB_TOKEN=ghp_...
|
|
234
|
+
GEMINI_API_KEY=AIza...
|
|
235
|
+
OPENAI_API_KEY=sk-proj-...
|
|
236
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**`Not a git repository`**
|
|
240
|
+
You need to be inside a git project. Run `git init` first.
|
|
241
|
+
|
|
242
|
+
**`No staged changes found`**
|
|
243
|
+
Run `git add .` before running `cmt`
|
|
244
|
+
|
|
245
|
+
**`pip install fails`**
|
|
246
|
+
Make sure Python 3.8+ is installed:
|
|
247
|
+
```bash
|
|
248
|
+
python --version
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Contributing
|
|
254
|
+
|
|
255
|
+
Pull requests are welcome! Here's how:
|
|
256
|
+
|
|
257
|
+
1. Fork the repo
|
|
258
|
+
2. Create a branch: `git checkout -b feat/your-feature`
|
|
259
|
+
3. Make your changes
|
|
260
|
+
4. Use commitgpt to write your own commit message 😄
|
|
261
|
+
5. Push and open a PR
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
MIT — free to use, modify and distribute.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
Made by a developer who was tired of writing "fix" as a commit message.
|
|
272
|
+
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# commitgpt ⚡
|
|
2
|
+
|
|
3
|
+
> AI-powered commit messages, standups, and PR descriptions — generated from your git diff in 2 seconds.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The problem
|
|
12
|
+
|
|
13
|
+
Every day as a developer you waste time writing:
|
|
14
|
+
|
|
15
|
+
- `git commit -m "fix"` — lazy, meaningless commit messages
|
|
16
|
+
- Standup updates — "what did I do yesterday??"
|
|
17
|
+
- PR descriptions — explaining your changes all over again
|
|
18
|
+
|
|
19
|
+
**commitgpt fixes all 3 with one command.**
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Demo
|
|
24
|
+
```
|
|
25
|
+
$ git add .
|
|
26
|
+
$ cmt
|
|
27
|
+
|
|
28
|
+
✨ feat(auth): add Google OAuth2 login with session timeout
|
|
29
|
+
|
|
30
|
+
- Implemented OAuth2 flow using Google provider
|
|
31
|
+
- Sessions expire after 30 mins of inactivity
|
|
32
|
+
- Fixed bug where users stayed logged in after password change
|
|
33
|
+
- Added redirect to dashboard on successful login
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
```bash
|
|
40
|
+
pip install commitgpt
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Setup
|
|
46
|
+
|
|
47
|
+
You only need ONE of these. Pick whichever you prefer:
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### Option 1 — GitHub Token (FREE, recommended)
|
|
52
|
+
|
|
53
|
+
Best for beginners. No credit card. 150 requests/day free.
|
|
54
|
+
|
|
55
|
+
- Go to [github.com](https://github.com) → Settings
|
|
56
|
+
- Click **Developer Settings** → **Personal Access Tokens** → **Tokens (classic)**
|
|
57
|
+
- Click **Generate new token (classic)**
|
|
58
|
+
- Give it any name, no scopes needed
|
|
59
|
+
- Copy the token starting with `ghp_`
|
|
60
|
+
|
|
61
|
+
Create a `.env` file in your project:
|
|
62
|
+
```
|
|
63
|
+
GITHUB_TOKEN=ghp_your_token_here
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### Option 2 — Gemini (FREE, best free option)
|
|
69
|
+
|
|
70
|
+
Best free option. 1,500 requests/day free. No credit card.
|
|
71
|
+
|
|
72
|
+
- Go to [aistudio.google.com](https://aistudio.google.com)
|
|
73
|
+
- Click **Get API Key** → **Create API key**
|
|
74
|
+
- Copy the key starting with `AIza`
|
|
75
|
+
|
|
76
|
+
Create a `.env` file in your project:
|
|
77
|
+
```
|
|
78
|
+
GEMINI_API_KEY=AIza_your_key_here
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### Option 3 — OpenAI (Paid)
|
|
84
|
+
|
|
85
|
+
Best quality. Costs roughly $0.001 per request.
|
|
86
|
+
|
|
87
|
+
- Go to [platform.openai.com](https://platform.openai.com)
|
|
88
|
+
- Click **API Keys** → **Create new secret key**
|
|
89
|
+
- Copy the key starting with `sk-proj-`
|
|
90
|
+
|
|
91
|
+
Create a `.env` file in your project:
|
|
92
|
+
```
|
|
93
|
+
OPENAI_API_KEY=sk-proj-your_key_here
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### Option 4 — Anthropic Claude (Paid)
|
|
99
|
+
|
|
100
|
+
Great quality. Costs roughly $0.001 per request.
|
|
101
|
+
|
|
102
|
+
- Go to [console.anthropic.com](https://console.anthropic.com)
|
|
103
|
+
- Click **API Keys** → **Create Key**
|
|
104
|
+
- Copy the key starting with `sk-ant-`
|
|
105
|
+
|
|
106
|
+
Create a `.env` file in your project:
|
|
107
|
+
```
|
|
108
|
+
ANTHROPIC_API_KEY=sk-ant-your_key_here
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Make your token permanent
|
|
114
|
+
|
|
115
|
+
So you never have to set it again every time you open terminal:
|
|
116
|
+
|
|
117
|
+
**Mac/Linux:**
|
|
118
|
+
```bash
|
|
119
|
+
echo 'export GITHUB_TOKEN=ghp_yourtoken' >> ~/.zshrc
|
|
120
|
+
source ~/.zshrc
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Windows:**
|
|
124
|
+
```bash
|
|
125
|
+
setx GITHUB_TOKEN "ghp_yourtoken"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Usage
|
|
131
|
+
|
|
132
|
+
### Commit message
|
|
133
|
+
```bash
|
|
134
|
+
git add .
|
|
135
|
+
cmt
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Daily standup
|
|
139
|
+
```bash
|
|
140
|
+
cmt standup
|
|
141
|
+
```
|
|
142
|
+
Output:
|
|
143
|
+
```
|
|
144
|
+
Yesterday: Implemented OAuth2 login flow, fixed session expiry bug
|
|
145
|
+
Today: Writing tests for auth middleware, reviewing PR #42
|
|
146
|
+
Blockers: None
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### PR description
|
|
150
|
+
```bash
|
|
151
|
+
cmt pr
|
|
152
|
+
```
|
|
153
|
+
Output:
|
|
154
|
+
```
|
|
155
|
+
## What changed
|
|
156
|
+
Added Google OAuth2 login with automatic session timeout after 30 minutes.
|
|
157
|
+
|
|
158
|
+
## Why
|
|
159
|
+
Users were being kept logged in indefinitely, creating a security risk.
|
|
160
|
+
|
|
161
|
+
## Testing
|
|
162
|
+
- Manual: tested login, logout, session expiry
|
|
163
|
+
- Unit: auth middleware coverage at 94%
|
|
164
|
+
- Edge: concurrent login sessions handled correctly
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Extra flags
|
|
168
|
+
```bash
|
|
169
|
+
cmt --emoji # adds emoji to commit message
|
|
170
|
+
cmt --copy # copies output to clipboard automatically
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## How the tool picks your API
|
|
176
|
+
|
|
177
|
+
You don't need to configure anything. Just put your key in `.env` and the tool automatically detects it in this order:
|
|
178
|
+
```
|
|
179
|
+
GITHUB_TOKEN → GitHub Models (gpt-4o-mini)
|
|
180
|
+
GEMINI_API_KEY → Gemini 2.0 Flash
|
|
181
|
+
OPENAI_API_KEY → OpenAI gpt-4o-mini
|
|
182
|
+
ANTHROPIC_API_KEY → Claude Haiku
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
First key found = that provider gets used.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Requirements
|
|
190
|
+
|
|
191
|
+
- Python 3.8+
|
|
192
|
+
- Git installed
|
|
193
|
+
- Any one API key from the options above
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Troubleshooting
|
|
198
|
+
|
|
199
|
+
**`cmt: command not found`**
|
|
200
|
+
```bash
|
|
201
|
+
pip install commitgpt
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**`Error: No API key found`**
|
|
205
|
+
Make sure your `.env` file exists with one of these:
|
|
206
|
+
```
|
|
207
|
+
GITHUB_TOKEN=ghp_...
|
|
208
|
+
GEMINI_API_KEY=AIza...
|
|
209
|
+
OPENAI_API_KEY=sk-proj-...
|
|
210
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**`Not a git repository`**
|
|
214
|
+
You need to be inside a git project. Run `git init` first.
|
|
215
|
+
|
|
216
|
+
**`No staged changes found`**
|
|
217
|
+
Run `git add .` before running `cmt`
|
|
218
|
+
|
|
219
|
+
**`pip install fails`**
|
|
220
|
+
Make sure Python 3.8+ is installed:
|
|
221
|
+
```bash
|
|
222
|
+
python --version
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Contributing
|
|
228
|
+
|
|
229
|
+
Pull requests are welcome! Here's how:
|
|
230
|
+
|
|
231
|
+
1. Fork the repo
|
|
232
|
+
2. Create a branch: `git checkout -b feat/your-feature`
|
|
233
|
+
3. Make your changes
|
|
234
|
+
4. Use commitgpt to write your own commit message 😄
|
|
235
|
+
5. Push and open a PR
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT — free to use, modify and distribute.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
Made by a developer who was tired of writing "fix" as a commit message.
|
|
246
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from openai import OpenAI
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
|
|
6
|
+
class AIError(RuntimeError):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
def get_api_key() -> str:
|
|
10
|
+
key = os.getenv("OPENAI_API_KEY")
|
|
11
|
+
if key:
|
|
12
|
+
return key
|
|
13
|
+
|
|
14
|
+
load_dotenv()
|
|
15
|
+
key = os.getenv("OPENAI_API_KEY")
|
|
16
|
+
if key:
|
|
17
|
+
return key
|
|
18
|
+
|
|
19
|
+
config_path = Path.home() / ".commitgpt"
|
|
20
|
+
if config_path.exists():
|
|
21
|
+
key = config_path.read_text().strip()
|
|
22
|
+
if key:
|
|
23
|
+
return key
|
|
24
|
+
|
|
25
|
+
raise AIError("OPENAI_API_KEY environment variable is not set, and ~/.commitgpt is missing or empty.")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def generate_text(system_prompt: str, user_prompt: str, emoji: bool = False) -> str:
|
|
29
|
+
try:
|
|
30
|
+
api_key = get_api_key()
|
|
31
|
+
client = OpenAI(api_key=api_key)
|
|
32
|
+
|
|
33
|
+
if emoji:
|
|
34
|
+
system_prompt += "\nAlso add an appropriate emoji at the start of the commit message."
|
|
35
|
+
|
|
36
|
+
response = client.chat.completions.create(
|
|
37
|
+
model="gpt-4o-mini",
|
|
38
|
+
messages=[
|
|
39
|
+
{"role": "system", "content": system_prompt},
|
|
40
|
+
{"role": "user", "content": user_prompt}
|
|
41
|
+
],
|
|
42
|
+
temperature=0.3,
|
|
43
|
+
)
|
|
44
|
+
return response.choices[0].message.content.strip()
|
|
45
|
+
except Exception as e:
|
|
46
|
+
raise AIError(f"OpenAI API Error: {str(e)}")
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import click
|
|
3
|
+
import pyperclip
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
|
|
6
|
+
from .git import get_staged_diff, get_recent_log, get_pr_diff, GitError
|
|
7
|
+
from .ai import generate_text, AIError
|
|
8
|
+
from .prompts import COMMIT_PROMPT, STANDUP_PROMPT, PR_PROMPT
|
|
9
|
+
|
|
10
|
+
load_dotenv()
|
|
11
|
+
|
|
12
|
+
@click.group(invoke_without_command=True)
|
|
13
|
+
@click.option('--copy', is_flag=True, help="Copy output to clipboard")
|
|
14
|
+
@click.option('--emoji', is_flag=True, help="Add emoji to commit message")
|
|
15
|
+
@click.pass_context
|
|
16
|
+
def cli(ctx, copy, emoji):
|
|
17
|
+
"""CommitGPT: Auto-generate commit messages, standups, and PR descriptions."""
|
|
18
|
+
if ctx.invoked_subcommand is None:
|
|
19
|
+
generate_commit(copy, emoji)
|
|
20
|
+
else:
|
|
21
|
+
ctx.ensure_object(dict)
|
|
22
|
+
ctx.obj['copy'] = copy
|
|
23
|
+
ctx.obj['emoji'] = emoji
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def generate_commit(copy: bool, emoji: bool):
|
|
27
|
+
try:
|
|
28
|
+
diff = get_staged_diff()
|
|
29
|
+
click.echo("Generating commit message...")
|
|
30
|
+
message = generate_text(COMMIT_PROMPT, diff, emoji=emoji)
|
|
31
|
+
click.echo("\n" + message + "\n")
|
|
32
|
+
if copy:
|
|
33
|
+
pyperclip.copy(message)
|
|
34
|
+
click.echo("Copied to clipboard!")
|
|
35
|
+
except (GitError, AIError) as e:
|
|
36
|
+
click.echo(f"Error: {str(e)}", err=True)
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
@cli.command()
|
|
40
|
+
@click.pass_context
|
|
41
|
+
def standup(ctx):
|
|
42
|
+
"""Generate a daily standup based on last 24h commits."""
|
|
43
|
+
try:
|
|
44
|
+
log = get_recent_log()
|
|
45
|
+
click.echo("Generating standup...")
|
|
46
|
+
message = generate_text(STANDUP_PROMPT, log)
|
|
47
|
+
click.echo("\n" + message + "\n")
|
|
48
|
+
if ctx.obj.get('copy'):
|
|
49
|
+
pyperclip.copy(message)
|
|
50
|
+
click.echo("Copied to clipboard!")
|
|
51
|
+
except (GitError, AIError) as e:
|
|
52
|
+
click.echo(f"Error: {str(e)}", err=True)
|
|
53
|
+
sys.exit(1)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@cli.command()
|
|
57
|
+
@click.pass_context
|
|
58
|
+
def pr(ctx):
|
|
59
|
+
"""Generate a PR description from diff main...HEAD."""
|
|
60
|
+
try:
|
|
61
|
+
diff = get_pr_diff()
|
|
62
|
+
click.echo("Generating PR description...")
|
|
63
|
+
message = generate_text(PR_PROMPT, diff)
|
|
64
|
+
click.echo("\n" + message + "\n")
|
|
65
|
+
if ctx.obj.get('copy'):
|
|
66
|
+
pyperclip.copy(message)
|
|
67
|
+
click.echo("Copied to clipboard!")
|
|
68
|
+
except (GitError, AIError) as e:
|
|
69
|
+
click.echo(f"Error: {str(e)}", err=True)
|
|
70
|
+
sys.exit(1)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def main():
|
|
74
|
+
cli(obj={})
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
main()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
|
|
3
|
+
class GitError(RuntimeError):
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
def _run_git(args: list[str]) -> str:
|
|
7
|
+
try:
|
|
8
|
+
subprocess.run(["git", "rev-parse", "--is-inside-work-tree"], capture_output=True, check=True)
|
|
9
|
+
except subprocess.CalledProcessError:
|
|
10
|
+
raise GitError("Not in a git repository.")
|
|
11
|
+
|
|
12
|
+
process = subprocess.run(["git", *args], capture_output=True, text=True)
|
|
13
|
+
if process.returncode != 0:
|
|
14
|
+
raise GitError(process.stderr.strip() or "Unknown git error")
|
|
15
|
+
return process.stdout.strip()
|
|
16
|
+
|
|
17
|
+
def get_staged_diff() -> str:
|
|
18
|
+
diff = _run_git(["diff", "--staged"])
|
|
19
|
+
if not diff:
|
|
20
|
+
raise GitError("No staged changes found. Did you forget to git add?")
|
|
21
|
+
return diff
|
|
22
|
+
|
|
23
|
+
def get_recent_log() -> str:
|
|
24
|
+
log = _run_git(["log", "--since=24 hours ago", "--oneline"])
|
|
25
|
+
if not log:
|
|
26
|
+
raise GitError("No commits found in the last 24 hours.")
|
|
27
|
+
return log
|
|
28
|
+
|
|
29
|
+
def get_pr_diff() -> str:
|
|
30
|
+
try:
|
|
31
|
+
diff = _run_git(["diff", "main...HEAD"])
|
|
32
|
+
except GitError:
|
|
33
|
+
try:
|
|
34
|
+
diff = _run_git(["diff", "master...HEAD"])
|
|
35
|
+
except GitError:
|
|
36
|
+
raise GitError("Could not diff against main or master.")
|
|
37
|
+
|
|
38
|
+
if not diff:
|
|
39
|
+
raise GitError("No differences found between main/master and HEAD.")
|
|
40
|
+
return diff
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
COMMIT_PROMPT = """You are an expert developer. Given this git diff, write a single conventional \ncommit message. Format: type(scope): description. Types: feat/fix/docs/style/\nrefactor/test/chore. Keep under 72 chars. Then add 2-4 bullet points explaining \nkey changes. Output ONLY the commit message and bullets, nothing else."""
|
|
2
|
+
|
|
3
|
+
STANDUP_PROMPT = """You are a developer writing a daily standup. Given these git commits from the \nlast 24 hours, generate a standup update. Format exactly:\nYesterday: [what was done, past tense, concise]\nToday: [logical next steps based on the work]\nBlockers: [say None if nothing obvious]\nBe specific about what changed. Output ONLY the standup, nothing else."""
|
|
4
|
+
|
|
5
|
+
PR_PROMPT = """You are an expert developer. Given this git diff between branches, write a \ncomplete QR description. Format exactly:\n## What changed\n[2-3 sentences]\n## Why\n[reason for the change]\n## Testing\n[how to test this]\n## Checklist\n- [ ] Tests added\n- [ ] Docs updated\nOutput ONLY the QR description markdown, nothing else."""
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: commitgpt-nikesh
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AI-powered commit messages, standups and PR descriptions from your git diff
|
|
5
|
+
Home-page: https://github.com/nikeshsundar/commitgpt
|
|
6
|
+
Author: Nikesh Sundar
|
|
7
|
+
Author-email: nikeshsundar@users.noreply.github.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: click
|
|
14
|
+
Requires-Dist: openai>=1.0.0
|
|
15
|
+
Requires-Dist: pyperclip
|
|
16
|
+
Requires-Dist: python-dotenv
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# commitgpt ⚡
|
|
28
|
+
|
|
29
|
+
> AI-powered commit messages, standups, and PR descriptions — generated from your git diff in 2 seconds.
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## The problem
|
|
38
|
+
|
|
39
|
+
Every day as a developer you waste time writing:
|
|
40
|
+
|
|
41
|
+
- `git commit -m "fix"` — lazy, meaningless commit messages
|
|
42
|
+
- Standup updates — "what did I do yesterday??"
|
|
43
|
+
- PR descriptions — explaining your changes all over again
|
|
44
|
+
|
|
45
|
+
**commitgpt fixes all 3 with one command.**
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Demo
|
|
50
|
+
```
|
|
51
|
+
$ git add .
|
|
52
|
+
$ cmt
|
|
53
|
+
|
|
54
|
+
✨ feat(auth): add Google OAuth2 login with session timeout
|
|
55
|
+
|
|
56
|
+
- Implemented OAuth2 flow using Google provider
|
|
57
|
+
- Sessions expire after 30 mins of inactivity
|
|
58
|
+
- Fixed bug where users stayed logged in after password change
|
|
59
|
+
- Added redirect to dashboard on successful login
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
```bash
|
|
66
|
+
pip install commitgpt
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Setup
|
|
72
|
+
|
|
73
|
+
You only need ONE of these. Pick whichever you prefer:
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### Option 1 — GitHub Token (FREE, recommended)
|
|
78
|
+
|
|
79
|
+
Best for beginners. No credit card. 150 requests/day free.
|
|
80
|
+
|
|
81
|
+
- Go to [github.com](https://github.com) → Settings
|
|
82
|
+
- Click **Developer Settings** → **Personal Access Tokens** → **Tokens (classic)**
|
|
83
|
+
- Click **Generate new token (classic)**
|
|
84
|
+
- Give it any name, no scopes needed
|
|
85
|
+
- Copy the token starting with `ghp_`
|
|
86
|
+
|
|
87
|
+
Create a `.env` file in your project:
|
|
88
|
+
```
|
|
89
|
+
GITHUB_TOKEN=ghp_your_token_here
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Option 2 — Gemini (FREE, best free option)
|
|
95
|
+
|
|
96
|
+
Best free option. 1,500 requests/day free. No credit card.
|
|
97
|
+
|
|
98
|
+
- Go to [aistudio.google.com](https://aistudio.google.com)
|
|
99
|
+
- Click **Get API Key** → **Create API key**
|
|
100
|
+
- Copy the key starting with `AIza`
|
|
101
|
+
|
|
102
|
+
Create a `.env` file in your project:
|
|
103
|
+
```
|
|
104
|
+
GEMINI_API_KEY=AIza_your_key_here
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### Option 3 — OpenAI (Paid)
|
|
110
|
+
|
|
111
|
+
Best quality. Costs roughly $0.001 per request.
|
|
112
|
+
|
|
113
|
+
- Go to [platform.openai.com](https://platform.openai.com)
|
|
114
|
+
- Click **API Keys** → **Create new secret key**
|
|
115
|
+
- Copy the key starting with `sk-proj-`
|
|
116
|
+
|
|
117
|
+
Create a `.env` file in your project:
|
|
118
|
+
```
|
|
119
|
+
OPENAI_API_KEY=sk-proj-your_key_here
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### Option 4 — Anthropic Claude (Paid)
|
|
125
|
+
|
|
126
|
+
Great quality. Costs roughly $0.001 per request.
|
|
127
|
+
|
|
128
|
+
- Go to [console.anthropic.com](https://console.anthropic.com)
|
|
129
|
+
- Click **API Keys** → **Create Key**
|
|
130
|
+
- Copy the key starting with `sk-ant-`
|
|
131
|
+
|
|
132
|
+
Create a `.env` file in your project:
|
|
133
|
+
```
|
|
134
|
+
ANTHROPIC_API_KEY=sk-ant-your_key_here
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Make your token permanent
|
|
140
|
+
|
|
141
|
+
So you never have to set it again every time you open terminal:
|
|
142
|
+
|
|
143
|
+
**Mac/Linux:**
|
|
144
|
+
```bash
|
|
145
|
+
echo 'export GITHUB_TOKEN=ghp_yourtoken' >> ~/.zshrc
|
|
146
|
+
source ~/.zshrc
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Windows:**
|
|
150
|
+
```bash
|
|
151
|
+
setx GITHUB_TOKEN "ghp_yourtoken"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Usage
|
|
157
|
+
|
|
158
|
+
### Commit message
|
|
159
|
+
```bash
|
|
160
|
+
git add .
|
|
161
|
+
cmt
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Daily standup
|
|
165
|
+
```bash
|
|
166
|
+
cmt standup
|
|
167
|
+
```
|
|
168
|
+
Output:
|
|
169
|
+
```
|
|
170
|
+
Yesterday: Implemented OAuth2 login flow, fixed session expiry bug
|
|
171
|
+
Today: Writing tests for auth middleware, reviewing PR #42
|
|
172
|
+
Blockers: None
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### PR description
|
|
176
|
+
```bash
|
|
177
|
+
cmt pr
|
|
178
|
+
```
|
|
179
|
+
Output:
|
|
180
|
+
```
|
|
181
|
+
## What changed
|
|
182
|
+
Added Google OAuth2 login with automatic session timeout after 30 minutes.
|
|
183
|
+
|
|
184
|
+
## Why
|
|
185
|
+
Users were being kept logged in indefinitely, creating a security risk.
|
|
186
|
+
|
|
187
|
+
## Testing
|
|
188
|
+
- Manual: tested login, logout, session expiry
|
|
189
|
+
- Unit: auth middleware coverage at 94%
|
|
190
|
+
- Edge: concurrent login sessions handled correctly
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Extra flags
|
|
194
|
+
```bash
|
|
195
|
+
cmt --emoji # adds emoji to commit message
|
|
196
|
+
cmt --copy # copies output to clipboard automatically
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## How the tool picks your API
|
|
202
|
+
|
|
203
|
+
You don't need to configure anything. Just put your key in `.env` and the tool automatically detects it in this order:
|
|
204
|
+
```
|
|
205
|
+
GITHUB_TOKEN → GitHub Models (gpt-4o-mini)
|
|
206
|
+
GEMINI_API_KEY → Gemini 2.0 Flash
|
|
207
|
+
OPENAI_API_KEY → OpenAI gpt-4o-mini
|
|
208
|
+
ANTHROPIC_API_KEY → Claude Haiku
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
First key found = that provider gets used.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Requirements
|
|
216
|
+
|
|
217
|
+
- Python 3.8+
|
|
218
|
+
- Git installed
|
|
219
|
+
- Any one API key from the options above
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Troubleshooting
|
|
224
|
+
|
|
225
|
+
**`cmt: command not found`**
|
|
226
|
+
```bash
|
|
227
|
+
pip install commitgpt
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**`Error: No API key found`**
|
|
231
|
+
Make sure your `.env` file exists with one of these:
|
|
232
|
+
```
|
|
233
|
+
GITHUB_TOKEN=ghp_...
|
|
234
|
+
GEMINI_API_KEY=AIza...
|
|
235
|
+
OPENAI_API_KEY=sk-proj-...
|
|
236
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**`Not a git repository`**
|
|
240
|
+
You need to be inside a git project. Run `git init` first.
|
|
241
|
+
|
|
242
|
+
**`No staged changes found`**
|
|
243
|
+
Run `git add .` before running `cmt`
|
|
244
|
+
|
|
245
|
+
**`pip install fails`**
|
|
246
|
+
Make sure Python 3.8+ is installed:
|
|
247
|
+
```bash
|
|
248
|
+
python --version
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Contributing
|
|
254
|
+
|
|
255
|
+
Pull requests are welcome! Here's how:
|
|
256
|
+
|
|
257
|
+
1. Fork the repo
|
|
258
|
+
2. Create a branch: `git checkout -b feat/your-feature`
|
|
259
|
+
3. Make your changes
|
|
260
|
+
4. Use commitgpt to write your own commit message 😄
|
|
261
|
+
5. Push and open a PR
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
MIT — free to use, modify and distribute.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
Made by a developer who was tired of writing "fix" as a commit message.
|
|
272
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
commitgpt/__init__.py
|
|
4
|
+
commitgpt/ai.py
|
|
5
|
+
commitgpt/cli.py
|
|
6
|
+
commitgpt/git.py
|
|
7
|
+
commitgpt/prompts.py
|
|
8
|
+
commitgpt_nikesh.egg-info/PKG-INFO
|
|
9
|
+
commitgpt_nikesh.egg-info/SOURCES.txt
|
|
10
|
+
commitgpt_nikesh.egg-info/dependency_links.txt
|
|
11
|
+
commitgpt_nikesh.egg-info/entry_points.txt
|
|
12
|
+
commitgpt_nikesh.egg-info/requires.txt
|
|
13
|
+
commitgpt_nikesh.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
commitgpt
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="commitgpt-nikesh",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
include_package_data=True,
|
|
8
|
+
install_requires=[
|
|
9
|
+
"click",
|
|
10
|
+
"openai>=1.0.0",
|
|
11
|
+
"pyperclip",
|
|
12
|
+
"python-dotenv",
|
|
13
|
+
],
|
|
14
|
+
entry_points={
|
|
15
|
+
"console_scripts": [
|
|
16
|
+
"cmt=commitgpt.cli:main",
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
author="Nikesh Sundar",
|
|
20
|
+
author_email="nikeshsundar@users.noreply.github.com",
|
|
21
|
+
description="AI-powered commit messages, standups and PR descriptions from your git diff",
|
|
22
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
23
|
+
long_description_content_type="text/markdown",
|
|
24
|
+
url="https://github.com/nikeshsundar/commitgpt",
|
|
25
|
+
classifiers=[
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"License :: OSI Approved :: MIT License",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
],
|
|
30
|
+
python_requires=">=3.9",
|
|
31
|
+
)
|