diffron 0.1.0__tar.gz → 0.1.2__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.
- {diffron-0.1.0 → diffron-0.1.2}/MANIFEST.in +17 -19
- {diffron-0.1.0/diffron.egg-info → diffron-0.1.2}/PKG-INFO +8 -8
- {diffron-0.1.0 → diffron-0.1.2}/README.md +7 -7
- {diffron-0.1.0 → diffron-0.1.2}/diffron/git_hooks.py +1 -1
- diffron-0.1.2/diffron/hooks/prepare-commit-msg +13 -0
- diffron-0.1.2/diffron/hooks/prepare-commit-msg-global.py +59 -0
- diffron-0.1.2/diffron/hooks/prepare-commit-msg.py +101 -0
- {diffron-0.1.0 → diffron-0.1.2/diffron.egg-info}/PKG-INFO +8 -8
- {diffron-0.1.0 → diffron-0.1.2}/diffron.egg-info/SOURCES.txt +7 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron.egg-info/top_level.txt +1 -0
- {diffron-0.1.0 → diffron-0.1.2}/docs/HOOKS.md +109 -7
- {diffron-0.1.0 → diffron-0.1.2}/docs/SETUP.md +1 -1
- diffron-0.1.2/hooks/aipr.py +96 -0
- diffron-0.1.2/hooks/prepare-commit-msg +13 -0
- diffron-0.1.2/hooks/prepare-commit-msg-global.py +59 -0
- diffron-0.1.2/hooks/prepare-commit-msg.py +101 -0
- {diffron-0.1.0 → diffron-0.1.2}/pyproject.toml +3 -2
- {diffron-0.1.0 → diffron-0.1.2}/setup.py +64 -64
- {diffron-0.1.0 → diffron-0.1.2}/CHANGELOG.md +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/LICENSE +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/__init__.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/__init__.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/cli.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/cli.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/client.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/client.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/commit_gen.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/commit_gen.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/git_hooks.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2/diffron}/hooks/aipr.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/lemonade.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/lemonade.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/pr_gen.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/pr_gen.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/py.typed +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/utils.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron/utils.pyi +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron.egg-info/dependency_links.txt +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron.egg-info/entry_points.txt +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/diffron.egg-info/requires.txt +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/docs/PLAN.md +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/docs/PYPI_RELEASE.md +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/docs/USAGE.md +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/requirements.txt +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/setup.cfg +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/tests/test_commit_gen.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/tests/test_git_hooks.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/tests/test_lemonade.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/tests/test_pr_gen.py +0 -0
- {diffron-0.1.0 → diffron-0.1.2}/tests/test_utils.py +0 -0
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
include LICENSE
|
|
2
|
-
include README.md
|
|
3
|
-
include CHANGELOG.md
|
|
4
|
-
include requirements.txt
|
|
5
|
-
include pyproject.toml
|
|
6
|
-
|
|
7
|
-
recursive-include diffron *.py *.pyi py.typed
|
|
8
|
-
recursive-include
|
|
9
|
-
recursive-include
|
|
10
|
-
|
|
11
|
-
exclude tests
|
|
12
|
-
exclude hooks
|
|
13
|
-
exclude
|
|
14
|
-
exclude
|
|
15
|
-
exclude
|
|
16
|
-
exclude
|
|
17
|
-
exclude
|
|
18
|
-
exclude .gitignore
|
|
19
|
-
exclude .sorana
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include requirements.txt
|
|
5
|
+
include pyproject.toml
|
|
6
|
+
|
|
7
|
+
recursive-include diffron *.py *.pyi py.typed
|
|
8
|
+
recursive-include diffron/hooks *
|
|
9
|
+
recursive-include docs *.md
|
|
10
|
+
|
|
11
|
+
exclude tests
|
|
12
|
+
exclude hooks
|
|
13
|
+
exclude *.bat
|
|
14
|
+
exclude *.code-workspace
|
|
15
|
+
exclude sync-*.txt
|
|
16
|
+
exclude .gitignore
|
|
17
|
+
exclude .sorana
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffron
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Git commit message and PR description generator using Lemonade
|
|
5
5
|
Home-page: https://github.com/diffron/diffron
|
|
6
6
|
Author: Diffron Contributors
|
|
@@ -45,7 +45,7 @@ Dynamic: requires-python
|
|
|
45
45
|
|
|
46
46
|
Git commit message and PR description generator using AMD Lemonade via lemonade-python-sdk.
|
|
47
47
|
|
|
48
|
-
**
|
|
48
|
+
**Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
|
|
49
49
|
|
|
50
50
|

|
|
51
51
|

