Skip to content

Commit 0a7084e

Browse files
committed
feat: Add command modules for documentation generation and Git hook installation
1 parent 5172098 commit 0a7084e

7 files changed

Lines changed: 579 additions & 586 deletions

File tree

penify_hook/commands/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This file makes the commands directory a proper Python package
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import json
2+
import webbrowser
3+
import http.server
4+
import socketserver
5+
import urllib.parse
6+
import random
7+
from threading import Thread
8+
from pathlib import Path
9+
from ..api_client import APIClient
10+
11+
def save_credentials(api_key):
12+
"""
13+
Save the token and API keys in the .penify file in the user's home directory.
14+
"""
15+
home_dir = Path.home()
16+
penify_file = home_dir / '.penify'
17+
18+
credentials = {
19+
'api_keys': api_key
20+
}
21+
22+
try:
23+
with open(penify_file, 'w') as f:
24+
json.dump(credentials, f)
25+
return True
26+
except Exception as e:
27+
print(f"Error saving credentials: {str(e)}")
28+
return False
29+
30+
def login(api_url, dashboard_url):
31+
"""
32+
Open the login page in a web browser and listen for the redirect URL to capture the token.
33+
"""
34+
redirect_port = random.randint(30000, 50000)
35+
redirect_url = f"http://localhost:{redirect_port}/callback"
36+
37+
full_login_url = f"{dashboard_url}?redirectUri={urllib.parse.quote(redirect_url)}"
38+
39+
print(f"Opening login page in your default web browser: {full_login_url}")
40+
webbrowser.open(full_login_url)
41+
42+
class TokenHandler(http.server.SimpleHTTPRequestHandler):
43+
def do_GET(self):
44+
query = urllib.parse.urlparse(self.path).query
45+
query_components = urllib.parse.parse_qs(query)
46+
token = query_components.get("token", [None])[0]
47+
48+
if token:
49+
self.send_response(200)
50+
self.send_header("Content-type", "text/html")
51+
self.end_headers()
52+
response = """
53+
<html>
54+
<head>
55+
<script>
56+
setTimeout(function() {
57+
window.location.href = 'https://dashboard.penify.dev';
58+
}, 5000);
59+
</script>
60+
</head>
61+
<body>
62+
<h1>Login Successful!</h1>
63+
<p>You will be redirected to the Penify dashboard in 5 seconds. You can also close this window and return to the CLI.</p>
64+
</body>
65+
</html>
66+
"""
67+
self.wfile.write(response.encode())
68+
69+
print(f"\nLogin successful! Fetching API keys...")
70+
api_key = APIClient(api_url, None, token).get_api_key()
71+
if api_key:
72+
save_credentials(api_key)
73+
print("API keys fetched and saved successfully.")
74+
print("You'll be redirected to the Penify dashboard. You can continue using the CLI.")
75+
else:
76+
print("Failed to fetch API keys.")
77+
else:
78+
self.send_response(400)
79+
self.send_header("Content-type", "text/html")
80+
self.end_headers()
81+
response = """
82+
<html>
83+
<body>
84+
<h1>Login Failed</h1>
85+
<p>Please try again.</p>
86+
</body>
87+
</html>
88+
"""
89+
self.wfile.write(response.encode())
90+
print("\nLogin failed. Please try again.")
91+
92+
# Schedule the server shutdown
93+
thread = Thread(target=self.server.shutdown)
94+
thread.daemon = True
95+
thread.start()
96+
97+
def log_message(self, format, *args):
98+
# Suppress log messages
99+
return
100+
101+
with socketserver.TCPServer(("", redirect_port), TokenHandler) as httpd:
102+
print(f"Listening on port {redirect_port} for the redirect...")
103+
httpd.serve_forever()
104+
105+
print("Login process completed. You can now use other commands with your API token.")
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import sys
2+
from ..commit_analyzer import CommitDocGenHook
3+
from ..api_client import APIClient
4+
5+
# Try importing optional dependencies
6+
try:
7+
from ..llm_client import LLMClient
8+
except ImportError:
9+
LLMClient = None
10+
11+
try:
12+
from ..jira_client import JiraClient
13+
except ImportError:
14+
JiraClient = None
15+
16+
def commit_code(api_url, gf_path, token, message, open_terminal,
17+
llm_model=None, llm_api_base=None, llm_api_key=None,
18+
jira_url=None, jira_user=None, jira_api_token=None):
19+
"""
20+
Enhance Git commits with AI-powered commit messages.
21+
"""
22+
# Create API client
23+
api_client = APIClient(api_url, token)
24+
25+
# Initialize LLM client if LLM parameters are provided and LLMClient is available
26+
llm_client = None
27+
if LLMClient is not None and llm_model:
28+
try:
29+
llm_client = LLMClient(
30+
model=llm_model,
31+
api_base=llm_api_base,
32+
api_key=llm_api_key
33+
)
34+
print(f"Using LLM model: {llm_model}")
35+
except Exception as e:
36+
print(f"Error initializing LLM client: {e}")
37+
print("Falling back to API for commit summary generation")
38+
39+
# Initialize JIRA client if parameters are provided and JiraClient is available
40+
jira_client = None
41+
if JiraClient is not None and jira_url and jira_user and jira_api_token:
42+
try:
43+
jira_client = JiraClient(
44+
jira_url=jira_url,
45+
jira_user=jira_user,
46+
jira_api_token=jira_api_token
47+
)
48+
if jira_client.is_connected():
49+
print(f"Connected to JIRA: {jira_url}")
50+
else:
51+
print(f"Failed to connect to JIRA: {jira_url}")
52+
jira_client = None
53+
except Exception as e:
54+
print(f"Error initializing JIRA client: {e}")
55+
jira_client = None
56+
57+
try:
58+
# Pass the LLM client and JIRA client to CommitDocGenHook
59+
analyzer = CommitDocGenHook(gf_path, api_client, llm_client, jira_client)
60+
analyzer.run(message, open_terminal)
61+
except Exception as e:
62+
print(f"Error: {e}")
63+
sys.exit(1)

0 commit comments

Comments
 (0)