Skip to content

Commit f1d5e46

Browse files
committed
refactor(analyzers): consolidate common functionality into BaseAnalyzer class
1 parent f9de943 commit f1d5e46

8 files changed

Lines changed: 59 additions & 101 deletions

File tree

penify_hook/base_analyzer.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import os
2+
from git import Repo
3+
from .api_client import APIClient
4+
from penify_hook.utils import get_repo_details, recursive_search_git_folder
5+
6+
7+
class BaseAnalyzer:
8+
9+
def __init__(self, folder_path: str, api_client: APIClient):
10+
self.folder_path = folder_path
11+
self.repo_path = recursive_search_git_folder(folder_path)
12+
self.repo = None
13+
self.repo_details = None
14+
if self.folder_path:
15+
self.repo = Repo(self.repo_path)
16+
self.repo_details = get_repo_details(self.repo)
17+
18+
self.relative_file_path = os.path.relpath(folder_path)
19+
self.api_client = api_client
20+
self.supported_file_types = set(api_client.get_supported_file_types())

penify_hook/commands/commit_commands.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import os
12
import sys
3+
4+
from penify_hook.utils import recursive_search_git_folder
25
from ..commit_analyzer import CommitDocGenHook
36
from ..api_client import APIClient
47

@@ -13,7 +16,7 @@
1316
except ImportError:
1417
JiraClient = None
1518

