diffsage 1.2.0__tar.gz → 1.3.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.
- {diffsage-1.2.0/src/diffsage.egg-info → diffsage-1.3.0}/PKG-INFO +156 -29
- {diffsage-1.2.0 → diffsage-1.3.0}/README.md +155 -28
- {diffsage-1.2.0 → diffsage-1.3.0}/pyproject.toml +1 -1
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/cli.py +7 -1
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/ask.py +6 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/commit.py +23 -6
- diffsage-1.3.0/src/diffsage/commands/pr.py +220 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/__init__.py +31 -10
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/base.py +12 -0
- diffsage-1.3.0/src/diffsage/exceptions/git.py +21 -0
- diffsage-1.3.0/src/diffsage/exceptions/github.py +13 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/git/client.py +102 -0
- diffsage-1.3.0/src/diffsage/github/client.py +65 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/commit_message.py +2 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/git.py +13 -1
- diffsage-1.3.0/src/diffsage/models/pull_request.py +27 -0
- diffsage-1.3.0/src/diffsage/models/pull_request_analysis.py +29 -0
- diffsage-1.3.0/src/diffsage/parsers/pull_request_parser.py +68 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/ai_service.py +11 -1
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/commit_service.py +10 -2
- diffsage-1.3.0/src/diffsage/services/git_service.py +116 -0
- diffsage-1.3.0/src/diffsage/services/github_service.py +75 -0
- diffsage-1.3.0/src/diffsage/services/prompt_service.py +182 -0
- diffsage-1.3.0/src/diffsage/services/pull_request_analysis_service.py +281 -0
- diffsage-1.3.0/src/diffsage/services/pull_request_service.py +42 -0
- diffsage-1.3.0/src/diffsage/ui/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/commit_view.py +2 -2
- diffsage-1.3.0/src/diffsage/ui/pull_request_view.py +122 -0
- {diffsage-1.2.0 → diffsage-1.3.0/src/diffsage.egg-info}/PKG-INFO +156 -29
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/SOURCES.txt +12 -1
- diffsage-1.2.0/src/diffsage/exceptions/git.py +0 -9
- diffsage-1.2.0/src/diffsage/services/git_service.py +0 -20
- diffsage-1.2.0/src/diffsage/services/prompt_service.py +0 -60
- {diffsage-1.2.0 → diffsage-1.3.0}/LICENSE +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/setup.cfg +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/__main__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/auth.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/config.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/commands/doctor.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/defaults.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/file_loader.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/loader.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/paths.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/resolver.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/schema.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/scope.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/config/settings.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/credentials.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/exceptions/provider.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/git/__init__.py +0 -0
- {diffsage-1.2.0/src/diffsage/logging → diffsage-1.3.0/src/diffsage/github}/__init__.py +0 -0
- {diffsage-1.2.0/src/diffsage/models → diffsage-1.3.0/src/diffsage/logging}/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/logging/formatter.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/logging/logger.py +0 -0
- {diffsage-1.2.0/src/diffsage/prompts → diffsage-1.3.0/src/diffsage/models}/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/config.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/credentials.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/doctor.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/models/provider.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/parsers/commit_message_parser.py +0 -0
- {diffsage-1.2.0/src/diffsage/providers → diffsage-1.3.0/src/diffsage/prompts}/__init__.py +0 -0
- {diffsage-1.2.0/src/diffsage/services → diffsage-1.3.0/src/diffsage/providers}/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/providers/base.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/providers/factory.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/providers/gemini_provider.py +0 -0
- {diffsage-1.2.0/src/diffsage/storage → diffsage-1.3.0/src/diffsage/services}/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/config_service.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/credentials_service.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/doctor_service.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/services/editor_service.py +0 -0
- {diffsage-1.2.0/src/diffsage/ui → diffsage-1.3.0/src/diffsage/storage}/__init__.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/storage/base.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/storage/config_repository.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/storage/credentials_repository.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/ask_view.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/auth_view.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/base.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/config_view.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage/ui/doctor_view.py +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/dependency_links.txt +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/entry_points.txt +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/requires.txt +0 -0
- {diffsage-1.2.0 → diffsage-1.3.0}/src/diffsage.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffsage
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: AI-powered Git workflow assistant
|
|
5
5
|
Author: Gunitha Rathnayake
|
|
6
6
|
License: MIT
|
|
@@ -116,6 +116,10 @@ Current capabilities include:
|
|
|
116
116
|
- AI provider authentication and error handling
|
|
117
117
|
- Layered architecture
|
|
118
118
|
- Comprehensive automated test suite
|
|
119
|
+
- Add AI-assisted PR generation
|
|
120
|
+
- Interactive PR draft review/edit/regeneration
|
|
121
|
+
- GitHub PR creation
|
|
122
|
+
- Branch synchronization validation
|
|
119
123
|
|
|
120
124
|
---
|
|
121
125
|
|
|
@@ -150,18 +154,38 @@ Its scope is intentionally focused on improving Git workflows.
|
|
|
150
154
|
|
|
151
155
|
# Project Status
|
|
152
156
|
|
|
153
|
-
> **Current Stage:**
|
|
157
|
+
> **Current Stage:** Alpha
|
|
154
158
|
|
|
155
|
-
DiffSage is
|
|
159
|
+
DiffSage is an actively developed open-source project.
|
|
156
160
|
|
|
157
|
-
The project is
|
|
161
|
+
The project is published on PyPI and distributed as a Python package for
|
|
162
|
+
developers, automation, and AI agents.
|
|
158
163
|
|
|
159
|
-
The
|
|
164
|
+
The current focus is on expanding Git workflow capabilities while maintaining
|
|
165
|
+
a stable architecture, clear documentation, reliable automation, and strong
|
|
166
|
+
engineering practices.
|
|
160
167
|
|
|
161
168
|
---
|
|
162
169
|
|
|
163
170
|
# Installation
|
|
164
171
|
|
|
172
|
+
## User Installation
|
|
173
|
+
|
|
174
|
+
DiffSage is published on PyPI and can be installed using `pipx`.
|
|
175
|
+
|
|
176
|
+
DiffSage currently requires Python 3.12.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
pipx install diffsage
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
After installation verify the environment
|
|
183
|
+
```bash
|
|
184
|
+
diffsage doctor
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Developer Installation
|
|
188
|
+
|
|
165
189
|
Clone the repository:
|
|
166
190
|
|
|
167
191
|
```bash
|
|
@@ -192,9 +216,29 @@ Windows
|
|
|
192
216
|
Install the project:
|
|
193
217
|
|
|
194
218
|
```bash
|
|
195
|
-
pip install -e ".[dev]"
|
|
219
|
+
python -m pip install -e ".[dev]"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
# Releases
|
|
225
|
+
|
|
226
|
+
DiffSage releases are published through GitHub Releases and distributed through PyPI.
|
|
227
|
+
|
|
228
|
+
Released package versions can be installed directly with:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
pipx install diffsage
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
A specific version can be installed with:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
pipx install diffsage==1.2.0
|
|
196
238
|
```
|
|
197
239
|
|
|
240
|
+
Release builds and PyPI publishing are automated through GitHub Actions.
|
|
241
|
+
|
|
198
242
|
---
|
|
199
243
|
|
|
200
244
|
# Configuration
|
|
@@ -203,17 +247,18 @@ DiffSage supports layered configuration through global and repository-local TOML
|
|
|
203
247
|
|
|
204
248
|
Application configuration controls how DiffSage behaves and can be managed through global, repository-local, and environment-based configuration.
|
|
205
249
|
|
|
206
|
-
Provider credentials are managed separately from application configuration.
|
|
207
250
|
Provider credentials are managed separately from application configuration and are not part of the Settings configuration model.
|
|
208
251
|
|
|
209
252
|
```env
|
|
210
253
|
DIFFSAGE_PROVIDER=gemini
|
|
211
|
-
DIFFSAGE_AI_MODEL
|
|
254
|
+
DIFFSAGE_AI_MODEL=<provider-supported-model>
|
|
212
255
|
DIFFSAGE_LOG_LEVEL=INFO
|
|
213
256
|
DIFFSAGE_TIMEOUT=60
|
|
214
257
|
DIFFSAGE_MAX_RETRIES=3
|
|
215
258
|
```
|
|
216
259
|
|
|
260
|
+
The configured model must be supported by the selected AI provider.
|
|
261
|
+
|
|
217
262
|
Configuration can also be managed directly from the CLI:
|
|
218
263
|
|
|
219
264
|
```bash
|
|
@@ -272,10 +317,38 @@ Display AI suggestion
|
|
|
272
317
|
[N] Cancel
|
|
273
318
|
```
|
|
274
319
|
|
|
320
|
+
```bash
|
|
321
|
+
diffsage pr
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
PR workflow
|
|
325
|
+
|
|
326
|
+
```text
|
|
327
|
+
Generate PR draft
|
|
328
|
+
│
|
|
329
|
+
▼
|
|
330
|
+
Show base/head branches
|
|
331
|
+
│
|
|
332
|
+
▼
|
|
333
|
+
Display PR draft
|
|
334
|
+
│
|
|
335
|
+
┌─────┼───────────┐
|
|
336
|
+
▼ ▼ ▼
|
|
337
|
+
Edit Regenerate Cancel
|
|
338
|
+
│
|
|
339
|
+
▼
|
|
340
|
+
Accept
|
|
341
|
+
│
|
|
342
|
+
▼
|
|
343
|
+
Create GitHub PR
|
|
344
|
+
│
|
|
345
|
+
▼
|
|
346
|
+
Display PR URL
|
|
347
|
+
```
|
|
348
|
+
|
|
275
349
|
Named credential profiles are also supported:
|
|
276
350
|
|
|
277
351
|
```bash
|
|
278
|
-
|
|
279
352
|
diffsage auth set gemini YOUR_API_KEY --name paid
|
|
280
353
|
```
|
|
281
354
|
|
|
@@ -300,6 +373,8 @@ diffsage auth unset gemini
|
|
|
300
373
|
|----------|-------------|
|
|
301
374
|
| `diffsage doctor` | Validate the local DiffSage environment |
|
|
302
375
|
| `diffsage commit` | Generate and manage AI-assisted commit messages |
|
|
376
|
+
| `diffsage pr` | Generate, review, and create a GitHub pull request |
|
|
377
|
+
| `diffsage pr <base-branch>` | Generate and create a pull request against a specific base branch |
|
|
303
378
|
| `diffsage config list` | Display the current DiffSage configuration |
|
|
304
379
|
| `diffsage config get` | Display the value of a configuration setting |
|
|
305
380
|
| `diffsage config set` | Update a configuration setting |
|
|
@@ -310,7 +385,46 @@ diffsage auth unset gemini
|
|
|
310
385
|
| `diffsage auth unset` | Remove a provider credential |
|
|
311
386
|
| `diffsage ask` | Ask the configured AI provider a question |
|
|
312
387
|
|
|
313
|
-
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Pull Request Workflow
|
|
391
|
+
|
|
392
|
+
The `diffsage pr` command analyzes the current Git branch against a resolved base branch and generates a structured pull request draft.
|
|
393
|
+
|
|
394
|
+
The workflow is interactive:
|
|
395
|
+
|
|
396
|
+
```text
|
|
397
|
+
Analyze Git repository
|
|
398
|
+
│
|
|
399
|
+
▼
|
|
400
|
+
Resolve base branch
|
|
401
|
+
│
|
|
402
|
+
▼
|
|
403
|
+
Generate PR draft
|
|
404
|
+
│
|
|
405
|
+
▼
|
|
406
|
+
Display base/head branches
|
|
407
|
+
│
|
|
408
|
+
▼
|
|
409
|
+
Review PR draft
|
|
410
|
+
│
|
|
411
|
+
┌──────┼──────────────┐
|
|
412
|
+
▼ ▼ ▼
|
|
413
|
+
Edit Regenerate Cancel
|
|
414
|
+
│ │
|
|
415
|
+
└──────┴───────┐
|
|
416
|
+
▼
|
|
417
|
+
Accept
|
|
418
|
+
│
|
|
419
|
+
▼
|
|
420
|
+
Validate GitHub access
|
|
421
|
+
│
|
|
422
|
+
▼
|
|
423
|
+
Create GitHub pull request
|
|
424
|
+
│
|
|
425
|
+
▼
|
|
426
|
+
Display pull request URL
|
|
427
|
+
```
|
|
314
428
|
|
|
315
429
|
---
|
|
316
430
|
|
|
@@ -328,15 +442,22 @@ Commands
|
|
|
328
442
|
│
|
|
329
443
|
├── Authentication
|
|
330
444
|
│
|
|
331
|
-
|
|
332
|
-
Services
|
|
333
|
-
│
|
|
334
|
-
├── Git
|
|
335
|
-
├── AI
|
|
336
|
-
├── Prompt Generation
|
|
337
|
-
└── Credentials
|
|
445
|
+
├── Commit Workflow
|
|
338
446
|
│
|
|
339
|
-
|
|
447
|
+
└── Pull Request Workflow
|
|
448
|
+
│
|
|
449
|
+
▼
|
|
450
|
+
Services
|
|
451
|
+
│
|
|
452
|
+
├── Git
|
|
453
|
+
├── GitHub
|
|
454
|
+
├── AI
|
|
455
|
+
├── Prompt Generation
|
|
456
|
+
├── Pull Request Analysis
|
|
457
|
+
├── Pull Request Parsing
|
|
458
|
+
└── Credentials
|
|
459
|
+
│
|
|
460
|
+
▼
|
|
340
461
|
Providers / Storage
|
|
341
462
|
```
|
|
342
463
|
|
|
@@ -362,6 +483,7 @@ src/
|
|
|
362
483
|
├── config/
|
|
363
484
|
├── exceptions/
|
|
364
485
|
├── git/
|
|
486
|
+
├── github/
|
|
365
487
|
├── logging/
|
|
366
488
|
├── models/
|
|
367
489
|
├── parsers/
|
|
@@ -372,6 +494,18 @@ src/
|
|
|
372
494
|
└── ui/
|
|
373
495
|
|
|
374
496
|
tests/
|
|
497
|
+
├── commands/
|
|
498
|
+
├── config/
|
|
499
|
+
├── git/
|
|
500
|
+
├── github/
|
|
501
|
+
├── integration/
|
|
502
|
+
├── models/
|
|
503
|
+
├── parsers/
|
|
504
|
+
├── prompts/
|
|
505
|
+
├── providers/
|
|
506
|
+
├── services/
|
|
507
|
+
├── storage/
|
|
508
|
+
└── ui/
|
|
375
509
|
|
|
376
510
|
docs/
|
|
377
511
|
```
|
|
@@ -390,10 +524,6 @@ Additional project documentation is available within the repository.
|
|
|
390
524
|
| `docs/changelog.md` | Project changes and milestones |
|
|
391
525
|
| `docs/adrs/ADR-*` | Architecture Decision Records (ADRs) |
|
|
392
526
|
|
|
393
|
-
Future documentation will include:
|
|
394
|
-
|
|
395
|
-
- Contributing Guide
|
|
396
|
-
|
|
397
527
|
---
|
|
398
528
|
|
|
399
529
|
# Roadmap
|
|
@@ -424,6 +554,7 @@ Instead of requiring every automation tool or AI agent to implement Git workflow
|
|
|
424
554
|
|
|
425
555
|
- Repository validation
|
|
426
556
|
- Git operations
|
|
557
|
+
- GitHub integration
|
|
427
558
|
- AI integration
|
|
428
559
|
- Workflow execution
|
|
429
560
|
- Error handling
|
|
@@ -452,15 +583,11 @@ Features that fall outside these principles intentionally remain out of scope.
|
|
|
452
583
|
|
|
453
584
|
# Contributing
|
|
454
585
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
Future contributors will be encouraged to review:
|
|
586
|
+
DiffSage is an open-source project and contributions are welcome.
|
|
458
587
|
|
|
459
|
-
|
|
460
|
-
- Coding conventions
|
|
461
|
-
- ADRs
|
|
588
|
+
Before contributing, review the project architecture, coding conventions, and architectural decision records in the `docs/` directory.
|
|
462
589
|
|
|
463
|
-
|
|
590
|
+
Additional contribution guidelines will be documented as the project evolves.
|
|
464
591
|
|
|
465
592
|
---
|
|
466
593
|
|
|
@@ -77,6 +77,10 @@ Current capabilities include:
|
|
|
77
77
|
- AI provider authentication and error handling
|
|
78
78
|
- Layered architecture
|
|
79
79
|
- Comprehensive automated test suite
|
|
80
|
+
- Add AI-assisted PR generation
|
|
81
|
+
- Interactive PR draft review/edit/regeneration
|
|
82
|
+
- GitHub PR creation
|
|
83
|
+
- Branch synchronization validation
|
|
80
84
|
|
|
81
85
|
---
|
|
82
86
|
|
|
@@ -111,18 +115,38 @@ Its scope is intentionally focused on improving Git workflows.
|
|
|
111
115
|
|
|
112
116
|
# Project Status
|
|
113
117
|
|
|
114
|
-
> **Current Stage:**
|
|
118
|
+
> **Current Stage:** Alpha
|
|
115
119
|
|
|
116
|
-
DiffSage is
|
|
120
|
+
DiffSage is an actively developed open-source project.
|
|
117
121
|
|
|
118
|
-
The project is
|
|
122
|
+
The project is published on PyPI and distributed as a Python package for
|
|
123
|
+
developers, automation, and AI agents.
|
|
119
124
|
|
|
120
|
-
The
|
|
125
|
+
The current focus is on expanding Git workflow capabilities while maintaining
|
|
126
|
+
a stable architecture, clear documentation, reliable automation, and strong
|
|
127
|
+
engineering practices.
|
|
121
128
|
|
|
122
129
|
---
|
|
123
130
|
|
|
124
131
|
# Installation
|
|
125
132
|
|
|
133
|
+
## User Installation
|
|
134
|
+
|
|
135
|
+
DiffSage is published on PyPI and can be installed using `pipx`.
|
|
136
|
+
|
|
137
|
+
DiffSage currently requires Python 3.12.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
pipx install diffsage
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
After installation verify the environment
|
|
144
|
+
```bash
|
|
145
|
+
diffsage doctor
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Developer Installation
|
|
149
|
+
|
|
126
150
|
Clone the repository:
|
|
127
151
|
|
|
128
152
|
```bash
|
|
@@ -153,9 +177,29 @@ Windows
|
|
|
153
177
|
Install the project:
|
|
154
178
|
|
|
155
179
|
```bash
|
|
156
|
-
pip install -e ".[dev]"
|
|
180
|
+
python -m pip install -e ".[dev]"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
# Releases
|
|
186
|
+
|
|
187
|
+
DiffSage releases are published through GitHub Releases and distributed through PyPI.
|
|
188
|
+
|
|
189
|
+
Released package versions can be installed directly with:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pipx install diffsage
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
A specific version can be installed with:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pipx install diffsage==1.2.0
|
|
157
199
|
```
|
|
158
200
|
|
|
201
|
+
Release builds and PyPI publishing are automated through GitHub Actions.
|
|
202
|
+
|
|
159
203
|
---
|
|
160
204
|
|
|
161
205
|
# Configuration
|
|
@@ -164,17 +208,18 @@ DiffSage supports layered configuration through global and repository-local TOML
|
|
|
164
208
|
|
|
165
209
|
Application configuration controls how DiffSage behaves and can be managed through global, repository-local, and environment-based configuration.
|
|
166
210
|
|
|
167
|
-
Provider credentials are managed separately from application configuration.
|
|
168
211
|
Provider credentials are managed separately from application configuration and are not part of the Settings configuration model.
|
|
169
212
|
|
|
170
213
|
```env
|
|
171
214
|
DIFFSAGE_PROVIDER=gemini
|
|
172
|
-
DIFFSAGE_AI_MODEL
|
|
215
|
+
DIFFSAGE_AI_MODEL=<provider-supported-model>
|
|
173
216
|
DIFFSAGE_LOG_LEVEL=INFO
|
|
174
217
|
DIFFSAGE_TIMEOUT=60
|
|
175
218
|
DIFFSAGE_MAX_RETRIES=3
|
|
176
219
|
```
|
|
177
220
|
|
|
221
|
+
The configured model must be supported by the selected AI provider.
|
|
222
|
+
|
|
178
223
|
Configuration can also be managed directly from the CLI:
|
|
179
224
|
|
|
180
225
|
```bash
|
|
@@ -233,10 +278,38 @@ Display AI suggestion
|
|
|
233
278
|
[N] Cancel
|
|
234
279
|
```
|
|
235
280
|
|
|
281
|
+
```bash
|
|
282
|
+
diffsage pr
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
PR workflow
|
|
286
|
+
|
|
287
|
+
```text
|
|
288
|
+
Generate PR draft
|
|
289
|
+
│
|
|
290
|
+
▼
|
|
291
|
+
Show base/head branches
|
|
292
|
+
│
|
|
293
|
+
▼
|
|
294
|
+
Display PR draft
|
|
295
|
+
│
|
|
296
|
+
┌─────┼───────────┐
|
|
297
|
+
▼ ▼ ▼
|
|
298
|
+
Edit Regenerate Cancel
|
|
299
|
+
│
|
|
300
|
+
▼
|
|
301
|
+
Accept
|
|
302
|
+
│
|
|
303
|
+
▼
|
|
304
|
+
Create GitHub PR
|
|
305
|
+
│
|
|
306
|
+
▼
|
|
307
|
+
Display PR URL
|
|
308
|
+
```
|
|
309
|
+
|
|
236
310
|
Named credential profiles are also supported:
|
|
237
311
|
|
|
238
312
|
```bash
|
|
239
|
-
|
|
240
313
|
diffsage auth set gemini YOUR_API_KEY --name paid
|
|
241
314
|
```
|
|
242
315
|
|
|
@@ -261,6 +334,8 @@ diffsage auth unset gemini
|
|
|
261
334
|
|----------|-------------|
|
|
262
335
|
| `diffsage doctor` | Validate the local DiffSage environment |
|
|
263
336
|
| `diffsage commit` | Generate and manage AI-assisted commit messages |
|
|
337
|
+
| `diffsage pr` | Generate, review, and create a GitHub pull request |
|
|
338
|
+
| `diffsage pr <base-branch>` | Generate and create a pull request against a specific base branch |
|
|
264
339
|
| `diffsage config list` | Display the current DiffSage configuration |
|
|
265
340
|
| `diffsage config get` | Display the value of a configuration setting |
|
|
266
341
|
| `diffsage config set` | Update a configuration setting |
|
|
@@ -271,7 +346,46 @@ diffsage auth unset gemini
|
|
|
271
346
|
| `diffsage auth unset` | Remove a provider credential |
|
|
272
347
|
| `diffsage ask` | Ask the configured AI provider a question |
|
|
273
348
|
|
|
274
|
-
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Pull Request Workflow
|
|
352
|
+
|
|
353
|
+
The `diffsage pr` command analyzes the current Git branch against a resolved base branch and generates a structured pull request draft.
|
|
354
|
+
|
|
355
|
+
The workflow is interactive:
|
|
356
|
+
|
|
357
|
+
```text
|
|
358
|
+
Analyze Git repository
|
|
359
|
+
│
|
|
360
|
+
▼
|
|
361
|
+
Resolve base branch
|
|
362
|
+
│
|
|
363
|
+
▼
|
|
364
|
+
Generate PR draft
|
|
365
|
+
│
|
|
366
|
+
▼
|
|
367
|
+
Display base/head branches
|
|
368
|
+
│
|
|
369
|
+
▼
|
|
370
|
+
Review PR draft
|
|
371
|
+
│
|
|
372
|
+
┌──────┼──────────────┐
|
|
373
|
+
▼ ▼ ▼
|
|
374
|
+
Edit Regenerate Cancel
|
|
375
|
+
│ │
|
|
376
|
+
└──────┴───────┐
|
|
377
|
+
▼
|
|
378
|
+
Accept
|
|
379
|
+
│
|
|
380
|
+
▼
|
|
381
|
+
Validate GitHub access
|
|
382
|
+
│
|
|
383
|
+
▼
|
|
384
|
+
Create GitHub pull request
|
|
385
|
+
│
|
|
386
|
+
▼
|
|
387
|
+
Display pull request URL
|
|
388
|
+
```
|
|
275
389
|
|
|
276
390
|
---
|
|
277
391
|
|
|
@@ -289,15 +403,22 @@ Commands
|
|
|
289
403
|
│
|
|
290
404
|
├── Authentication
|
|
291
405
|
│
|
|
292
|
-
|
|
293
|
-
Services
|
|
294
|
-
│
|
|
295
|
-
├── Git
|
|
296
|
-
├── AI
|
|
297
|
-
├── Prompt Generation
|
|
298
|
-
└── Credentials
|
|
406
|
+
├── Commit Workflow
|
|
299
407
|
│
|
|
300
|
-
|
|
408
|
+
└── Pull Request Workflow
|
|
409
|
+
│
|
|
410
|
+
▼
|
|
411
|
+
Services
|
|
412
|
+
│
|
|
413
|
+
├── Git
|
|
414
|
+
├── GitHub
|
|
415
|
+
├── AI
|
|
416
|
+
├── Prompt Generation
|
|
417
|
+
├── Pull Request Analysis
|
|
418
|
+
├── Pull Request Parsing
|
|
419
|
+
└── Credentials
|
|
420
|
+
│
|
|
421
|
+
▼
|
|
301
422
|
Providers / Storage
|
|
302
423
|
```
|
|
303
424
|
|
|
@@ -323,6 +444,7 @@ src/
|
|
|
323
444
|
├── config/
|
|
324
445
|
├── exceptions/
|
|
325
446
|
├── git/
|
|
447
|
+
├── github/
|
|
326
448
|
├── logging/
|
|
327
449
|
├── models/
|
|
328
450
|
├── parsers/
|
|
@@ -333,6 +455,18 @@ src/
|
|
|
333
455
|
└── ui/
|
|
334
456
|
|
|
335
457
|
tests/
|
|
458
|
+
├── commands/
|
|
459
|
+
├── config/
|
|
460
|
+
├── git/
|
|
461
|
+
├── github/
|
|
462
|
+
├── integration/
|
|
463
|
+
├── models/
|
|
464
|
+
├── parsers/
|
|
465
|
+
├── prompts/
|
|
466
|
+
├── providers/
|
|
467
|
+
├── services/
|
|
468
|
+
├── storage/
|
|
469
|
+
└── ui/
|
|
336
470
|
|
|
337
471
|
docs/
|
|
338
472
|
```
|
|
@@ -351,10 +485,6 @@ Additional project documentation is available within the repository.
|
|
|
351
485
|
| `docs/changelog.md` | Project changes and milestones |
|
|
352
486
|
| `docs/adrs/ADR-*` | Architecture Decision Records (ADRs) |
|
|
353
487
|
|
|
354
|
-
Future documentation will include:
|
|
355
|
-
|
|
356
|
-
- Contributing Guide
|
|
357
|
-
|
|
358
488
|
---
|
|
359
489
|
|
|
360
490
|
# Roadmap
|
|
@@ -385,6 +515,7 @@ Instead of requiring every automation tool or AI agent to implement Git workflow
|
|
|
385
515
|
|
|
386
516
|
- Repository validation
|
|
387
517
|
- Git operations
|
|
518
|
+
- GitHub integration
|
|
388
519
|
- AI integration
|
|
389
520
|
- Workflow execution
|
|
390
521
|
- Error handling
|
|
@@ -413,15 +544,11 @@ Features that fall outside these principles intentionally remain out of scope.
|
|
|
413
544
|
|
|
414
545
|
# Contributing
|
|
415
546
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
Future contributors will be encouraged to review:
|
|
547
|
+
DiffSage is an open-source project and contributions are welcome.
|
|
419
548
|
|
|
420
|
-
|
|
421
|
-
- Coding conventions
|
|
422
|
-
- ADRs
|
|
549
|
+
Before contributing, review the project architecture, coding conventions, and architectural decision records in the `docs/` directory.
|
|
423
550
|
|
|
424
|
-
|
|
551
|
+
Additional contribution guidelines will be documented as the project evolves.
|
|
425
552
|
|
|
426
553
|
---
|
|
427
554
|
|
|
@@ -7,6 +7,7 @@ from diffsage.commands.auth import app as auth_app
|
|
|
7
7
|
from diffsage.commands.commit import commit
|
|
8
8
|
from diffsage.commands.config import app as config_app
|
|
9
9
|
from diffsage.commands.doctor import doctor
|
|
10
|
+
from diffsage.commands.pr import pr
|
|
10
11
|
from diffsage.config.loader import load_settings
|
|
11
12
|
from diffsage.logging.logger import configure_logging
|
|
12
13
|
|
|
@@ -31,8 +32,13 @@ def main() -> None:
|
|
|
31
32
|
app.command()(doctor)
|
|
32
33
|
app.command()(ask)
|
|
33
34
|
app.command()(commit)
|
|
35
|
+
app.command()(pr)
|
|
36
|
+
|
|
34
37
|
app.add_typer(
|
|
35
38
|
config_app,
|
|
36
39
|
name="config",
|
|
37
40
|
)
|
|
38
|
-
app.add_typer(
|
|
41
|
+
app.add_typer(
|
|
42
|
+
auth_app,
|
|
43
|
+
name="auth",
|
|
44
|
+
)
|
|
@@ -4,6 +4,7 @@ from diffsage.exceptions import (
|
|
|
4
4
|
AuthenticationError,
|
|
5
5
|
ConfigError,
|
|
6
6
|
CredentialNotFoundError,
|
|
7
|
+
ModelNotFoundError,
|
|
7
8
|
ProviderUnavailableError,
|
|
8
9
|
)
|
|
9
10
|
from diffsage.logging.logger import get_logger
|
|
@@ -46,6 +47,11 @@ def ask(prompt: str) -> None:
|
|
|
46
47
|
view.show_error(str(e))
|
|
47
48
|
raise SystemExit(1) from None
|
|
48
49
|
|
|
50
|
+
except ModelNotFoundError as e:
|
|
51
|
+
logger.warning(str(e))
|
|
52
|
+
view.show_error(str(e))
|
|
53
|
+
raise SystemExit(1) from None
|
|
54
|
+
|
|
49
55
|
except ProviderUnavailableError as e:
|
|
50
56
|
logger.warning(str(e))
|
|
51
57
|
view.show_error(str(e))
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
1
3
|
from diffsage.config.loader import load_settings
|
|
2
4
|
from diffsage.config.paths import get_credentials_path
|
|
3
5
|
from diffsage.exceptions import (
|
|
@@ -22,8 +24,13 @@ from diffsage.ui.commit_view import CommitView
|
|
|
22
24
|
logger = get_logger(__name__)
|
|
23
25
|
|
|
24
26
|
|
|
25
|
-
def generate_message(
|
|
26
|
-
|
|
27
|
+
def generate_message(
|
|
28
|
+
commit_service: CommitService,
|
|
29
|
+
on_attempt: Callable[[int, int], None] | None = None,
|
|
30
|
+
) -> str:
|
|
31
|
+
return commit_service.generate_commit_message(
|
|
32
|
+
on_attempt=on_attempt,
|
|
33
|
+
)
|
|
27
34
|
|
|
28
35
|
|
|
29
36
|
def commit() -> None:
|
|
@@ -54,8 +61,13 @@ def commit() -> None:
|
|
|
54
61
|
ai_service,
|
|
55
62
|
)
|
|
56
63
|
|
|
57
|
-
with view.generating():
|
|
58
|
-
raw_message = generate_message(
|
|
64
|
+
with view.generating() as status:
|
|
65
|
+
raw_message = generate_message(
|
|
66
|
+
commit_service,
|
|
67
|
+
on_attempt=lambda attempt, total: status.update(
|
|
68
|
+
f"Generating commit message... Attempt {attempt}/{total}"
|
|
69
|
+
),
|
|
70
|
+
)
|
|
59
71
|
commit_message = CommitMessageParser.parse(raw_message)
|
|
60
72
|
|
|
61
73
|
view.show_generated()
|
|
@@ -79,8 +91,13 @@ def commit() -> None:
|
|
|
79
91
|
|
|
80
92
|
if choice == "r":
|
|
81
93
|
logger.info("User selected regenerate.")
|
|
82
|
-
with view.generating():
|
|
83
|
-
raw_message = generate_message(
|
|
94
|
+
with view.generating() as status:
|
|
95
|
+
raw_message = generate_message(
|
|
96
|
+
commit_service,
|
|
97
|
+
on_attempt=lambda attempt, total: status.update(
|
|
98
|
+
f"Generating commit message... Attempt {attempt}/{total}"
|
|
99
|
+
),
|
|
100
|
+
)
|
|
84
101
|
commit_message = CommitMessageParser.parse(raw_message)
|
|
85
102
|
|
|
86
103
|
view.show_generated()
|