Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion penify_hook/commands/config_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,26 @@ def do_GET(self):
content = f.read()

self.wfile.write(content.encode())
elif self.path == "/get_config":
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()

# Get current LLM configuration
current_config = get_llm_config()

if current_config:
response = {
"success": True,
"config": current_config
}
else:
response = {
"success": False,
"message": "No configuration found"
}

self.wfile.write(json.dumps(response).encode())
else:
self.send_response(404)
self.send_header("Content-type", "text/plain")
Expand Down Expand Up @@ -186,7 +206,6 @@ def config_jira_web():
"""
Open a web browser interface for configuring JIRA settings.
"""
# Similar implementation to config_llm_web but for JIRA settings
redirect_port = random.randint(30000, 50000)
server_url = f"http://localhost:{redirect_port}"

Expand All @@ -208,6 +227,26 @@ def do_GET(self):
content = f.read()

self.wfile.write(content.encode())
elif self.path == "/get_config":
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()

# Get current JIRA configuration
current_config = get_jira_config()

if current_config:
response = {
"success": True,
"config": current_config
}
else:
response = {
"success": False,
"message": "No JIRA configuration found"
}

self.wfile.write(json.dumps(response).encode())
else:
self.send_response(404)
self.send_header("Content-type", "text/plain")
Expand Down
48 changes: 48 additions & 0 deletions penify_hook/commit_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import argparse



def setup_commit_parser(parser):
commit_parser_description = """
It generates smart commit messages. By default, it will just generate just the Title of the commit message.
1. If you have not configured LLM, it will give an error. You either need to configure LLM or use the API key.
2. If you have not configured JIRA. It will not enhance the commit message with JIRA issue details.
3. For more information, visit https://docs.penify.dev/
"""
parser.help = "Generate smart commit messages using local-LLM(no login required)."
parser.description = commit_parser_description
parser.formatter_class = argparse.RawDescriptionHelpFormatter

# Add the message argument with better help
parser.add_argument("-m", "--message", required=False, help="Commit with contextual commit message.", default="N/A")
parser.add_argument("-e", "--terminal", action="store_true", help="Open edit terminal before committing.")
parser.add_argument("-d", "--description", action="store_false", help="It will generate commit message with title and description.", default=False)

def handle_commit(args):
from penify_hook.commands.commit_commands import commit_code
from penify_hook.commands.config_commands import get_jira_config, get_llm_config, get_token
from penify_hook.constants import API_URL

# Only import dependencies needed for commit functionality here
open_terminal = args.terminal
generate_description = args.description
print(f"Generate Description: {generate_description}")
# Try to get from config
llm_config = get_llm_config()
llm_model = llm_config.get('model')
llm_api_base = llm_config.get('api_base')
llm_api_key = llm_config.get('api_key')
token = get_token()



# Try to get from config
jira_config = get_jira_config()
jira_url = jira_config.get('url')
jira_user = jira_config.get('username')
jira_api_token = jira_config.get('api_token')


commit_code(API_URL, token, args.message, open_terminal, generate_description,
llm_model, llm_api_base, llm_api_key,
jira_url, jira_user, jira_api_token)
68 changes: 68 additions & 0 deletions penify_hook/config_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@



def setup_config_parser(parent_parser):
# Config subcommand: Create subparsers for config types
parser = parent_parser.add_subparsers(title="config_type", dest="config_type")

# Config subcommand: llm
llm_config_parser = parser.add_parser("llm", help="Configure LLM settings.")
llm_config_parser.add_argument("--model", required=True, help="LLM model to use")
llm_config_parser.add_argument("--api-base", help="API base URL for the LLM service")
llm_config_parser.add_argument("--api-key", help="API key for the LLM service")

# Config subcommand: llm-web
parser.add_parser("llm-web", help="Configure LLM settings through a web interface")

# Config subcommand: jira
jira_config_parser = parser.add_parser("jira", help="Configure JIRA settings.")
jira_config_parser.add_argument("--url", required=True, help="JIRA base URL")
jira_config_parser.add_argument("--username", required=True, help="JIRA username or email")
jira_config_parser.add_argument("--api-token", required=True, help="JIRA API token")
jira_config_parser.add_argument("--verify", action="store_true", help="Verify JIRA connection")

# Config subcommand: jira-web
parser.add_parser("jira-web", help="Configure JIRA settings through a web interface")

# Add all other necessary arguments for config command