16-
def commit_code(api_url, gf_path, token, message, open_terminal,
19+
def commit_code(api_url, token, message, open_terminal,
1720
llm_model=None, llm_api_base=None, llm_api_key=None,
1821
jira_url=None, jira_user=None, jira_api_token=None):
1922
"""
@@ -56,6 +59,7 @@ def commit_code(api_url, gf_path, token, message, open_terminal,
5659

5760
try:
5861
# Pass the LLM client and JIRA client to CommitDocGenHook
62+
gf_path = recursive_search_git_folder(os.getcwd())
5963
analyzer = CommitDocGenHook(gf_path, api_client, llm_client, jira_client)
6064
analyzer.run(message, open_terminal)
6165
except Exception as e:

penify_hook/commit_analyzer.py

Lines changed: 5 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,83 +5,16 @@
55
from typing import Optional, List
66
from git import Repo
77
from tqdm import tqdm
8+
9+
from penify_hook.base_analyzer import BaseAnalyzer
810
from .api_client import APIClient
911

10-
class CommitDocGenHook:
12+
class CommitDocGenHook(BaseAnalyzer):
1113
def __init__(self, repo_path: str, api_client: APIClient, llm_client=None, jira_client=None):
12-
self.repo_path = repo_path
13-
self.api_client = api_client
14+
super().__init__(repo_path, api_client)
15+
1416
self.llm_client = llm_client # Add LLM client as an optional parameter
1517
self.jira_client = jira_client # Add JIRA client as an optional parameter
16-
self.repo = Repo(repo_path)
17-
self.supported_file_types = set(self.api_client.get_supported_file_types())
18-
self.repo_details = self.get_repo_details()
19-
20-
def get_repo_details(self):
21-
"""Get the details of the repository, including the hosting service,
22-
organization name, and repository name.
23-
24-
This method checks the remote URL of the repository to determine whether
25-
it is hosted on GitHub, Azure DevOps, Bitbucket, GitLab, or another
26-
service. It extracts the organization (or user) name and the repository
27-
name from the URL. If the hosting service is not recognized, it will
28-
return "Unknown Hosting Service". The method handles potential errors
29-
during the extraction process and returns a dictionary with the relevant
30-
details.
31-
32-
Returns:
33-
dict: A dictionary containing the organization name, repository name, and
34-
hosting service.
35-
"""
36-
remote_url = None
37-
hosting_service = "Unknown"
38-
org_name = None
39-
repo_name = None
40-
41-
try:
42-
# Get the remote URL
43-
remote = self.repo.remotes.origin.url
44-
remote_url = remote
45-
46-
# Determine the hosting service based on the URL
47-
if "github.com" in remote:
48-
hosting_service = "GITHUB"
49-
match = re.match(r".*github\.com[:/](.*?)/(.*?)(\.git)?$", remote)
50-
elif "dev.azure.com" in remote:
51-
hosting_service = "AZUREDEVOPS"
52-
match = re.match(r".*dev\.azure\.com/(.*?)/(.*?)/_git/(.*?)(\.git)?$", remote)
53-
elif "visualstudio.com" in remote:
54-
hosting_service = "AZUREDEVOPS"
55-
match = re.match(r".*@(.*?)\.visualstudio\.com/(.*?)/_git/(.*?)(\.git)?$", remote)
56-
elif "bitbucket.org" in remote:
57-
hosting_service = "BITBUCKET"
58-
match = re.match(r".*bitbucket\.org[:/](.*?)/(.*?)(\.git)?$", remote)
59-
elif "gitlab.com" in remote:
60-
hosting_service = "GITLAB"
61-
match = re.match(r".*gitlab\.com[:/](.*?)/(.*?)(\.git)?$", remote)
62-
else:
63-
hosting_service = "Unknown Hosting Service"
64-
match = None
65-
66-
if match:
67-
org_name = match.group(1)
68-
repo_name = match.group(2)
69-
70-
# For Azure DevOps, adjust the group indices
71-
if hosting_service == "AZUREDEVOPS":
72-
repo_name = match.group(3)
73-
74-
except Exception as e:
75-
print(f"Error determining repo details: {e}")
76-
77-
org_name = org_name if org_name else "UNKNOWN_ORG"
78-
repo_name = repo_name if repo_name else "UNKNOWN_REPO"
79-
80-
return {
81-
"organization_name": org_name,
82-
"repo_name": repo_name,
83-
"vendor": hosting_service
84-
}
8518

8619
def get_summary(self, instruction: str):
8720
"""Generate a summary for the commit based on the staged changes.

penify_hook/file_analyzer.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from tqdm import tqdm
55
import time
66

7+
from penify_hook.base_analyzer import BaseAnalyzer
78
from penify_hook.utils import get_repo_details, recursive_search_git_folder
89
from .api_client import APIClient
910
import logging
@@ -16,15 +17,12 @@
1617
# Set up logger
1718
logger = logging.getLogger(__name__)
1819

19-
class FileAnalyzerGenHook:
20+
class FileAnalyzerGenHook(BaseAnalyzer):
2021
def __init__(self, file_path: str, api_client: APIClient):
2122
self.file_path = file_path
22-
self.repo_path = recursive_search_git_folder(file_path)
23-
self.repo = Repo(self.repo_path)
24-
self.repo_details = get_repo_details(self.repo)
25-
self.relative_file_path = os.path.relpath(file_path)
26-
self.api_client = api_client
27-
self.supported_file_types = set(self.api_client.get_supported_file_types())
23+
super().__init__(file_path, api_client)
24+
25+
2826

2927
def process_file(self, file_path, pbar):
3028
"""Process a file by reading its content and sending it to an API for

penify_hook/folder_analyzer.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import os
22
from git import Repo
3+
4+
from penify_hook.base_analyzer import BaseAnalyzer
35
from .api_client import APIClient
46
from .file_analyzer import FileAnalyzerGenHook
57
from tqdm import tqdm
68

7-
class FolderAnalyzerGenHook:
9+
class FolderAnalyzerGenHook(BaseAnalyzer):
810
def __init__(self, dir_path: str, api_client: APIClient):
911
self.dir_path = dir_path
10-
self.api_client = api_client
12+
super().__init__(dir_path, api_client)
1113

1214
def list_all_files_in_dir(self, dir_path: str):
1315
"""List all files in a directory and its subdirectories.

penify_hook/git_analyzer.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from git import Repo
44
from tqdm import tqdm
55

6+
from penify_hook.base_analyzer import BaseAnalyzer
67
from penify_hook.utils import get_repo_details, recursive_search_git_folder
78
from .api_client import APIClient
89
import logging
@@ -15,13 +16,9 @@
1516
# Set up logger
1617
logger = logging.getLogger(__name__)
1718

18-
class GitDocGenHook:
19+
class GitDocGenHook(BaseAnalyzer):
1920
def __init__(self, repo_path: str, api_client: APIClient):
20-
self.repo_path = recursive_search_git_folder(repo_path)
21-
self.api_client = api_client
22-
self.repo = Repo(self.repo_path)
23-
self.supported_file_types = set(self.api_client.get_supported_file_types())
24-
self.repo_details = get_repo_details(self.repo)
21+
super().__init__(repo_path, api_client)
2522

2623
def get_modified_files_in_last_commit(self):
2724
"""Get the list of files modified in the last commit.

penify_hook/main.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,21 @@ def main():
6363
parser.add_argument_group(advanced_title)
6464

6565
# ===== BASIC COMMANDS (No login required) =====
66+
67+
68+
commit_parser_description = """
69+
It generates smart commit messages. By default, it will just generate just the Title of the commit message.
70+
71+
1. If you have not configured LLM, it will give an error. You either need to configure LLM or use the API key.
72+
2. If you have not configured JIRA. It will not enhance the commit message with JIRA issue details.
73+
3. For more information, visit https://docs.penify.dev/
74+
"""
6675

6776
# Subcommand: commit
68-
commit_parser = subparsers.add_parser("commit", help="Generate smart commit messages using local-LLM(no login required).")
69-
commit_parser.add_argument("-gf", "--git_folder_path", help="Path to the folder with git.", default=os.getcwd())
77+
commit_parser = subparsers.add_parser("commit", help="Generate smart commit messages using local-LLM(no login required).", description=commit_parser_description, formatter_class=argparse.RawDescriptionHelpFormatter)
7078
commit_parser.add_argument("-m", "--message", required=False, help="Commit with contextual commit message.", default="N/A")
71-
commit_parser.add_argument("-e", "--terminal", required=False, help="Open edit terminal", default="False")
72-
# Add LLM options
73-
commit_parser.add_argument("--llm", "--llm-model", dest="llm_model", help="LLM model to use")
74-
commit_parser.add_argument("--llm-api-base", help="API base URL for the LLM service")
75-
commit_parser.add_argument("--llm-api-key", help="API key for the LLM service")
76-
# Add JIRA options
77-
commit_parser.add_argument("--jira-url", help="JIRA base URL")
78-
commit_parser.add_argument("--jira-user", help="JIRA username or email")
79-
commit_parser.add_argument("--jira-api-token", help="JIRA API token")
79+
commit_parser.add_argument("-e", "--terminal", action="store_true", help="Open edit terminal before committing.")
80+
commit_parser.add_argument("-d", "--description", action="store_false", help="It will generate commit message with title and description.")
8081

8182
# Subcommand: config
8283
config_parser = subparsers.add_parser("config", help="Configure local-LLM and JIRA.")
@@ -153,7 +154,7 @@ def main():
153154

154155
elif args.subcommand == "commit":
155156
# For commit, token is now optional - some functionality may be limited without it
156-
open_terminal = args.terminal.lower() == "true"
157+
open_terminal = args.terminal
157158

158159
# Get LLM configuration
159160
llm_model = args.llm_model
@@ -179,7 +180,7 @@ def main():
179180
jira_user = jira_user or jira_config.get('username')
180181
jira_api_token = jira_api_token or jira_config.get('api_token')
181182

182-
commit_code(API_URL, args.git_folder_path, token, args.message, open_terminal,
183+
commit_code(API_URL, token, args.message, open_terminal,
183184
llm_model, llm_api_base, llm_api_key,
184185
jira_url, jira_user, jira_api_token)
185186

penify_hook/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ def recursive_search_git_folder(folder_path):
9090
if os.path.isdir(folder_path):
9191
if '.git' in os.listdir(folder_path):
9292
return folder_path
93+
# reached the root of the filesystem
94+
elif folder_path == os.path.dirname(folder_path):
95+
return None
9396
else:
9497
return recursive_search_git_folder(os.path.dirname(folder_path))
9598

0 commit comments

Comments
 (0)