|
|
@@ -243,12 +243,12 @@ client = DiffronClient(model="your-model-name")
|
|
|
243
243
|
|
|
244
244
|
| Project | Description |
|
|
245
245
|
|---------|-------------|
|
|
246
|
-
| **lemonade-python-sdk** | 🍋 **AMD Lemonade Challenge Submission** - Python SDK for AMD Lemonade API |
|
|
247
|
-
| **Diffron** |
|
|
248
|
-
| **Aicono** | AI Assistant (Desktop App) |
|
|
249
|
-
| **TabNeuron** | Browser Connector / Memory |
|
|
250
|
-
| **Sorana** | Advanced AI Interface |
|
|
251
|
-
| **
|
|
246
|
+
| [**lemonade-python-sdk**](https://github.com/Tetramatrix/lemonade-python-sdk) | 🍋 **AMD Lemonade Challenge Submission** - Python SDK for AMD Lemonade API |
|
|
247
|
+
| [**Diffron**](https://pypi.org/project/diffron/) | Production-ready reference implementation using lemonade-python-sdk (this repo) |
|
|
248
|
+
| [**Aicono**](https://tetramatrix.github.io/Aicono/) | AI Assistant (Desktop App) |
|
|
249
|
+
| [**TabNeuron**](https://tetramatrix.github.io/TabNeuron/) | Browser Connector / Memory |
|
|
250
|
+
| [**Sorana**](https://tetramatrix.github.io/Sorana/) | Advanced AI Interface |
|
|
251
|
+
| [**RyzenZPilot**](https://tetramatrix.github.io/RyzenZPilot/) | Hardware Optimization |
|
|
252
252
|
|
|
253
253
|
**Note:** Lemonade is AMD's local LLM server for Ryzen AI PCs. Diffron uses `lemonade-python-sdk` to communicate with Lemonade's API.
|
|
254
254
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Git commit message and PR description generator using AMD Lemonade via lemonade-python-sdk.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|

|
|
@@ -200,12 +200,12 @@ client = DiffronClient(model="your-model-name")
|
|
|
200
200
|
|
|
201
201
|
| Project | Description |
|
|
202
202
|
|---------|-------------|
|
|
203
|
-
| **lemonade-python-sdk** | 🍋 **AMD Lemonade Challenge Submission** - Python SDK for AMD Lemonade API |
|
|
204
|
-
| **Diffron** |
|
|
205
|
-
| **Aicono** | AI Assistant (Desktop App) |
|
|
206
|
-
| **TabNeuron** | Browser Connector / Memory |
|
|
207
|
-
| **Sorana** | Advanced AI Interface |
|
|
208
|
-
| **
|
|
203
|
+
| [**lemonade-python-sdk**](https://github.com/Tetramatrix/lemonade-python-sdk) | 🍋 **AMD Lemonade Challenge Submission** - Python SDK for AMD Lemonade API |
|
|
204
|
+
| [**Diffron**](https://pypi.org/project/diffron/) | Production-ready reference implementation using lemonade-python-sdk (this repo) |
|
|
205
|
+
| [**Aicono**](https://tetramatrix.github.io/Aicono/) | AI Assistant (Desktop App) |
|
|
206
|
+
| [**TabNeuron**](https://tetramatrix.github.io/TabNeuron/) | Browser Connector / Memory |
|
|
207
|
+
| [**Sorana**](https://tetramatrix.github.io/Sorana/) | Advanced AI Interface |
|
|
208
|
+
| [**RyzenZPilot**](https://tetramatrix.github.io/RyzenZPilot/) | Hardware Optimization |
|
|
209
209
|
|
|
210
210
|
**Note:** Lemonade is AMD's local LLM server for Ryzen AI PCs. Diffron uses `lemonade-python-sdk` to communicate with Lemonade's API.
|
|
211
211
|
|
|
@@ -19,7 +19,7 @@ PYTHON_HOOK_NAME = "prepare-commit-msg.py"
|
|
|
19
19
|
|
|
20
20
|
# Get the hooks directory (where the template hooks are stored)
|
|
21
21
|
DIFFRON_PACKAGE_DIR = Path(__file__).parent
|
|
22
|
-
HOOKS_TEMPLATE_DIR = DIFFRON_PACKAGE_DIR
|
|
22
|
+
HOOKS_TEMPLATE_DIR = DIFFRON_PACKAGE_DIR / "hooks"
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def install_hooks(
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Diffron prepare-commit-msg hook wrapper for Windows (Git Bash)
|
|
3
|
+
# This file should be placed in .git/hooks/prepare-commit-msg (no extension)
|
|
4
|
+
|
|
5
|
+
# Get the directory where this wrapper script is located (Unix-style path)
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
7
|
+
|
|
8
|
+
# Convert Unix path to Windows path for Python using cygpath
|
|
9
|
+
# Git Bash on Windows uses /d/... but Windows needs D:\...
|
|
10
|
+
PYTHON_SCRIPT="$(cygpath -w "$SCRIPT_DIR/prepare-commit-msg.py" 2>/dev/null || echo "$SCRIPT_DIR/prepare-commit-msg.py")"
|
|
11
|
+
|
|
12
|
+
# Run the Python script
|
|
13
|
+
python "$PYTHON_SCRIPT" "$1" "$2"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Diffron prepare-commit-msg Git hook.
|
|
4
|
+
|
|
5
|
+
Automatically generates commit messages using Lemonade LLM.
|
|
6
|
+
Installed globally by Diffron.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
# Import diffron from installed package (no path manipulation needed)
|
|
13
|
+
from diffron.commit_gen import generate_commit_message
|
|
14
|
+
from diffron.lemonade import is_lemonade_running
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
"""Main hook entry point."""
|
|
19
|
+
# Parse arguments
|
|
20
|
+
if len(sys.argv) < 2:
|
|
21
|
+
print("Error: Missing commit message file argument", file=sys.stderr)
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
commit_msg_file = sys.argv[1]
|
|
25
|
+
commit_source = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
26
|
+
|
|
27
|
+
# Skip for merges, rebases, and amend commits
|
|
28
|
+
skip_sources = {"merge", "squash", "commit"}
|
|
29
|
+
if commit_source in skip_sources:
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
# Check if Lemonade is running
|
|
33
|
+
if not is_lemonade_running():
|
|
34
|
+
# Silently exit if Lemonade not running - let user commit manually
|
|
35
|
+
sys.exit(0)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
# Generate commit message
|
|
39
|
+
commit_message = generate_commit_message()
|
|
40
|
+
|
|
41
|
+
if commit_message:
|
|
42
|
+
# Write to commit message file
|
|
43
|
+
with open(commit_msg_file, "w", encoding="utf-8") as f:
|
|
44
|
+
f.write(commit_message)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
# Log error but don't block commit
|
|
47
|
+
error_msg = f"# Diffron error: {e}\n"
|
|
48
|
+
try:
|
|
49
|
+
with open(commit_msg_file, "a", encoding="utf-8") as f:
|
|
50
|
+
f.write(error_msg)
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
sys.exit(0) # Don't block commit on error
|
|
54
|
+
|
|
55
|
+
sys.exit(0)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
main()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Diffron prepare-commit-msg Git hook.
|
|
4
|
+
|
|
5
|
+
Automatically generates commit messages using Lemonade LLM.
|
|
6
|
+
Installed globally by Diffron.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
import urllib.request
|
|
12
|
+
import urllib.error
|
|
13
|
+
|
|
14
|
+
# Import diffron from installed package (no path manipulation needed)
|
|
15
|
+
from diffron.commit_gen import generate_commit_message
|
|
16
|
+
from diffron.lemonade import get_lemonade_url
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def is_lemonade_api_responsive(url: str, timeout: float = 10.0) -> bool:
|
|
20
|
+
"""
|
|
21
|
+
Check if Lemonade API actually responds (not just port open).
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
url: Lemonade server URL.
|
|
25
|
+
timeout: Request timeout in seconds (10s to allow for slow startup).
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
True if API responds successfully.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
# Try /api/v1/models endpoint
|
|
32
|
+
models_url = f"{url}/api/v1/models"
|
|
33
|
+
req = urllib.request.Request(models_url)
|
|
34
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
35
|
+
if response.status == 200:
|
|
36
|
+
return True
|
|
37
|
+
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
# Fallback: try root endpoint
|
|
41
|
+
try:
|
|
42
|
+
req = urllib.request.Request(url)
|
|
43
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
44
|
+
return response.status == 200
|
|
45
|
+
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main():
|
|
52
|
+
"""Main hook entry point."""
|
|
53
|
+
# Parse arguments
|
|
54
|
+
if len(sys.argv) < 2:
|
|
55
|
+
print("Error: Missing commit message file argument", file=sys.stderr)
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
|
|
58
|
+
commit_msg_file = sys.argv[1]
|
|
59
|
+
commit_source = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
60
|
+
|
|
61
|
+
# Skip for merges, rebases, and amend commits
|
|
62
|
+
skip_sources = {"merge", "squash", "commit"}
|
|
63
|
+
if commit_source in skip_sources:
|
|
64
|
+
sys.exit(0)
|
|
65
|
+
|
|
66
|
+
# Change to the repository directory (where git commit was run)
|
|
67
|
+
repo_dir = os.path.dirname(os.path.abspath(commit_msg_file))
|
|
68
|
+
# Navigate up from .git/COMMIT_EDITMSG to repo root
|
|
69
|
+
if os.path.basename(repo_dir) == ".git":
|
|
70
|
+
repo_dir = os.path.dirname(repo_dir)
|
|
71
|
+
os.chdir(repo_dir)
|
|
72
|
+
|
|
73
|
+
# Get Lemonade URL and check if API is actually responsive
|
|
74
|
+
lemonade_url = get_lemonade_url()
|
|
75
|
+
if not is_lemonade_api_responsive(lemonade_url):
|
|
76
|
+
# Silently exit if Lemonade not responding - let user commit manually
|
|
77
|
+
sys.exit(0)
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
# Generate commit message
|
|
81
|
+
commit_message = generate_commit_message()
|
|
82
|
+
|
|
83
|
+
if commit_message:
|
|
84
|
+
# Write to commit message file
|
|
85
|
+
with open(commit_msg_file, "w", encoding="utf-8") as f:
|
|
86
|
+
f.write(commit_message)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
# Log error but don't block commit
|
|
89
|
+
error_msg = f"# Diffron error: {e}\n"
|
|
90
|
+
try:
|
|
91
|
+
with open(commit_msg_file, "a", encoding="utf-8") as f:
|
|
92
|
+
f.write(error_msg)
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
sys.exit(0) # Don't block commit on error
|
|
96
|
+
|
|
97
|
+
sys.exit(0)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffron
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Git commit message and PR description generator using Lemonade
|
|
5
5
|
Home-page: https://github.com/diffron/diffron
|
|
6
6
|
Author: Diffron Contributors
|
|
@@ -45,7 +45,7 @@ Dynamic: requires-python
|
|
|
45
45
|
|
|
46
46
|
Git commit message and PR description generator using AMD Lemonade via lemonade-python-sdk.
|
|
47
47
|
|
|
48
|
-
**
|
|
48
|
+
**Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
|
|
49
49
|
|
|
50
50
|

|
|
51
51
|

|
|
@@ -243,12 +243,12 @@ client = DiffronClient(model="your-model-name")
|
|
|
243
243
|
|
|
244
244
|
| Project | Description |
|
|
245
245
|
|---------|-------------|
|
|
246
|
-
| **lemonade-python-sdk** | 🍋 **AMD Lemonade Challenge Submission** - Python SDK for AMD Lemonade API |
|
|
247
|
-
| **Diffron** |
|
|
248
|
-
| **Aicono** | AI Assistant (Desktop App) |
|
|
249
|
-
| **TabNeuron** | Browser Connector / Memory |
|
|
250
|
-
| **Sorana** | Advanced AI Interface |
|
|
251
|
-
| **
|
|
246
|
+
| [**lemonade-python-sdk**](https://github.com/Tetramatrix/lemonade-python-sdk) | 🍋 **AMD Lemonade Challenge Submission** - Python SDK for AMD Lemonade API |
|
|
247
|
+
| [**Diffron**](https://pypi.org/project/diffron/) | Production-ready reference implementation using lemonade-python-sdk (this repo) |
|
|
248
|
+
| [**Aicono**](https://tetramatrix.github.io/Aicono/) | AI Assistant (Desktop App) |
|
|
249
|
+
| [**TabNeuron**](https://tetramatrix.github.io/TabNeuron/) | Browser Connector / Memory |
|
|
250
|
+
| [**Sorana**](https://tetramatrix.github.io/Sorana/) | Advanced AI Interface |
|
|
251
|
+
| [**RyzenZPilot**](https://tetramatrix.github.io/RyzenZPilot/) | Hardware Optimization |
|
|
252
252
|
|
|
253
253
|
**Note:** Lemonade is AMD's local LLM server for Ryzen AI PCs. Diffron uses `lemonade-python-sdk` to communicate with Lemonade's API.
|
|
254
254
|
|
|
@@ -28,12 +28,19 @@ diffron.egg-info/dependency_links.txt
|
|
|
28
28
|
diffron.egg-info/entry_points.txt
|
|
29
29
|
diffron.egg-info/requires.txt
|
|
30
30
|
diffron.egg-info/top_level.txt
|
|
31
|
+
diffron/hooks/aipr.py
|
|
32
|
+
diffron/hooks/prepare-commit-msg
|
|
33
|
+
diffron/hooks/prepare-commit-msg-global.py
|
|
34
|
+
diffron/hooks/prepare-commit-msg.py
|
|
31
35
|
docs/HOOKS.md
|
|
32
36
|
docs/PLAN.md
|
|
33
37
|
docs/PYPI_RELEASE.md
|
|
34
38
|
docs/SETUP.md
|
|
35
39
|
docs/USAGE.md
|
|
36
40
|
hooks/aipr.py
|
|
41
|
+
hooks/prepare-commit-msg
|
|
42
|
+
hooks/prepare-commit-msg-global.py
|
|
43
|
+
hooks/prepare-commit-msg.py
|
|
37
44
|
tests/test_commit_gen.py
|
|
38
45
|
tests/test_git_hooks.py
|
|
39
46
|
tests/test_lemonade.py
|
|
@@ -164,13 +164,18 @@ C:\Users\YourName\.diffron-hooks\
|
|
|
164
164
|
#### prepare-commit-msg (Shell Wrapper)
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
|
-
#!/
|
|
168
|
-
# Diffron prepare-commit-msg hook wrapper
|
|
167
|
+
#!/bin/sh
|
|
168
|
+
# Diffron prepare-commit-msg hook wrapper for Windows (Git Bash)
|
|
169
169
|
|
|
170
|
-
# Get the directory where this wrapper script is located
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
# Get the directory where this wrapper script is located (Unix-style path)
|
|
171
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
172
|
+
|
|
173
|
+
# Convert Unix path to Windows path for Python using cygpath
|
|
174
|
+
# Git Bash on Windows uses /d/... but Windows needs D:\...
|
|
175
|
+
PYTHON_SCRIPT="$(cygpath -w "$SCRIPT_DIR/prepare-commit-msg.py" 2>/dev/null || echo "$SCRIPT_DIR/prepare-commit-msg.py")"
|
|
176
|
+
|
|
177
|
+
# Run the Python script
|
|
178
|
+
python "$PYTHON_SCRIPT" "$1" "$2"
|
|
174
179
|
```
|
|
175
180
|
|
|
176
181
|
**Purpose:** Git for Windows executes this shell script, which delegates to Python.
|
|
@@ -179,6 +184,7 @@ exit 0
|
|
|
179
184
|
- Git for Windows uses bundled Git Bash
|
|
180
185
|
- Python may not be in Git Bash PATH
|
|
181
186
|
- Wrapper ensures correct Python interpreter is used
|
|
187
|
+
- **cygpath** converts Unix-style paths (`/d/...`) to Windows paths (`D:\...`)
|
|
182
188
|
|
|
183
189
|
#### prepare-commit-msg.py (Python Hook)
|
|
184
190
|
|
|
@@ -417,6 +423,102 @@ git commit -m "test"
|
|
|
417
423
|
|
|
418
424
|
---
|
|
419
425
|
|
|
426
|
+
## Troubleshooting
|
|
427
|
+
|
|
428
|
+
### Hooks werden nicht ausgeführt
|
|
429
|
+
|
|
430
|
+
**Symptom:** `git commit` öffnet den Editor ohne generierte Message.
|
|
431
|
+
|
|
432
|
+
**Ursache 1: Lokaler `core.hooksPath` überschreibt globalen Wert**
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
# Prüfen ob lokaler hooksPath gesetzt ist
|
|
436
|
+
git config core.hooksPath
|
|
437
|
+
|
|
438
|
+
# Wenn Output leer ist ("core.hooksPath="), wurde er auf leer gesetzt
|
|
439
|
+
# Das deaktiviert Hooks komplett!
|
|
440
|
+
|
|
441
|
+
# Lösung: Lokalen Wert entfernen
|
|
442
|
+
git config --unset core.hooksPath
|
|
443
|
+
|
|
444
|
+
# Verifizieren: Sollte jetzt keinen Output geben
|
|
445
|
+
git config core.hooksPath
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Ursache 2: Backup hat fehlerhafte Konfiguration wiederhergestellt**
|
|
449
|
+
|
|
450
|
+
Nach dem Einspielen eines Backups kann die `.git/config` einen leeren `core.hooksPath=` enthalten.
|
|
451
|
+
|
|
452
|
+
**Lösung nach Backup:**
|
|
453
|
+
```bash
|
|
454
|
+
cd path/to/repo
|
|
455
|
+
git config --unset core.hooksPath
|
|
456
|
+
git commit # Testen ob Hook funktioniert
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Ursache 3: Wrapper-Pfad-Konvertierung fehlgeschlagen**
|
|
460
|
+
|
|
461
|
+
Der Shell-Wrapper muss Unix-Pfade (`/d/...`) zu Windows-Pfaden (`D:\...`) konvertieren.
|
|
462
|
+
|
|
463
|
+
**Lösung:** Stelle sicher dass der Wrapper `cygpath` verwendet:
|
|
464
|
+
```bash
|
|
465
|
+
#!/bin/sh
|
|
466
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
467
|
+
PYTHON_SCRIPT="$(cygpath -w "$SCRIPT_DIR/prepare-commit-msg.py" 2>/dev/null || echo "$SCRIPT_DIR/prepare-commit-msg.py")"
|
|
468
|
+
python "$PYTHON_SCRIPT" "$1" "$2"
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Lemonade antwortet nicht / ist langsam
|
|
472
|
+
|
|
473
|
+
**Symptom:** Hook schreibt keine Message, Commit erfordert manuelle Eingabe.
|
|
474
|
+
|
|
475
|
+
**Ursache:** Lemonade Server ist nicht erreichbar oder antwortet zu langsam.
|
|
476
|
+
|
|
477
|
+
**Lösung:**
|
|
478
|
+
1. Prüfen ob Lemonade läuft: `http://localhost:8020` im Browser öffnen
|
|
479
|
+
2. Hook-Timeout erhöhen (Standard: 10 Sekunden):
|
|
480
|
+
```python
|
|
481
|
+
# In prepare-commit-msg.py
|
|
482
|
+
def is_lemonade_api_responsive(url: str, timeout: float = 10.0) -> bool:
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### "No staged changes" Fehler im Log
|
|
486
|
+
|
|
487
|
+
**Symptom:** Hook wird ausgeführt, aber generiert keine Message.
|
|
488
|
+
|
|
489
|
+
**Ursache:** Der Hook prüft den git diff im aktuellen Arbeitsverzeichnis, nicht im Hook-Kontext.
|
|
490
|
+
|
|
491
|
+
**Lösung:** Der Hook wechselt automatisch ins Repository-Verzeichnis. Stelle sicher dass:
|
|
492
|
+
```python
|
|
493
|
+
# Change to the repository directory
|
|
494
|
+
repo_dir = os.path.dirname(os.path.abspath(commit_msg_file))
|
|
495
|
+
if os.path.basename(repo_dir) == ".git":
|
|
496
|
+
repo_dir = os.path.dirname(repo_dir)
|
|
497
|
+
os.chdir(repo_dir)
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Globale vs. Lokale Hooks
|
|
501
|
+
|
|
502
|
+
**Frage:** Soll ich globale oder lokale Hooks verwenden?
|
|
503
|
+
|
|
504
|
+
**Empfehlung:** Verwende **globale Hooks** für konsistentes Verhalten:
|
|
505
|
+
```bash
|
|
506
|
+
git config --global core.hooksPath "C:/Users/YourName/.diffron-hooks"
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
**Vorteile:**
|
|
510
|
+
- Einmal installieren, überall verfügbar
|
|
511
|
+
- Backup von `.git/config` beeinflusst Hooks nicht
|
|
512
|
+
- Konsistentes Verhalten über alle Repositories
|
|
513
|
+
|
|
514
|
+
**Nach Backup prüfen:**
|
|
515
|
+
```bash
|
|
516
|
+
git config --global core.hooksPath # Sollte Pfad anzeigen
|
|
517
|
+
git config core.hooksPath # Sollte leer sein (kein Output)
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
420
522
|
## Hook Lifecycle
|
|
421
523
|
|
|
422
524
|
### Installation
|
|
@@ -438,5 +540,5 @@ git commit -m "test"
|
|
|
438
540
|
|
|
439
541
|
---
|
|
440
542
|
|
|
441
|
-
*Last updated: 2026-03-
|
|
543
|
+
*Last updated: 2026-03-29*
|
|
442
544
|
*Version: 0.1.0*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Complete installation guide for Diffron on Windows with AMD Lemonade and GitHub Desktop.
|
|
4
4
|
|
|
5
|
-
**Diffron is a
|
|
5
|
+
**Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Diffron PR Description Generator (aipr).
|
|
4
|
+
|
|
5
|
+
Generates GitHub PR title and description from branch changes.
|
|
6
|
+
Run this script manually when ready to create a PR.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python aipr.py [branch] [base]
|
|
10
|
+
|
|
11
|
+
branch: Branch to analyze (default: current branch)
|
|
12
|
+
base: Base branch to compare against (default: main/master)
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
python aipr.py feature/my-feature main
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
import os
|
|
20
|
+
import subprocess
|
|
21
|
+
|
|
22
|
+
# Add parent directory to path to import diffron
|
|
23
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
24
|
+
|
|
25
|
+
from diffron.pr_gen import generate_pr_description, create_github_pr
|
|
26
|
+
from diffron.lemonade import is_lemonade_running
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def check_gh_cli() -> bool:
|
|
30
|
+
"""Check if GitHub CLI is available."""
|
|
31
|
+
try:
|
|
32
|
+
result = subprocess.run(
|
|
33
|
+
["gh", "--version"],
|
|
34
|
+
capture_output=True,
|
|
35
|
+
text=True,
|
|
36
|
+
timeout=10,
|
|
37
|
+
)
|
|
38
|
+
return result.returncode == 0
|
|
39
|
+
except (subprocess.SubprocessError, FileNotFoundError):
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main():
|
|
44
|
+
"""Main entry point."""
|
|
45
|
+
# Parse arguments
|
|
46
|
+
branch = sys.argv[1] if len(sys.argv) > 1 else None
|
|
47
|
+
base = sys.argv[2] if len(sys.argv) > 2 else None
|
|
48
|
+
|
|
49
|
+
# Check if Lemonade is running
|
|
50
|
+
if not is_lemonade_running():
|
|
51
|
+
print(
|
|
52
|
+
"Error: Lemonade server is not running.",
|
|
53
|
+
file=sys.stderr
|
|
54
|
+
)
|
|
55
|
+
print(
|
|
56
|
+
"Please start Lemonade first (e.g., 'lemonade serve').",
|
|
57
|
+
file=sys.stderr
|
|
58
|
+
)
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
# Generate PR description
|
|
63
|
+
print("Analyzing branch changes...")
|
|
64
|
+
pr = generate_pr_description(branch=branch, base=base)
|
|
65
|
+
|
|
66
|
+
# Output result
|
|
67
|
+
print("\n" + "=" * 60)
|
|
68
|
+
print(pr.format_output())
|
|
69
|
+
print("=" * 60 + "\n")
|
|
70
|
+
|
|
71
|
+
# Check if gh CLI is available
|
|
72
|
+
if check_gh_cli():
|
|
73
|
+
response = input("Create PR on GitHub now? (y/n): ").strip().lower()
|
|
74
|
+
if response in ("y", "yes"):
|
|
75
|
+
print("Creating PR...")
|
|
76
|
+
create_github_pr(branch=branch, base=base, auto_submit=True)
|
|
77
|
+
print("PR created successfully!")
|
|
78
|
+
else:
|
|
79
|
+
print(
|
|
80
|
+
"Tip: Install GitHub CLI (gh) to auto-create PRs: "
|
|
81
|
+
"https://cli.github.com/"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
except ValueError as e:
|
|
85
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
except ConnectionError as e:
|
|
88
|
+
print(f"Connection error: {e}", file=sys.stderr)
|
|
89
|
+
sys.exit(1)
|
|
90
|
+
except KeyboardInterrupt:
|
|
91
|
+
print("\nCancelled.")
|
|
92
|
+
sys.exit(0)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
main()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Diffron prepare-commit-msg hook wrapper for Windows (Git Bash)
|
|
3
|
+
# This file should be placed in .git/hooks/prepare-commit-msg (no extension)
|
|
4
|
+
|
|
5
|
+
# Get the directory where this wrapper script is located (Unix-style path)
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
7
|
+
|
|
8
|
+
# Convert Unix path to Windows path for Python using cygpath
|
|
9
|
+
# Git Bash on Windows uses /d/... but Windows needs D:\...
|
|
10
|
+
PYTHON_SCRIPT="$(cygpath -w "$SCRIPT_DIR/prepare-commit-msg.py" 2>/dev/null || echo "$SCRIPT_DIR/prepare-commit-msg.py")"
|
|
11
|
+
|
|
12
|
+
# Run the Python script
|
|
13
|
+
python "$PYTHON_SCRIPT" "$1" "$2"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Diffron prepare-commit-msg Git hook.
|
|
4
|
+
|
|
5
|
+
Automatically generates commit messages using Lemonade LLM.
|
|
6
|
+
Installed globally by Diffron.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
# Import diffron from installed package (no path manipulation needed)
|
|
13
|
+
from diffron.commit_gen import generate_commit_message
|
|
14
|
+
from diffron.lemonade import is_lemonade_running
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
"""Main hook entry point."""
|
|
19
|
+
# Parse arguments
|
|
20
|
+
if len(sys.argv) < 2:
|
|
21
|
+
print("Error: Missing commit message file argument", file=sys.stderr)
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
commit_msg_file = sys.argv[1]
|
|
25
|
+
commit_source = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
26
|
+
|
|
27
|
+
# Skip for merges, rebases, and amend commits
|
|
28
|
+
skip_sources = {"merge", "squash", "commit"}
|
|
29
|
+
if commit_source in skip_sources:
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
# Check if Lemonade is running
|
|
33
|
+
if not is_lemonade_running():
|
|
34
|
+
# Silently exit if Lemonade not running - let user commit manually
|
|
35
|
+
sys.exit(0)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
# Generate commit message
|
|
39
|
+
commit_message = generate_commit_message()
|
|
40
|
+
|
|
41
|
+
if commit_message:
|
|
42
|
+
# Write to commit message file
|
|
43
|
+
with open(commit_msg_file, "w", encoding="utf-8") as f:
|
|
44
|
+
f.write(commit_message)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
# Log error but don't block commit
|
|
47
|
+
error_msg = f"# Diffron error: {e}\n"
|
|
48
|
+
try:
|
|
49
|
+
with open(commit_msg_file, "a", encoding="utf-8") as f:
|
|
50
|
+
f.write(error_msg)
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
sys.exit(0) # Don't block commit on error
|
|
54
|
+
|
|
55
|
+
sys.exit(0)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
main()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Diffron prepare-commit-msg Git hook.
|
|
4
|
+
|
|
5
|
+
Automatically generates commit messages using Lemonade LLM.
|
|
6
|
+
Installed globally by Diffron.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
import urllib.request
|
|
12
|
+
import urllib.error
|
|
13
|
+
|
|
14
|
+
# Import diffron from installed package (no path manipulation needed)
|
|
15
|
+
from diffron.commit_gen import generate_commit_message
|
|
16
|
+
from diffron.lemonade import get_lemonade_url
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def is_lemonade_api_responsive(url: str, timeout: float = 10.0) -> bool:
|
|
20
|
+
"""
|
|
21
|
+
Check if Lemonade API actually responds (not just port open).
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
url: Lemonade server URL.
|
|
25
|
+
timeout: Request timeout in seconds (10s to allow for slow startup).
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
True if API responds successfully.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
# Try /api/v1/models endpoint
|
|
32
|
+
models_url = f"{url}/api/v1/models"
|
|
33
|
+
req = urllib.request.Request(models_url)
|
|
34
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
35
|
+
if response.status == 200:
|
|
36
|
+
return True
|
|
37
|
+
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
# Fallback: try root endpoint
|
|
41
|
+
try:
|
|
42
|
+
req = urllib.request.Request(url)
|
|
43
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
44
|
+
return response.status == 200
|
|
45
|
+
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main():
|
|
52
|
+
"""Main hook entry point."""
|
|
53
|
+
# Parse arguments
|
|
54
|
+
if len(sys.argv) < 2:
|
|
55
|
+
print("Error: Missing commit message file argument", file=sys.stderr)
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
|
|
58
|
+
commit_msg_file = sys.argv[1]
|
|
59
|
+
commit_source = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
60
|
+
|
|
61
|
+
# Skip for merges, rebases, and amend commits
|
|
62
|
+
skip_sources = {"merge", "squash", "commit"}
|
|
63
|
+
if commit_source in skip_sources:
|
|
64
|
+
sys.exit(0)
|
|
65
|
+
|
|
66
|
+
# Change to the repository directory (where git commit was run)
|
|
67
|
+
repo_dir = os.path.dirname(os.path.abspath(commit_msg_file))
|
|
68
|
+
# Navigate up from .git/COMMIT_EDITMSG to repo root
|
|
69
|
+
if os.path.basename(repo_dir) == ".git":
|
|
70
|
+
repo_dir = os.path.dirname(repo_dir)
|
|
71
|
+
os.chdir(repo_dir)
|
|
72
|
+
|
|
73
|
+
# Get Lemonade URL and check if API is actually responsive
|
|
74
|
+
lemonade_url = get_lemonade_url()
|
|
75
|
+
if not is_lemonade_api_responsive(lemonade_url):
|
|
76
|
+
# Silently exit if Lemonade not responding - let user commit manually
|
|
77
|
+
sys.exit(0)
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
# Generate commit message
|
|
81
|
+
commit_message = generate_commit_message()
|
|
82
|
+
|
|
83
|
+
if commit_message:
|
|
84
|
+
# Write to commit message file
|
|
85
|
+
with open(commit_msg_file, "w", encoding="utf-8") as f:
|
|
86
|
+
f.write(commit_message)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
# Log error but don't block commit
|
|
89
|
+
error_msg = f"# Diffron error: {e}\n"
|
|
90
|
+
try:
|
|
91
|
+
with open(commit_msg_file, "a", encoding="utf-8") as f:
|
|
92
|
+
f.write(error_msg)
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
sys.exit(0) # Don't block commit on error
|
|
96
|
+
|
|
97
|
+
sys.exit(0)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "diffron"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Git commit message and PR description generator using Lemonade"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -55,10 +55,11 @@ Documentation = "https://github.com/diffron/diffron/docs"
|
|
|
55
55
|
Repository = "https://github.com/diffron/diffron"
|
|
56
56
|
|
|
57
57
|
[tool.setuptools.packages.find]
|
|
58
|
-
exclude = ["tests"
|
|
58
|
+
exclude = ["tests"]
|
|
59
59
|
|
|
60
60
|
[tool.setuptools.package-data]
|
|
61
61
|
diffron = ["py.typed"]
|
|
62
|
+
"diffron.hooks" = ["*"]
|
|
62
63
|
|
|
63
64
|
[tool.black]
|
|
64
65
|
line-length = 100
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
"""Setup script for Diffron package."""
|
|
2
|
-
|
|
3
|
-
from setuptools import setup, find_packages
|
|
4
|
-
|
|
5
|
-
with open("README.md", "r", encoding="utf-8") as fh:
|
|
6
|
-
long_description = fh.read()
|
|
7
|
-
|
|
8
|
-
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
|
9
|
-
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
|
|
10
|
-
|
|
11
|
-
setup(
|
|
12
|
-
name="diffron",
|
|
13
|
-
version="0.1.
|
|
14
|
-
author="Diffron Contributors",
|
|
15
|
-
author_email="diffron@example.com",
|
|
16
|
-
description="Git commit message and PR description generator using Lemonade",
|
|
17
|
-
long_description=long_description,
|
|
18
|
-
long_description_content_type="text/markdown",
|
|
19
|
-
url="https://github.com/diffron/diffron",
|
|
20
|
-
packages=find_packages(exclude=["tests", "hooks"]),
|
|
21
|
-
classifiers=[
|
|
22
|
-
"Development Status :: 3 - Alpha",
|
|
23
|
-
"Environment :: Console",
|
|
24
|
-
"Intended Audience :: Developers",
|
|
25
|
-
"License :: OSI Approved :: MIT License",
|
|
26
|
-
"Operating System :: Microsoft :: Windows",
|
|
27
|
-
"Operating System :: POSIX :: Linux",
|
|
28
|
-
"Operating System :: MacOS :: MacOS X",
|
|
29
|
-
"Programming Language :: Python :: 3",
|
|
30
|
-
"Programming Language :: Python :: 3.9",
|
|
31
|
-
"Programming Language :: Python :: 3.10",
|
|
32
|
-
"Programming Language :: Python :: 3.11",
|
|
33
|
-
"Programming Language :: Python :: 3.12",
|
|
34
|
-
"Topic :: Software Development :: Version Control :: Git",
|
|
35
|
-
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
36
|
-
],
|
|
37
|
-
python_requires=">=3.9",
|
|
38
|
-
install_requires=[
|
|
39
|
-
"openai>=1.0.0",
|
|
40
|
-
"psutil>=5.9.0",
|
|
41
|
-
],
|
|
42
|
-
extras_require={
|
|
43
|
-
"git": ["gitpython>=3.1.0"],
|
|
44
|
-
"dev": [
|
|
45
|
-
"pytest>=7.0.0",
|
|
46
|
-
"pytest-cov>=4.0.0",
|
|
47
|
-
"black>=23.0.0",
|
|
48
|
-
"isort>=5.12.0",
|
|
49
|
-
"mypy>=1.0.0",
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
entry_points={
|
|
53
|
-
"console_scripts": [
|
|
54
|
-
"diffron-install-hooks=diffron.cli:install_hooks_cli",
|
|
55
|
-
"diffron-uninstall-hooks=diffron.cli:uninstall_hooks_cli",
|
|
56
|
-
"diffron-pr=diffron.cli:pr_description_cli",
|
|
57
|
-
"diffron-status=diffron.cli:status_cli",
|
|
58
|
-
],
|
|
59
|
-
},
|
|
60
|
-
include_package_data=True,
|
|
61
|
-
package_data={
|
|
62
|
-
"diffron": ["py.typed"],
|
|
63
|
-
},
|
|
64
|
-
)
|
|
1
|
+
"""Setup script for Diffron package."""
|
|
2
|
+
|
|
3
|
+
from setuptools import setup, find_packages
|
|
4
|
+
|
|
5
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
6
|
+
long_description = fh.read()
|
|
7
|
+
|
|
8
|
+
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
|
9
|
+
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
|
|
10
|
+
|
|
11
|
+
setup(
|
|
12
|
+
name="diffron",
|
|
13
|
+
version="0.1.2",
|
|
14
|
+
author="Diffron Contributors",
|
|
15
|
+
author_email="diffron@example.com",
|
|
16
|
+
description="Git commit message and PR description generator using Lemonade",
|
|
17
|
+
long_description=long_description,
|
|
18
|
+
long_description_content_type="text/markdown",
|
|
19
|
+
url="https://github.com/diffron/diffron",
|
|
20
|
+
packages=find_packages(exclude=["tests", "hooks"]),
|
|
21
|
+
classifiers=[
|
|
22
|
+
"Development Status :: 3 - Alpha",
|
|
23
|
+
"Environment :: Console",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"License :: OSI Approved :: MIT License",
|
|
26
|
+
"Operating System :: Microsoft :: Windows",
|
|
27
|
+
"Operating System :: POSIX :: Linux",
|
|
28
|
+
"Operating System :: MacOS :: MacOS X",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.9",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Topic :: Software Development :: Version Control :: Git",
|
|
35
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
36
|
+
],
|
|
37
|
+
python_requires=">=3.9",
|
|
38
|
+
install_requires=[
|
|
39
|
+
"openai>=1.0.0",
|
|
40
|
+
"psutil>=5.9.0",
|
|
41
|
+
],
|
|
42
|
+
extras_require={
|
|
43
|
+
"git": ["gitpython>=3.1.0"],
|
|
44
|
+
"dev": [
|
|
45
|
+
"pytest>=7.0.0",
|
|
46
|
+
"pytest-cov>=4.0.0",
|
|
47
|
+
"black>=23.0.0",
|
|
48
|
+
"isort>=5.12.0",
|
|
49
|
+
"mypy>=1.0.0",
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
entry_points={
|
|
53
|
+
"console_scripts": [
|
|
54
|
+
"diffron-install-hooks=diffron.cli:install_hooks_cli",
|
|
55
|
+
"diffron-uninstall-hooks=diffron.cli:uninstall_hooks_cli",
|
|
56
|
+
"diffron-pr=diffron.cli:pr_description_cli",
|
|
57
|
+
"diffron-status=diffron.cli:status_cli",
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
include_package_data=True,
|
|
61
|
+
package_data={
|
|
62
|
+
"diffron": ["py.typed"],
|
|
63
|
+
},
|
|
64
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|