def handle_config(args):
# Only import dependencies needed for config functionality here
from penify_hook.commands.config_commands import save_llm_config
from penify_hook.jira_client import JiraClient # Import moved here
from penify_hook.commands.config_commands import config_jira_web, config_llm_web, save_jira_config

if args.config_type == "llm":
save_llm_config(args.model, args.api_base, args.api_key)
print(f"LLM configuration set: Model={args.model}, API Base={args.api_base or 'default'}")

elif args.config_type == "llm-web":
config_llm_web()

elif args.config_type == "jira":
save_jira_config(args.url, args.username, args.api_token)
print(f"JIRA configuration set: URL={args.url}, Username={args.username}")

# Verify connection if requested
if args.verify:
if JiraClient:
jira_client = JiraClient(
jira_url=args.url,
jira_user=args.username,
jira_api_token=args.api_token
)
if jira_client.is_connected():
print("JIRA connection verified successfully!")
else:
print("Failed to connect to JIRA. Please check your credentials.")
else:
print("JIRA package not installed. Cannot verify connection.")

elif args.config_type == "jira-web":
config_jira_web()

else:
print("Please specify a config type: llm, llm-web, jira, or jira-web")
return 1

return 0
2 changes: 2 additions & 0 deletions penify_hook/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
API_URL = 'https://production-gateway.snorkell.ai/api'
DASHBOARD_URL = "https://dashboard.penify.dev/auth/localhost/login"
55 changes: 55 additions & 0 deletions penify_hook/docgen_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import logging
import os



# Define the docgen description text
docgen_description = """Generate code documentation using Penify.

This command requires you to be logged in to your Penify account.
You can generate documentation for:
- Current Git diff (default)
- Specific file
- Specific folder
"""

def setup_docgen_parser(parser):
# We don't need to create a new docgen_parser since it's passed as a parameter
docgen_subparsers = parser.add_subparsers(title="docgen_subcommand", dest="docgen_subcommand")

# Docgen main options (for direct documentation generation)
parser.add_argument("-l", "--location", help="[Optional] Path to the folder or file to Generate Documentation. By default it will pick the root directory.", default=None)

# Subcommand: install-hook (as part of docgen)
install_hook_parser = docgen_subparsers.add_parser("install-hook", help="Install the Git post-commit hook.")
install_hook_parser.add_argument("-l", "--location", required=False,
help="Location in which to install the Git hook. Defaults to current directory.",
default=os.getcwd())

# Subcommand: uninstall-hook (as part of docgen)
uninstall_hook_parser = docgen_subparsers.add_parser("uninstall-hook", help="Uninstall the Git post-commit hook.")
uninstall_hook_parser.add_argument("-l", "--location", required=False,
help="Location from which to uninstall the Git hook. Defaults to current directory.",
default=os.getcwd())

def handle_docgen(args):
# Only import dependencies needed for docgen functionality here
from penify_hook.commands.config_commands import get_token
import sys
from penify_hook.commands.doc_commands import generate_doc
from penify_hook.commands.hook_commands import install_git_hook, uninstall_git_hook
from penify_hook.constants import API_URL

token = get_token()
if not token:
logging.error("Error: Unable to authenticate. Please run 'penifycli login'.")
sys.exit(1)

if args.docgen_subcommand == "install-hook":
install_git_hook(args.location, token)

elif args.docgen_subcommand == "uninstall-hook":
uninstall_git_hook(args.location)

else: # Direct documentation generation
generate_doc(API_URL, token, args.location)
4 changes: 2 additions & 2 deletions penify_hook/file_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ def process_file(self, file_path, pbar):
# --- STAGE 1: Validating ---
update_stage(pbar, "Validating")
if not file_extension:
logger.info(f"File {file_path} has no extension. Skipping.")
print_warning(f" Empty extension is not supported. Skipping '{self.relative_file_path}'.")
return False

file_extension = file_extension[1:] # Remove the leading dot

if file_extension not in self.supported_file_types:
logger.info(f"File type {file_extension} is not supported. Skipping {file_path}.")
print_warning(f" File type '{file_extension}' is not supported. Skipping '{self.relative_file_path}'.")
return False

# Update progress bar to indicate we're moving to next stage
Expand Down
11 changes: 11 additions & 0 deletions penify_hook/login_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def setup_login_parser(parser):
parser.add_argument("--token", help="Specify API token directly")
# Add all other necessary arguments for login command

def handle_login(args):
from penify_hook.constants import API_URL, DASHBOARD_URL
from penify_hook.commands.auth_commands import login


# Only import dependencies needed for login functionality here
return login(API_URL, DASHBOARD_URL)
Loading