diff --git a/docs343/xml/Doxyfile.xml b/docs343/xml/Doxyfile.xml
new file mode 100644
index 0000000..56db19d
--- /dev/null
+++ b/docs343/xml/Doxyfile.xml
@@ -0,0 +1,391 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/README_8md.xml b/docs343/xml/README_8md.xml
new file mode 100644
index 0000000..d74636f
--- /dev/null
+++ b/docs343/xml/README_8md.xml
@@ -0,0 +1,179 @@
+
+
+
+ README.md
+
+
+
+
+
+#PenifyCLITool
+
+
+
+
+ACLItooltogeneratesmartcommitmessages,codedocumentation,andmore.
+
+##Features
+
+-Automaticallygeneratedocumentationforyourcode
+-Supportformultipleprogramminglanguages
+-Githookintegrationforautomaticdocumentationoncommits
+-Folderandfileanalysis
+
+##Installation
+
+InstallfromPyPI:
+
+```bash
+pipinstallpenify
+```
+
+##Usage
+
+PenifyCLIprovidesseveralsubcommandsfordifferentfunctionalities,organizedintobasiccommands(nologinrequired)andadvancedcommands(loginrequired).
+
+##BasicCommands(Nologinrequired)
+
+###Commit
+
+GeneratesmartcommitmessagesusinglocalLLM:
+
+```bash
+penifycommit[-m"Optionalmessage"][-e][-d]
+```
+
+Options:
+-`-m,--message`:Optionalcustomcommitmessage
+-`-e,--terminal`:Openeditortomodifycommitmessagebeforecommitting
+-`-d,--description`:Generatecommitmessagewithbothtitleanddescription(withoutthisflag,onlytitleisgenerated)
+
+###Config
+
+ConfigurelocalLLMandJIRAsettings:
+
+```bash
+#ConfigureLLMsettings
+penifyconfigllm--modelMODEL_NAME[--api-baseAPI_URL][--api-keyAPI_KEY]
+
+#ConfigureLLMsettingsthroughwebinterface
+penifyconfigllm-web
+
+#ConfigureJIRAsettings
+penifyconfigjira--urlJIRA_URL--usernameUSERNAME--api-tokenTOKEN[--verify]
+
+#ConfigureJIRAsettingsthroughwebinterface
+penifyconfigjira-web
+```
+
+##AdvancedCommands(Loginrequired)
+
+###Login
+
+TologinandobtainanAPItoken:
+
+```bash
+penifylogin
+```
+
+Thiscommandwillopenabrowserwindowforauthentication.Aftersuccessfullogin,theAPIkeywillbesavedlocallyforfutureuse.
+
+###DocumentationGeneration
+
+GeneratedocumentationforGitdiff,filesorfolders:
+
+```bash
+#GeneratedocumentationforlatestGitcommitdiff
+penifydocgen
+
+#Generatedocumentationforspecificfileorfolder
+penifydocgen-l/path/to/file/or/folder
+```
+
+Options:
+-`-l,--location`:Pathtospecificfileorfolderfordocumentationgeneration(defaultstocurrentdirectory)
+
+###GitHookManagement
+
+InstalloruninstallGitpost-commithooks:
+
+```bash
+#InstallGithook
+penifydocgeninstall-hook[-l/path/to/repo]
+
+#UninstallGithook
+penifydocgenuninstall-hook[-l/path/to/repo]
+```
+
+Options:
+-`-l,--location`:PathtotheGitrepository(defaultstocurrentdirectory)
+
+##Authentication
+
+PenifyCLIusesanAPItokenforauthenticationwithadvancedfeatures.
+
+Ifnotokenisavailableandyoutrytoaccessanadvancedfeature,you'llbepromptedtologin.
+
+##LocalLLMConfiguration
+
+Forcommitmessagegeneration,PenifycanusealocalLLM.Configureitusing:
+
+```bash
+penifyconfigllm--modelMODEL_NAME--api-baseAPI_URL--api-keyAPI_KEY
+```
+
+Commonconfigurations:
+-OpenAI:`--modelgpt-3.5-turbo--api-basehttps://api.openai.com/v1--api-keyYOUR_KEY`
+-Anthropic:`--modelclaude-2--api-basehttps://api.anthropic.com--api-keyYOUR_KEY`
+
+##JIRAIntegration
+
+ConfigureJIRAintegrationtoenhancecommitmessageswithissuedetails:
+
+```bash
+penifyconfigjira--urlhttps://your-domain.atlassian.net--usernameyour-email@example.com--api-tokenYOUR_API_TOKEN
+```
+
+##Development
+
+Tosetupthedevelopmentenvironment:
+
+1.Clonetherepository:
+```bash
+gitclonehttps://github.com/SingularityX-ai/penify-cli.git
+```
+
+2.Installthepackageineditablemode:
+```bash
+pipinstall-e.
+```
+
+###RunningTests
+
+```bash
+pytest
+```
+
+##License
+
+ThisprojectislicensedundertheMITLicense.
+
+##Author
+
+SumanSaurabh(ss.sumansaurabh92@gmail.com)
+
+##Contributing
+
+Contributionsarewelcome!PleasefeelfreetosubmitaPullRequest.
+
+##Issues
+
+Ifyouencounteranyproblemsorhavesuggestions,pleasefileanissueonthe[GitHubrepository](https://github.com/SingularityX-ai/penify/issues).
+
+##Support
+
+ForautomatedAPIDocumentation,ArchitectureDocumentation,CodeDocumentation,PullRequestDocumentation,orifyouneedademo,pleasejoinour[Discordsupportchannel](https://discord.gg/wqrc8JeV).
+
+
+
+
diff --git a/docs343/xml/api__client_8py.xml b/docs343/xml/api__client_8py.xml
new file mode 100644
index 0000000..2cc88a0
--- /dev/null
+++ b/docs343/xml/api__client_8py.xml
@@ -0,0 +1,183 @@
+
+
+
+ api_client.py
+ penify_hook::api_client::APIClient
+ penify_hook
+ penify_hook::api_client
+
+
+
+
+
+importjson
+importos
+importrequests
+from.llm_clientimportLLMClient
+
+class[APIClient]:
+def[__init__](self,api_url,api_token:str=None,bearer_token:str=None):
+self.[api_url]=api_url
+self.[AUTH_TOKEN]=api_token
+self.[BEARER_TOKEN]=bearer_token
+
+def[send_file_for_docstring_generation](self,file_name,content,line_numbers,repo_details=None):
+"""SendfilecontentandmodifiedlinestotheAPIandreturnmodified
+content.
+
+Thisfunctionconstructsapayloadcontainingthefilepath,content,
+andmodifiedlinenumbers,andsendsittoaspecifiedAPIendpointfor
+processing.IthandlestheresponsefromtheAPI,returningthemodified
+contentiftherequestissuccessful.Iftherequestfails,itlogsthe
+errordetailsandreturnstheoriginalcontent.
+
+Args:
+file_name(str):Thepathtothefilebeingsent.
+content(str):Thecontentofthefiletobeprocessed.
+line_numbers(list):Alistoflinenumbersthathavebeenmodified.
+repo_details(str?):Additionalrepositorydetailsifapplicable.DefaultstoNone.
+
+Returns:
+str:ThemodifiedcontentreturnedbytheAPI,ortheoriginalcontentifthe
+requestfails.
+
+Raises:
+Exception:Ifthereisanerrorinprocessingthefileandnospecificerror
+messageisprovided.
+"""
+payload={
+'file_path':file_name,
+'content':content,
+'modified_lines':line_numbers
+}
+ifrepo_details:
+payload['git_repo']=repo_details
+url=self.[api_url]+"/v1/cli/file/generate/doc"
+response=requests.post(url,json=payload,headers={"api-key":f"{self.AUTH_TOKEN}"},timeout=60*10)
+ifresponse.status_code==200:
+response=response.json()
+returnresponse.get('modified_content')
+else:
+error_message=response.json().get('detail')
+ifnoterror_message:
+error_message=response.text
+
+raise[Exception](f"APIError:{error_message}")
+
+def[generate_commit_summary](self,git_diff,instruction:str="",repo_details=None,jira_context:dict=None):
+"""GenerateacommitsummarybysendingaPOSTrequesttotheAPIendpoint.
+
+Thisfunctionconstructsapayloadcontainingthegitdiffandany
+additionalinstructionsprovided.Itthensendsthispayloadtoa
+specifiedAPIendpointtogenerateasummaryofthecommit.Ifthe
+requestissuccessful,itreturnstheresponsefromtheAPI;otherwise,
+itreturnsNone.
+
+Args:
+git_diff(str):Thegitdiffofthecommit.
+instruction(str??):Additionalinstructionforthecommit.Defaultsto"".
+repo_details(dict??):Detailsofthegitrepository.DefaultstoNone.
+jira_context(dict??):JIRAissuedetailstoenhancethecommitsummary.DefaultstoNone.
+
+Returns:
+dict:TheresponsefromtheAPIiftherequestissuccessful,Noneotherwise.
+
+Raises:
+Exception:IfthereisanerrorduringtheAPIrequest.
+"""
+payload={
+'git_diff':git_diff,
+'additional_instruction':instruction
+}
+ifrepo_details:
+payload['git_repo']=repo_details
+
+
+ifjira_context:
+payload['jira_context']=jira_context
+
+url=self.[api_url]+"/v1/cli/commit/summary"
+try:
+response=requests.post(url,json=payload,headers
+={"api-key":f"{self.AUTH_TOKEN}"},timeout=60*10)
+ifresponse.status_code==200:
+response=response.json()
+returnresponse
+else:
+
+
+raise[Exception](f"APIError:{response.text}")
+exceptExceptionase:
+print(f"Error:{e}")
+returnNone
+
+def[get_supported_file_types](self)->list[str]:
+"""RetrievethesupportedfiletypesfromtheAPI.
+
+ThisfunctionsendsarequesttotheAPIendpoint
+`/v1/file/supported_languages`toobtainalistofsupportedfiletypes.
+IftheAPIcallissuccessful(statuscode200),itparsestheJSON
+responseandreturnsthelistofsupportedfiletypes.IftheAPIcall
+fails,itreturnsadefaultlistofcommonfiletypes.
+
+Returns:
+list[str]:Alistofsupportedfiletypes,eitherfromtheAPIoradefaultset.
+"""
+
+url=self.[api_url]+"/v1/cli/supported_languages"
+response=requests.get(url)
+ifresponse.status_code==200:
+response=response.json()
+returnresponse
+else:
+return["py","js","ts","java","kt","cs","c"]
+
+def[generate_commit_summary_with_llm](self,diff,message,generate_description:bool,repo_details,llm_client:LLMClient,jira_context=None):
+"""GeneratesacommitsummaryusingalocalLLMclient.Ifanerroroccurs
+duringthegenerationprocess,
+itfallsbacktousingtheAPI.
+
+Args:
+diff(str):TheGitdiffofchanges.
+message(str):User-providedcommitmessageorinstructions.
+generate_description(bool):Flagindicatingwhethertogenerateadescriptionforthecommit.
+repo_details(dict):Detailsabouttherepository.
+llm_client(LLMClient):AninstanceofLLMClientusedtogeneratethesummary.
+jira_context(JIRAContext?):OptionalJIRAissuecontexttoenhancethesummary.
+
+Returns:
+dict:Adictionarycontainingthetitleanddescriptionforthecommit.
+"""
+try:
+returnllm_client.generate_commit_summary(diff,message,generate_description,repo_details,jira_context)
+exceptExceptionase:
+print(f"ErrorusinglocalLLM:{e}")
+
+returnself.[generate_commit_summary](diff,message,repo_details,jira_context)
+
+def[get_api_key](self):
+"""FetchanAPIkeyfromaspecifiedURL.
+
+ThisfunctionsendsaGETrequesttoretrieveanAPItokenusinga
+Bearertokenintheheaders.IthandlestheresponseandreturnstheAPI
+keyiftherequestissuccessful,or`None`otherwise.
+
+Returns:
+str:TheAPIkeyiftherequestissuccessful,`None`otherwise.
+"""
+
+
+url=self.[api_url]+"/v1/apiToken/get"
+response=requests.get(url,headers={"Authorization":f"Bearer{self.BEARER_TOKEN}"},timeout=60*10)
+ifresponse.status_code==200:
+response=response.json()
+returnresponse.get('key')
+else:
+print(f"Response:{response.status_code}")
+print(f"Error:{response.text}")
+returnNone
+
+
+
+
+
diff --git a/docs343/xml/auth__commands_8py.xml b/docs343/xml/auth__commands_8py.xml
new file mode 100644
index 0000000..307767a
--- /dev/null
+++ b/docs343/xml/auth__commands_8py.xml
@@ -0,0 +1,196 @@
+
+
+
+ auth_commands.py
+ penify_hook
+ penify_hook::commands
+ penify_hook::commands::auth_commands
+
+
+
+
+
+importjson
+importwebbrowser
+importhttp.server
+importsocketserver
+importurllib.parse
+importrandom
+importos
+fromthreadingimportThread
+frompathlibimportPath
+
+def[save_credentials](api_key):
+"""
+SavethetokenandAPIkeysbasedonpriority:
+1..envfileinGitreporoot(ifinagitrepo)
+2..penifyfileinhomedirectory(globalfallback)
+
+Args:
+api_key:TheAPIkeytosave
+
+Returns:
+bool:Trueifsavedsuccessfully,Falseotherwise
+"""
+
+try:
+from..utilsimportrecursive_search_git_folder
+current_dir=os.getcwd()
+repo_root=[recursive_search_git_folder](current_dir)
+
+ifrepo_root:
+
+env_file=Path(repo_root)/'.env'
+try:
+
+env_content={}
+ifenv_file.exists():
+withopen(env_file,'r')asf:
+forlineinf:
+line=line.strip()
+iflineandnotline.startswith('#')and'='inline:
+key,value=line.split('=',1)
+env_content[key.strip()]=value.strip()
+
+
+env_content['PENIFY_API_TOKEN']=api_key
+
+
+withopen(env_file,'w')asf:
+forkey,valueinenv_content.items():
+f.write(f"{key}={value}\n")
+
+print(f"APItokensavedto{env_file}")
+returnTrue
+exceptExceptionase:
+print(f"Errorsavingto.envfile:{str(e)}")
+
+exceptExceptionase:
+print(f"Errorfindinggitrepository:{str(e)}")
+
+
+home_dir=Path.home()
+penify_file=home_dir/'.penify'
+
+
+ifpenify_file.exists():
+withopen(penify_file,'r')asf:
+credentials=json.load(f)
+credentials['api_keys']=api_key
+else:
+credentials={
+'api_keys':api_key
+}
+
+try:
+withopen(penify_file,'w')asf:
+json.dump(credentials,f)
+print(f"APItokensavedtoglobalconfig{penify_file}")
+returnTrue
+exceptExceptionase:
+print(f"Errorsavingcredentials:{str(e)}")
+returnFalse
+
+def[login](api_url,dashboard_url):
+"""OpentheloginpageinawebbrowserandlistenfortheredirectURLto
+capturethetoken.
+
+Thisfunctiongeneratesarandomredirectport,constructsthefull
+loginURLwiththeprovideddashboardURL,openstheloginpageinthe
+defaultwebbrowser,andsetsupasimpleHTTPservertolistenforthe
+redirect.Uponreceivingtheredirect,itextractsthetokenfromthe
+queryparameters,fetchesAPIkeysusingthetoken,savesthemif
+successful,andhandlesloginfailuresbynotifyingtheuser.
+
+Args:
+api_url(str):TheURLoftheAPIservicetofetchAPIkeys.
+dashboard_url(str):TheURLofthedashboardwheretheuserwillberedirectedafterlogging
+in.
+"""
+redirect_port=random.randint(30000,50000)
+redirect_url=f"http://localhost:{redirect_port}/callback"
+
+full_login_url=f"{dashboard_url}?redirectUri={urllib.parse.quote(redirect_url)}"
+
+print(f"Openingloginpageinyourdefaultwebbrowser:{full_login_url}")
+webbrowser.open(full_login_url)
+
+classTokenHandler(http.server.SimpleHTTPRequestHandler):
+defdo_GET(self):
+"""HandleaGETrequesttoprocesslogintokenandredirectordisplay
+errormessage.
+
+ThismethodprocessestheincomingGETrequest,extractsthetokenfrom
+thequerystring,andperformsactionsbasedonwhetherthetokenis
+present.Ifthetokenisvalid,itredirectstheusertothePenify
+dashboardandfetchesAPIkeysifsuccessful.Ifthetokenisinvalid,
+itdisplaysanerrormessage.
+"""
+
+query=urllib.parse.urlparse(self.path).query
+query_components=urllib.parse.parse_qs(query)
+token=query_components.get("token",[None])[0]
+
+iftoken:
+self.send_response(200)
+self.send_header("Content-type","text/html")
+self.end_headers()
+response="""
+<html>
+<head>
+<script>
+setTimeout(function(){
+window.location.href='https://dashboard.penify.dev';
+},5000);
+</script>
+</head>
+<body>
+<h1>LoginSuccessful!</h1>
+<p>YouwillberedirectedtothePenifydashboardin5seconds.YoucanalsoclosethiswindowandreturntotheCLI.</p>
+</body>
+</html>
+"""
+self.wfile.write(response.encode())
+
+print(f"\nLoginsuccessful!FetchingAPIkeys...")
+from..api_clientimportAPIClient
+api_key=APIClient(api_url,None,token).get_api_key()
+ifapi_key:
+[save_credentials](api_key)
+print("APIkeysfetchedandsavedsuccessfully.")
+print("You'llberedirectedtothePenifydashboard.YoucancontinueusingtheCLI.")
+else:
+print("FailedtofetchAPIkeys.")
+else:
+self.send_response(400)
+self.send_header("Content-type","text/html")
+self.end_headers()
+response="""
+<html>
+<body>
+<h1>LoginFailed</h1>
+<p>Pleasetryagain.</p>
+</body>
+</html>
+"""
+self.wfile.write(response.encode())
+print("\nLoginfailed.Pleasetryagain.")
+
+
+thread=Thread(target=self.server.shutdown)
+thread.daemon=True
+thread.start()
+
+deflog_message(self,format,*args):
+
+return
+
+withsocketserver.TCPServer(("",redirect_port),TokenHandler)ashttpd:
+print(f"Listeningonport{redirect_port}fortheredirect...")
+httpd.serve_forever()
+
+print("Loginprocesscompleted.YoucannowuseothercommandswithyourAPItoken.")
+
+
+
+
diff --git a/docs343/xml/base__analyzer_8py.xml b/docs343/xml/base__analyzer_8py.xml
new file mode 100644
index 0000000..3071dfd
--- /dev/null
+++ b/docs343/xml/base__analyzer_8py.xml
@@ -0,0 +1,36 @@
+
+
+
+ base_analyzer.py
+ penify_hook::base_analyzer::BaseAnalyzer
+ penify_hook
+ penify_hook::base_analyzer
+
+
+
+
+
+importos
+fromgitimportRepo
+from.api_clientimportAPIClient
+from[penify_hook.utils]importget_repo_details,recursive_search_git_folder
+
+
+class[BaseAnalyzer]:
+
+def[__init__](self,folder_path:str,api_client:APIClient):
+self.[folder_path]=folder_path
+self.[repo_path]=[recursive_search_git_folder](folder_path)
+self.[repo]=None
+self.[repo_details]=None
+ifself.[folder_path]:
+self.[repo]=Repo(self.[repo_path])
+self.[repo_details]=[get_repo_details](self.[repo])
+
+self.[relative_file_path]=os.path.relpath(folder_path)
+self.[api_client]=api_client
+self.[supported_file_types]=set(api_client.get_supported_file_types())
+
+
+
+
diff --git a/docs343/xml/classException.xml b/docs343/xml/classException.xml
new file mode 100644
index 0000000..2277730
--- /dev/null
+++ b/docs343/xml/classException.xml
@@ -0,0 +1,32 @@
+
+
+
+ Exception
+ penify_hook.utils.GitRepoNotFoundError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1api__client_1_1APIClient.xml b/docs343/xml/classpenify__hook_1_1api__client_1_1APIClient.xml
new file mode 100644
index 0000000..8711c1a
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1api__client_1_1APIClient.xml
@@ -0,0 +1,346 @@
+
+
+
+ penify_hook::api_client::APIClient
+
+
+
+ penify_hook.api_client.APIClient::api_url
+
+ api_url
+ penify_hook.api_client.APIClient.api_url
+
+
+
+
+
+
+
+ penify_hook.api_client.APIClient.generate_commit_summary
+ penify_hook.api_client.APIClient.get_api_key
+ penify_hook.api_client.APIClient.get_supported_file_types
+ penify_hook.api_client.APIClient.send_file_for_docstring_generation
+
+
+
+ penify_hook.api_client.APIClient::AUTH_TOKEN
+
+ AUTH_TOKEN
+ penify_hook.api_client.APIClient.AUTH_TOKEN
+
+
+
+
+
+
+
+
+
+
+ penify_hook.api_client.APIClient::BEARER_TOKEN
+
+ BEARER_TOKEN
+ penify_hook.api_client.APIClient.BEARER_TOKEN
+
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.api_client.APIClient.__init__
+ (self, api_url, str api_token=None, str bearer_token=None)
+ __init__
+ penify_hook.api_client.APIClient.__init__
+
+ self
+ self
+
+
+ [api_url]
+ api_url
+
+
+ str
+ api_token
+ None
+
+
+ str
+ bearer_token
+ None
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.api_client.APIClient.send_file_for_docstring_generation
+ (self, file_name, content, line_numbers, repo_details=None)
+ send_file_for_docstring_generation
+ penify_hook.api_client.APIClient.send_file_for_docstring_generation
+
+ self
+ self
+
+
+ file_name
+ file_name
+
+
+ content
+ content
+
+
+ line_numbers
+ line_numbers
+
+
+ repo_details
+ repo_details
+ None
+
+
+
+
+Send file content and modified lines to the API and return modified
+content.
+
+This function constructs a payload containing the file path, content,
+and modified line numbers, and sends it to a specified API endpoint for
+processing. It handles the response from the API, returning the modified
+content if the request is successful. If the request fails, it logs the
+error details and returns the original content.
+
+Args:
+ file_name (str): The path to the file being sent.
+ content (str): The content of the file to be processed.
+ line_numbers (list): A list of line numbers that have been modified.
+ repo_details (str?): Additional repository details if applicable. Defaults to None.
+
+Returns:
+ str: The modified content returned by the API, or the original content if the
+ request fails.
+
+Raises:
+ Exception: If there is an error in processing the file and no specific error
+ message is provided.
+
+
+
+
+
+ penify_hook.api_client.APIClient.api_url
+
+
+ def
+ def penify_hook.api_client.APIClient.generate_commit_summary
+ (self, git_diff, str instruction="", repo_details=None, dict jira_context=None)
+ generate_commit_summary
+ penify_hook.api_client.APIClient.generate_commit_summary
+
+ self
+ self
+
+
+ git_diff
+ git_diff
+
+
+ str
+ instruction
+ ""
+
+
+ repo_details
+ repo_details
+ None
+
+
+ dict
+ jira_context
+ None
+
+
+
+
+Generate a commit summary by sending a POST request to the API endpoint.
+
+This function constructs a payload containing the git diff and any
+additional instructions provided. It then sends this payload to a
+specified API endpoint to generate a summary of the commit. If the
+request is successful, it returns the response from the API; otherwise,
+it returns None.
+
+Args:
+ git_diff (str): The git diff of the commit.
+ instruction (str??): Additional instruction for the commit. Defaults to "".
+ repo_details (dict??): Details of the git repository. Defaults to None.
+ jira_context (dict??): JIRA issue details to enhance the commit summary. Defaults to None.
+
+Returns:
+ dict: The response from the API if the request is successful, None otherwise.
+
+Raises:
+ Exception: If there is an error during the API request.
+
+
+
+
+
+ penify_hook.api_client.APIClient.api_url
+ penify_hook.api_client.APIClient.generate_commit_summary_with_llm
+
+
+ list[str]
+ list[str] penify_hook.api_client.APIClient.get_supported_file_types
+ (self)
+ get_supported_file_types
+ penify_hook.api_client.APIClient.get_supported_file_types
+
+ self
+ self
+
+
+
+
+Retrieve the supported file types from the API.
+
+This function sends a request to the API endpoint
+`/v1/file/supported_languages` to obtain a list of supported file types.
+If the API call is successful (status code 200), it parses the JSON
+response and returns the list of supported file types. If the API call
+fails, it returns a default list of common file types.
+
+Returns:
+ list[str]: A list of supported file types, either from the API or a default set.
+
+
+
+
+
+ penify_hook.api_client.APIClient.api_url
+
+
+ def
+ def penify_hook.api_client.APIClient.generate_commit_summary_with_llm
+ (self, diff, message, bool generate_description, repo_details, LLMClient llm_client, jira_context=None)
+ generate_commit_summary_with_llm
+ penify_hook.api_client.APIClient.generate_commit_summary_with_llm
+
+ self
+ self
+
+
+ diff
+ diff
+
+
+ message
+ message
+
+
+ bool
+ generate_description
+
+
+ repo_details
+ repo_details
+
+
+ [LLMClient]
+ llm_client
+
+
+ jira_context
+ jira_context
+ None
+
+
+
+
+Generates a commit summary using a local LLM client. If an error occurs
+during the generation process,
+it falls back to using the API.
+
+Args:
+ diff (str): The Git diff of changes.
+ message (str): User-provided commit message or instructions.
+ generate_description (bool): Flag indicating whether to generate a description for the commit.
+ repo_details (dict): Details about the repository.
+ llm_client (LLMClient): An instance of LLMClient used to generate the summary.
+ jira_context (JIRAContext?): Optional JIRA issue context to enhance the summary.
+
+Returns:
+ dict: A dictionary containing the title and description for the commit.
+
+
+
+
+
+ penify_hook.api_client.APIClient.generate_commit_summary
+ penify_hook.llm_client.LLMClient.generate_commit_summary
+
+
+ def
+ def penify_hook.api_client.APIClient.get_api_key
+ (self)
+ get_api_key
+ penify_hook.api_client.APIClient.get_api_key
+
+ self
+ self
+
+
+
+
+Fetch an API key from a specified URL.
+
+This function sends a GET request to retrieve an API token using a
+Bearer token in the headers. It handles the response and returns the API
+key if the request is successful, or `None` otherwise.
+
+Returns:
+ str: The API key if the request is successful, `None` otherwise.
+
+
+
+
+
+ penify_hook.api_client.APIClient.api_url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ penify_hook::api_client::APIClient__init__
+ penify_hook::api_client::APIClientapi_url
+ penify_hook::api_client::APIClientAUTH_TOKEN
+ penify_hook::api_client::APIClientBEARER_TOKEN
+ penify_hook::api_client::APIClientgenerate_commit_summary
+ penify_hook::api_client::APIClientgenerate_commit_summary_with_llm
+ penify_hook::api_client::APIClientget_api_key
+ penify_hook::api_client::APIClientget_supported_file_types
+ penify_hook::api_client::APIClientsend_file_for_docstring_generation
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1base__analyzer_1_1BaseAnalyzer.xml b/docs343/xml/classpenify__hook_1_1base__analyzer_1_1BaseAnalyzer.xml
new file mode 100644
index 0000000..78661b0
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1base__analyzer_1_1BaseAnalyzer.xml
@@ -0,0 +1,211 @@
+
+
+
+ penify_hook::base_analyzer::BaseAnalyzer
+ penify_hook.commit_analyzer.CommitDocGenHook
+ penify_hook.file_analyzer.FileAnalyzerGenHook
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook
+ penify_hook.git_analyzer.GitDocGenHook
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::folder_path
+
+ folder_path
+ penify_hook.base_analyzer.BaseAnalyzer.folder_path
+
+
+
+
+
+
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::repo_path
+
+ repo_path
+ penify_hook.base_analyzer.BaseAnalyzer.repo_path
+
+
+
+
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook._amend_commit
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::repo
+
+ repo
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+
+
+
+
+
+
+
+ penify_hook.git_analyzer.GitDocGenHook.get_modified_files_in_last_commit
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+ penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+ penify_hook.git_analyzer.GitDocGenHook.run
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::repo_details
+
+ repo_details
+ penify_hook.base_analyzer.BaseAnalyzer.repo_details
+
+
+
+
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::relative_file_path
+
+ relative_file_path
+ penify_hook.base_analyzer.BaseAnalyzer.relative_file_path
+
+
+
+
+
+
+
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::api_client
+
+ api_client
+ penify_hook.base_analyzer.BaseAnalyzer.api_client
+
+
+
+
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.run
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer::supported_file_types
+
+ supported_file_types
+ penify_hook.base_analyzer.BaseAnalyzer.supported_file_types
+
+
+
+
+
+
+
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+
+
+
+
+ def
+ def penify_hook.base_analyzer.BaseAnalyzer.__init__
+ (self, str folder_path, APIClient api_client)
+ __init__
+ penify_hook.base_analyzer.BaseAnalyzer.__init__
+ __init__
+ __init__
+ __init__
+ __init__
+
+ self
+ self
+
+
+ str
+ folder_path
+
+
+ [APIClient]
+ api_client
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ penify_hook::base_analyzer::BaseAnalyzer__init__
+ penify_hook::base_analyzer::BaseAnalyzerapi_client
+ penify_hook::base_analyzer::BaseAnalyzerfolder_path
+ penify_hook::base_analyzer::BaseAnalyzerrelative_file_path
+ penify_hook::base_analyzer::BaseAnalyzerrepo
+ penify_hook::base_analyzer::BaseAnalyzerrepo_details
+ penify_hook::base_analyzer::BaseAnalyzerrepo_path
+ penify_hook::base_analyzer::BaseAnalyzersupported_file_types
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1commit__analyzer_1_1CommitDocGenHook.xml b/docs343/xml/classpenify__hook_1_1commit__analyzer_1_1CommitDocGenHook.xml
new file mode 100644
index 0000000..8d77f23
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1commit__analyzer_1_1CommitDocGenHook.xml
@@ -0,0 +1,288 @@
+
+
+
+ penify_hook::commit_analyzer::CommitDocGenHook
+ penify_hook.base_analyzer.BaseAnalyzer
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook::llm_client
+
+ llm_client
+ penify_hook.commit_analyzer.CommitDocGenHook.llm_client
+
+
+
+
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+
+
+
+
+ def
+ def penify_hook.commit_analyzer.CommitDocGenHook.__init__
+ (self, str repo_path, APIClient api_client, llm_client=None, jira_client=None)
+ __init__
+ penify_hook.commit_analyzer.CommitDocGenHook.__init__
+ __init__
+
+ self
+ self
+
+
+ str
+ repo_path
+
+
+ [APIClient]
+ api_client
+
+
+ [llm_client]
+ llm_client
+ None
+
+
+ jira_client
+ jira_client
+ None
+
+
+
+
+
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook.__init__
+ penify_hook.commit_analyzer.CommitDocGenHook.__init__
+
+
+ dict
+ dict penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ (self, str instruction, bool generate_description)
+ get_summary
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+
+ self
+ self
+
+
+ str
+ instruction
+
+
+ bool
+ generate_description
+
+
+
+
+Generate a summary for the commit based on the staged changes.
+
+This function retrieves the differences of the staged changes in the
+repository and generates a commit summary using the provided
+instruction. If there are no changes staged for commit, an exception is
+raised. If a JIRA client is connected, it will attempt to extract issue
+keys from the current branch and use them to fetch context. The summary
+can be generated either with a Language Model (LLM) client or through
+the API client.
+
+Args:
+ instruction (str): A string containing instructions for generating the commit summary.
+ generate_description (bool): Whether to include detailed descriptions in the summary.
+
+Returns:
+ dict: The generated commit summary based on the staged changes, provided
+ instruction, and any relevant JIRA context. The dictionary contains keys
+ such as 'summary', 'description', etc., depending on whether a
+ description was requested.
+
+Raises:
+ ValueError: If there are no changes staged for commit.
+
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer.api_client
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.commit_analyzer.CommitDocGenHook.llm_client
+ penify_hook.ui_utils.print_info
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+ penify_hook.base_analyzer.BaseAnalyzer.repo_details
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+
+ def
+ def penify_hook.commit_analyzer.CommitDocGenHook.run
+ (self, Optional[str] msg, bool edit_commit_message, bool generate_description)
+ run
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+ self
+ self
+
+
+ Optional
+ msg
+ [str]
+
+
+ bool
+ edit_commit_message
+
+
+ bool
+ generate_description
+
+
+
+
+Run the post-commit hook.
+
+This method processes the modified files from the last commit, stages
+them, and creates an auto-commit with an optional message. It also
+handles JIRA integration if available. If there is an error generating
+the commit summary, an exception is raised.
+
+Args:
+ msg (Optional[str]): An optional message to include in the commit.
+ edit_commit_message (bool): A flag indicating whether to open the git commit edit terminal after
+ committing.
+ generate_description (bool): A flag indicating whether to include a description in the commit
+ message.
+
+Raises:
+ Exception: If there is an error generating the commit summary.
+
+
+
+
+
+ penify_hook.commit_analyzer.CommitDocGenHook._amend_commit
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.ui_utils.print_info
+ penify_hook.ui_utils.print_success
+ penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+
+
+ tuple
+ tuple penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+ (self, str title, str description, str msg)
+ process_jira_integration
+ penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+
+ self
+ self
+
+
+ str
+ title
+
+
+ str
+ description
+
+
+ str
+ msg
+
+
+
+
+Process JIRA integration for the commit message.
+
+Args:
+ title (str): Generated commit title.
+ description (str): Generated commit description.
+ msg (str): Original user message that might contain JIRA references.
+
+Returns:
+ tuple: A tuple containing the updated commit title and description with
+ included JIRA information.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.ui_utils.print_info
+ penify_hook.ui_utils.print_warning
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+
+
+
+ def
+ def penify_hook.commit_analyzer.CommitDocGenHook._amend_commit
+ (self)
+ _amend_commit
+ penify_hook.commit_analyzer.CommitDocGenHook._amend_commit
+
+ self
+ self
+
+
+
+
+Open the default git editor for editing the commit message.
+
+This function changes the current working directory to the repository
+path, runs the git command to amend the last commit, and opens the
+default editor for the user to modify the commit message. After the
+operation, it returns to the original directory.
+
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer.repo_path
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ penify_hook::commit_analyzer::CommitDocGenHook__init__
+ penify_hook::commit_analyzer::CommitDocGenHook_amend_commit
+ penify_hook::commit_analyzer::CommitDocGenHookget_summary
+ penify_hook::commit_analyzer::CommitDocGenHookllm_client
+ penify_hook::commit_analyzer::CommitDocGenHookprocess_jira_integration
+ penify_hook::commit_analyzer::CommitDocGenHookrun
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1file__analyzer_1_1FileAnalyzerGenHook.xml b/docs343/xml/classpenify__hook_1_1file__analyzer_1_1FileAnalyzerGenHook.xml
new file mode 100644
index 0000000..c07f4fd
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1file__analyzer_1_1FileAnalyzerGenHook.xml
@@ -0,0 +1,184 @@
+
+
+
+ penify_hook::file_analyzer::FileAnalyzerGenHook
+ penify_hook.base_analyzer.BaseAnalyzer
+
+
+
+ penify_hook.file_analyzer.FileAnalyzerGenHook::file_path
+
+ file_path
+ penify_hook.file_analyzer.FileAnalyzerGenHook.file_path
+
+
+
+
+
+
+
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+
+
+
+
+ def
+ def penify_hook.file_analyzer.FileAnalyzerGenHook.__init__
+ (self, str file_path, APIClient api_client)
+ __init__
+ penify_hook.file_analyzer.FileAnalyzerGenHook.__init__
+ __init__
+
+ self
+ self
+
+
+ str
+ file_path
+
+
+ [APIClient]
+ api_client
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+ (self, file_path, pbar, str new_param="")
+ process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+
+ self
+ self
+
+
+ [file_path]
+ file_path
+
+
+ pbar
+ pbar
+
+
+ str
+ new_param
+ ""
+
+
+
+
+Processes a file by validating its extension, reading content, generating documentation,
+and writing changes back to the file.
+
+Args:
+ file_path (str): The path of the file to be processed.
+ pbar (tqdm.tqdm): A progress bar object to update the status of processing stages.
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer.api_client
+ penify_hook.ui_utils.print_warning
+ penify_hook.base_analyzer.BaseAnalyzer.relative_file_path
+ penify_hook.base_analyzer.BaseAnalyzer.repo_details
+ penify_hook.base_analyzer.BaseAnalyzer.supported_file_types
+ penify_hook.ui_utils.update_stage
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+
+ def
+ def penify_hook.file_analyzer.FileAnalyzerGenHook.print_processing
+ (self, file_path)
+ print_processing
+ penify_hook.file_analyzer.FileAnalyzerGenHook.print_processing
+
+ self
+ self
+
+
+ [file_path]
+ file_path
+
+
+
+
+Prints a formatted message indicating that a file is being processed.
+
+
+
+
+ penify_hook.ui_utils.format_file_path
+
+
+ def
+ def penify_hook.file_analyzer.FileAnalyzerGenHook.run
+ (self)
+ run
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+
+ self
+ self
+
+
+
+
+Runs the documentation process with a progress bar.
+
+
+
+
+ penify_hook.ui_utils.create_stage_progress_bar
+ penify_hook.file_analyzer.FileAnalyzerGenHook.file_path
+ penify_hook.ui_utils.print_status
+ penify_hook.ui_utils.print_success
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+ penify_hook.ui_utils.update_stage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ penify_hook::file_analyzer::FileAnalyzerGenHook__init__
+ penify_hook::file_analyzer::FileAnalyzerGenHookfile_path
+ penify_hook::file_analyzer::FileAnalyzerGenHookprint_processing
+ penify_hook::file_analyzer::FileAnalyzerGenHookprocess_file
+ penify_hook::file_analyzer::FileAnalyzerGenHookrun
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1folder__analyzer_1_1FolderAnalyzerGenHook.xml b/docs343/xml/classpenify__hook_1_1folder__analyzer_1_1FolderAnalyzerGenHook.xml
new file mode 100644
index 0000000..a19eb53
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1folder__analyzer_1_1FolderAnalyzerGenHook.xml
@@ -0,0 +1,158 @@
+
+
+
+ penify_hook::folder_analyzer::FolderAnalyzerGenHook
+ penify_hook.base_analyzer.BaseAnalyzer
+
+
+
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook::dir_path
+
+ dir_path
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.dir_path
+
+
+
+
+
+
+
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.run
+
+
+
+
+ def
+ def penify_hook.folder_analyzer.FolderAnalyzerGenHook.__init__
+ (self, str dir_path, APIClient api_client)
+ __init__
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.__init__
+ __init__
+
+ self
+ self
+
+
+ str
+ dir_path
+
+
+ [APIClient]
+ api_client
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.folder_analyzer.FolderAnalyzerGenHook.list_all_files_in_dir
+ (self, str dir_path)
+ list_all_files_in_dir
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.list_all_files_in_dir
+
+ self
+ self
+
+
+ str
+ dir_path
+
+
+
+
+List all non-hidden files in a directory and its subdirectories.
+
+This function recursively traverses the specified directory and its
+subdirectories, collecting paths of all non-hidden files. It filters out
+hidden directories and files (those starting with a dot) to ensure only
+visible files are returned.
+
+Args:
+ dir_path (str): The path to the directory whose files and subdirectory files need to be
+ listed.
+
+Returns:
+ list: A list containing the full paths of all non-hidden files within the
+ specified directory and its subdirectories.
+
+
+
+
+
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.run
+
+
+ def
+ def penify_hook.folder_analyzer.FolderAnalyzerGenHook.run
+ (self)
+ run
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.run
+
+ self
+ self
+
+
+
+
+Run the post-commit hook.
+
+This function processes all files in a specified directory using a
+progress bar. It lists all files, initializes a `FileAnalyzerGenHook`
+for each file, and runs it. Errors during processing of individual files
+are caught and logged, but do not stop the processing of other files. A
+progress bar is displayed indicating the number of files processed.
+
+Args:
+ self (PostCommitHook): The instance of the post-commit hook class.
+
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer.api_client
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.dir_path
+ penify_hook.folder_analyzer.FolderAnalyzerGenHook.list_all_files_in_dir
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ penify_hook::folder_analyzer::FolderAnalyzerGenHook__init__
+ penify_hook::folder_analyzer::FolderAnalyzerGenHookdir_path
+ penify_hook::folder_analyzer::FolderAnalyzerGenHooklist_all_files_in_dir
+ penify_hook::folder_analyzer::FolderAnalyzerGenHookrun
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1git__analyzer_1_1GitDocGenHook.xml b/docs343/xml/classpenify__hook_1_1git__analyzer_1_1GitDocGenHook.xml
new file mode 100644
index 0000000..0cc4d5a
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1git__analyzer_1_1GitDocGenHook.xml
@@ -0,0 +1,228 @@
+
+
+
+ penify_hook::git_analyzer::GitDocGenHook
+ penify_hook.base_analyzer.BaseAnalyzer
+
+
+ def
+ def penify_hook.git_analyzer.GitDocGenHook.__init__
+ (self, str repo_path, APIClient api_client)
+ __init__
+ penify_hook.git_analyzer.GitDocGenHook.__init__
+ __init__
+
+ self
+ self
+
+
+ str
+ repo_path
+
+
+ [APIClient]
+ api_client
+
+
+
+
+
+
+
+
+ penify_hook.git_analyzer.GitDocGenHook.__init__
+ penify_hook.git_analyzer.GitDocGenHook.__init__
+
+
+ def
+ def penify_hook.git_analyzer.GitDocGenHook.get_modified_files_in_last_commit
+ (self)
+ get_modified_files_in_last_commit
+ penify_hook.git_analyzer.GitDocGenHook.get_modified_files_in_last_commit
+
+ self
+ self
+
+
+
+
+Get the list of files modified in the last commit.
+
+This function retrieves the files that were modified in the most recent
+commit of the repository. It accesses the last commit and iterates
+through the differences to compile a list of unique file paths that were
+changed. The function returns this list for further processing or
+analysis.
+
+Returns:
+ list: A list of file paths that were modified in the last commit.
+
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+
+ def
+ def penify_hook.git_analyzer.GitDocGenHook.get_modified_lines
+ (self, diff_text)
+ get_modified_lines
+ penify_hook.git_analyzer.GitDocGenHook.get_modified_lines
+
+ self
+ self
+
+
+ diff_text
+ diff_text
+
+
+
+
+Extract modified line numbers from a diff text.
+
+This function processes a diff text to identify and extract the line
+numbers that have been modified. It distinguishes between added and
+deleted lines and keeps track of the current line number as it parses
+through the diff. The function handles hunk headers and ensures that any
+deletions at the end of the file are also captured.
+
+Args:
+ diff_text (str): A string containing the diff text to be processed.
+
+Returns:
+ list: A sorted list of unique line numbers that have been modified.
+
+
+
+
+
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+
+
+ def
+ def penify_hook.git_analyzer.GitDocGenHook.process_file
+ (self, file_path)
+ process_file
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+
+ self
+ self
+
+
+ file_path
+ file_path
+
+
+
+
+Process a file by checking its type, reading its content, and sending it
+to an API.
+
+This method constructs the absolute path of the specified file and
+verifies if the file has a valid extension. If the file type is
+supported, it reads the content of the file and retrieves the
+differences from the last commit in the repository. If changes are
+detected, it sends the file content along with the modified lines to an
+API for further processing. If the API response indicates no changes,
+the original file will not be overwritten.
+
+Args:
+ file_path (str): The relative path to the file to be processed.
+
+Returns:
+ bool: True if the file was successfully processed and updated, False
+ otherwise.
+
+
+
+
+
+ penify_hook.base_analyzer.BaseAnalyzer.api_client
+ penify_hook.git_analyzer.GitDocGenHook.get_modified_lines
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+ penify_hook.base_analyzer.BaseAnalyzer.repo_details
+ penify_hook.base_analyzer.BaseAnalyzer.repo_path
+ penify_hook.base_analyzer.BaseAnalyzer.supported_file_types
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+
+ def
+ def penify_hook.git_analyzer.GitDocGenHook.run
+ (self)
+ run
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+ self
+ self
+
+
+
+
+Run the post-commit hook.
+
+This method retrieves the list of modified files from the last commit
+and processes each file. It stages any files that have been modified
+during processing and creates an auto-commit if changes were made. A
+progress bar is displayed to indicate the processing status of each
+file. The method handles any exceptions that occur during file
+processing, printing an error message for each file that fails to
+process. If any modifications are made to the files, an auto-commit is
+created to save those changes.
+
+
+
+
+
+ penify_hook.ui_utils.create_progress_bar
+ penify_hook.git_analyzer.GitDocGenHook.get_modified_files_in_last_commit
+ penify_hook.ui_utils.print_info
+ penify_hook.ui_utils.print_processing
+ penify_hook.ui_utils.print_status
+ penify_hook.ui_utils.print_success
+ penify_hook.git_analyzer.GitDocGenHook.process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+ penify_hook.base_analyzer.BaseAnalyzer.repo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ penify_hook::git_analyzer::GitDocGenHook__init__
+ penify_hook::git_analyzer::GitDocGenHookget_modified_files_in_last_commit
+ penify_hook::git_analyzer::GitDocGenHookget_modified_lines
+ penify_hook::git_analyzer::GitDocGenHookprocess_file
+ penify_hook::git_analyzer::GitDocGenHookrun
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1jira__client_1_1JiraClient.xml b/docs343/xml/classpenify__hook_1_1jira__client_1_1JiraClient.xml
new file mode 100644
index 0000000..04a4435
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1jira__client_1_1JiraClient.xml
@@ -0,0 +1,559 @@
+
+
+
+ penify_hook::jira_client::JiraClient
+
+
+
+ penify_hook.jira_client.JiraClient::jira_url
+
+ jira_url
+ penify_hook.jira_client.JiraClient.jira_url
+
+
+
+
+
+
+
+
+
+
+ penify_hook.jira_client.JiraClient::jira_user
+
+ jira_user
+ penify_hook.jira_client.JiraClient.jira_user
+
+
+
+
+
+
+
+
+
+
+ penify_hook.jira_client.JiraClient::jira_api_token
+
+ jira_api_token
+ penify_hook.jira_client.JiraClient.jira_api_token
+
+
+
+
+
+
+
+
+
+
+ penify_hook.jira_client.JiraClient::jira_client
+
+ jira_client
+ penify_hook.jira_client.JiraClient.jira_client
+
+
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.add_comment
+ penify_hook.jira_client.JiraClient.get_detailed_issue_context
+ penify_hook.jira_client.JiraClient.get_issue_details
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+ penify_hook.jira_client.JiraClient.update_issue_status
+
+
+
+
+ def
+ def penify_hook.jira_client.JiraClient.__init__
+ (self, str jira_url=None, str jira_user=None, str jira_api_token=None)
+ __init__
+ penify_hook.jira_client.JiraClient.__init__
+
+ self
+ self
+
+
+ str
+ jira_url
+ None
+
+
+ str
+ jira_user
+ None
+
+
+ str
+ jira_api_token
+ None
+
+
+
+
+Initialize the JIRA client.
+
+Args:
+ jira_url: Base URL for JIRA instance (e.g., "https://your-domain.atlassian.net")
+ jira_user: JIRA username or email
+ jira_api_token: JIRA API token
+
+
+
+
+
+
+
+ bool
+ bool penify_hook.jira_client.JiraClient.is_connected
+ (self)
+ is_connected
+ penify_hook.jira_client.JiraClient.is_connected
+
+ self
+ self
+
+
+
+
+Check if the JIRA client is connected.
+
+This function verifies whether the JIRA client has successfully
+established a connection. It returns `True` if the client is connected,
+and `False` otherwise.
+
+Returns:
+ bool: True if the JIRA client is connected, False otherwise
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.jira_client.JiraClient.add_comment
+ penify_hook.jira_client.JiraClient.enhance_commit_message
+ penify_hook.jira_client.JiraClient.format_commit_message_with_jira_info
+ penify_hook.jira_client.JiraClient.get_commit_context_from_issues
+ penify_hook.jira_client.JiraClient.get_detailed_issue_context
+ penify_hook.jira_client.JiraClient.get_issue_details
+ penify_hook.jira_client.JiraClient.update_issue_status
+
+
+ List[str]
+ List[str] penify_hook.jira_client.JiraClient.extract_issue_keys_from_branch
+ (self, str branch_name)
+ extract_issue_keys_from_branch
+ penify_hook.jira_client.JiraClient.extract_issue_keys_from_branch
+
+ self
+ self
+
+
+ str
+ branch_name
+
+
+
+
+Extracts JIRA issue keys from a branch name.
+
+This function searches through a given git branch name to find and
+return any JIRA issue keys that match the pattern. Common conventions
+for JIRA issue keys in branch names include: -
+feature/PROJECT-123-description - bugfix/PROJECT-123-fix-something -
+hotfix/PROJECT-123/short-desc
+
+Args:
+ branch_name (str): The name of the git branch to search for JIRA issue keys.
+
+Returns:
+ List[str]: A list of unique JIRA issue keys found in the branch name.
+
+Examples:
+ extract_issue_keys_from_branch("feature/PROJ-456-add-new-feature")
+ # Output: ['PROJ-456']
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.extract_issue_keys_from_branch
+ penify_hook.ui_utils.print_info
+ penify_hook.jira_client.JiraClient.extract_issue_keys_from_branch
+
+
+ List[str]
+ List[str] penify_hook.jira_client.JiraClient.extract_issue_keys
+ (self, str text)
+ extract_issue_keys
+ penify_hook.jira_client.JiraClient.extract_issue_keys
+
+ self
+ self
+
+
+ str
+ text
+
+
+
+
+Extract JIRA issue keys from a given text.
+
+This function searches through the provided text to find and return all
+unique JIRA issue keys. A JIRA issue key typically follows the pattern
+of PROJECT-123, where PROJECT is alphanumeric and consists of at least
+one uppercase letter followed by one or more alphanumeric characters,
+and 123 is a numeric sequence.
+
+Args:
+ text (str): The text in which to search for JIRA issue keys.
+
+Returns:
+ List[str]: A list of unique JIRA issue keys found in the text.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.format_commit_message_with_jira_info
+
+
+ Optional[Dict[str, Any]]
+ Optional[Dict[str, Any]] penify_hook.jira_client.JiraClient.get_issue_details
+ (self, str issue_key)
+ get_issue_details
+ penify_hook.jira_client.JiraClient.get_issue_details
+
+ self
+ self
+
+
+ str
+ issue_key
+
+
+
+
+Retrieve details of a JIRA issue based on its key.
+
+This function fetches detailed information about a specified JIRA issue
+using the provided issue key. It checks if the JIRA client is connected
+before attempting to retrieve the issue. If the client is not connected,
+it logs a warning and returns `None`. The function then attempts to
+fetch the issue from the JIRA server and constructs a dictionary
+containing various details about the issue such as its key, summary,
+status, description, assignee, reporter, type, priority, and URL. If any
+errors occur during this process, they are logged, and `None` is
+returned.
+
+Args:
+ issue_key (str): The JIRA issue key (e.g., "PROJECT-123").
+
+Returns:
+ Dict[str, Any] or None: A dictionary containing the details of the JIRA
+ issue if found, otherwise `None`.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.jira_client.JiraClient.format_commit_message_with_jira_info
+ penify_hook.jira_client.JiraClient.get_commit_context_from_issues
+
+
+ bool
+ bool penify_hook.jira_client.JiraClient.add_comment
+ (self, str issue_key, str comment)
+ add_comment
+ penify_hook.jira_client.JiraClient.add_comment
+
+ self
+ self
+
+
+ str
+ issue_key
+
+
+ str
+ comment
+
+
+
+
+Add a comment to a JIRA issue.
+
+Args:
+ issue_key (str): JIRA issue key (e.g., "PROJECT-123")
+ comment (str): Comment text to add
+
+Returns:
+ bool: True if the comment was added successfully, False otherwise
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.add_comment
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.jira_client.JiraClient.add_comment
+
+
+ bool
+ bool penify_hook.jira_client.JiraClient.update_issue_status
+ (self, str issue_key, str transition_name)
+ update_issue_status
+ penify_hook.jira_client.JiraClient.update_issue_status
+
+ self
+ self
+
+
+ str
+ issue_key
+
+
+ str
+ transition_name
+
+
+
+
+Update the status of a JIRA issue.
+
+Args:
+ issue_key (str): The key of the JIRA issue to be updated.
+ transition_name (str): The name of the desired transition.
+
+Returns:
+ bool: True if the status was successfully updated, False otherwise.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.jira_client.JiraClient.jira_client
+
+
+ tuple
+ tuple penify_hook.jira_client.JiraClient.format_commit_message_with_jira_info
+ (self, str commit_title, str commit_description, List[str] issue_keys=None)
+ format_commit_message_with_jira_info
+ penify_hook.jira_client.JiraClient.format_commit_message_with_jira_info
+
+ self
+ self
+
+
+ str
+ commit_title
+
+
+ str
+ commit_description
+
+
+ List
+ issue_keys
+ [str]
+ None
+
+
+
+
+Format commit message with JIRA issue information.
+
+Args:
+ commit_title (str): The original commit title.
+ commit_description (str): The original commit description.
+ issue_keys (List[str]?): A list of JIRA issue keys to include in the commit message. If not
+ provided, issue keys will be extracted from both the title and the
+ description.
+
+Returns:
+ tuple: A tuple containing the updated commit title and description with JIRA
+ information included.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.extract_issue_keys
+ penify_hook.jira_client.JiraClient.get_issue_details
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.jira_client.JiraClient.enhance_commit_message
+
+
+ Dict[str, Any]
+ Dict[str, Any] penify_hook.jira_client.JiraClient.get_detailed_issue_context
+ (self, str issue_key)
+ get_detailed_issue_context
+ penify_hook.jira_client.JiraClient.get_detailed_issue_context
+
+ self
+ self
+
+
+ str
+ issue_key
+
+
+
+
+Retrieve comprehensive details about a JIRA issue including context for
+better commit messages.
+
+This function fetches detailed information from a specified JIRA issue
+and constructs a dictionary containing various context fields such as
+the issue summary, description, type, status, priority, comments, URL,
+and additional custom fields like acceptance criteria and sprint
+information. If any errors occur during the fetching process,
+appropriate warnings or errors are logged.
+
+Args:
+ issue_key (str): The JIRA issue key (e.g., "PROJECT-123").
+
+Returns:
+ Dict[str, Any]: A dictionary containing business and technical context from the issue.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.jira_client.JiraClient.jira_client
+ penify_hook.jira_client.JiraClient.get_commit_context_from_issues
+
+
+ Dict[str, Any]
+ Dict[str, Any] penify_hook.jira_client.JiraClient.get_commit_context_from_issues
+ (self, List[str] issue_keys)
+ get_commit_context_from_issues
+ penify_hook.jira_client.JiraClient.get_commit_context_from_issues
+
+ self
+ self
+
+
+ List
+ issue_keys
+ [str]
+
+
+
+
+Gather contextual information from JIRA issues to improve commit
+messages.
+
+This function processes a list of JIRA issue keys, retrieves detailed
+context for each issue, and aggregates it into a dictionary that can be
+used to enhance commit messages. It first retrieves the primary issue
+(the first key in the list) and then gathers basic details for any
+related issues. The resulting context includes information from both the
+primary and related issues, along with all issue keys.
+
+Args:
+ issue_keys: List of JIRA issue keys to gather information from
+
+Returns:
+ Dict containing business and technical context from the issues
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.get_detailed_issue_context
+ penify_hook.jira_client.JiraClient.get_issue_details
+ penify_hook.jira_client.JiraClient.is_connected
+ penify_hook.jira_client.JiraClient.enhance_commit_message
+
+
+ tuple
+ tuple penify_hook.jira_client.JiraClient.enhance_commit_message
+ (self, str title, str description, List[str] issue_keys)
+ enhance_commit_message
+ penify_hook.jira_client.JiraClient.enhance_commit_message
+
+ self
+ self
+
+
+ str
+ title
+
+
+ str
+ description
+
+
+ List
+ issue_keys
+ [str]
+
+
+
+
+Enhance a commit message with business and technical context from JIRA
+issues.
+
+Args:
+ title (str): Original commit title.
+ description (str): Original commit description.
+ issue_keys (List[str]): List of JIRA issue keys to include in the enhanced commit message.
+
+Returns:
+ tuple: A tuple containing the enhanced commit title and description with added
+ context from JIRA issues.
+
+
+
+
+
+ penify_hook.jira_client.JiraClient.format_commit_message_with_jira_info
+ penify_hook.jira_client.JiraClient.get_commit_context_from_issues
+ penify_hook.jira_client.JiraClient.is_connected
+
+
+
+
+
+Client for interacting with JIRA API
+
+
+
+
+
+
+
+
+
+
+ penify_hook::jira_client::JiraClient__init__
+ penify_hook::jira_client::JiraClientadd_comment
+ penify_hook::jira_client::JiraClientenhance_commit_message
+ penify_hook::jira_client::JiraClientextract_issue_keys
+ penify_hook::jira_client::JiraClientextract_issue_keys_from_branch
+ penify_hook::jira_client::JiraClientformat_commit_message_with_jira_info
+ penify_hook::jira_client::JiraClientget_commit_context_from_issues
+ penify_hook::jira_client::JiraClientget_detailed_issue_context
+ penify_hook::jira_client::JiraClientget_issue_details
+ penify_hook::jira_client::JiraClientis_connected
+ penify_hook::jira_client::JiraClientjira_api_token
+ penify_hook::jira_client::JiraClientjira_client
+ penify_hook::jira_client::JiraClientjira_url
+ penify_hook::jira_client::JiraClientjira_user
+ penify_hook::jira_client::JiraClientupdate_issue_status
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1llm__client_1_1LLMClient.xml b/docs343/xml/classpenify__hook_1_1llm__client_1_1LLMClient.xml
new file mode 100644
index 0000000..adeff2a
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1llm__client_1_1LLMClient.xml
@@ -0,0 +1,190 @@
+
+
+
+ penify_hook::llm_client::LLMClient
+
+
+
+ penify_hook.llm_client.LLMClient::model
+
+ model
+ penify_hook.llm_client.LLMClient.model
+
+
+
+
+
+
+
+ penify_hook.llm_client.LLMClient.generate_commit_summary
+
+
+
+
+
+ penify_hook.llm_client.LLMClient::_litellm
+
+ _litellm
+ penify_hook.llm_client.LLMClient._litellm
+
+
+
+
+
+
+
+ penify_hook.llm_client.LLMClient.litellm
+
+
+
+
+ def
+ def penify_hook.llm_client.LLMClient.__init__
+ (self, str model=None, str api_base=None, str api_key=None)
+ __init__
+ penify_hook.llm_client.LLMClient.__init__
+
+ self
+ self
+
+
+ str
+ model
+ None
+
+
+ str
+ api_base
+ None
+
+
+ str
+ api_key
+ None
+
+
+
+
+Initialize the LLM client.
+
+Args:
+ model: LLM model to use (e.g., "gpt-4", "ollama/llama2", etc.)
+ api_base: Base URL for API requests (e.g., "http://localhost:11434" for Ollama)
+ api_key: API key for the LLM service
+
+
+
+
+
+
+
+ def
+ def penify_hook.llm_client.LLMClient.litellm
+ (self)
+ litellm
+ penify_hook.llm_client.LLMClient.litellm
+
+ self
+ self
+
+
+
+
+Lazy load litellm only when needed.
+
+
+
+
+ penify_hook.llm_client.LLMClient._litellm
+ penify_hook.llm_client.LLMClient.generate_commit_summary
+
+
+ Dict
+ Dict penify_hook.llm_client.LLMClient.generate_commit_summary
+ (self, str diff, str message, bool generate_description, Dict repo_details, Dict jira_context=None)
+ generate_commit_summary
+ penify_hook.llm_client.LLMClient.generate_commit_summary
+
+ self
+ self
+
+
+ str
+ diff
+
+
+ str
+ message
+
+
+ bool
+ generate_description
+
+
+ Dict
+ repo_details
+
+
+ Dict
+ jira_context
+ None
+
+
+
+
+Generate a commit summary using the LLM.
+
+This function generates a concise and descriptive commit summary based
+on the provided Git diff, user instructions, repository details, and
+optional JIRA context. It constructs a prompt for the LLM to produce a
+commit title and an optional detailed description, adhering to Semantic
+Commit Messages guidelines. If the JIRA context is provided, it enriches
+the prompt with relevant issue information.
+
+Args:
+ diff (str): Git diff of changes.
+ message (str): User-provided commit message or instructions.
+ generate_description (bool): Flag indicating whether to include a detailed description in the
+ summary.
+ repo_details (Dict): Details about the repository.
+ jira_context (Dict?): Optional JIRA issue context to enhance the summary.
+
+Returns:
+ Dict: A dictionary containing the title and description for the commit. If
+ generate_description is False,
+ the 'description' key may be absent.
+
+Raises:
+ ValueError: If the LLM model is not configured.
+
+
+
+
+
+ penify_hook.llm_client.LLMClient.litellm
+ penify_hook.llm_client.LLMClient.model
+ penify_hook.api_client.APIClient.generate_commit_summary_with_llm
+
+
+
+
+
+Client for interacting with LLM models using LiteLLM.
+
+
+
+
+
+
+
+
+
+
+ penify_hook::llm_client::LLMClient__init__
+ penify_hook::llm_client::LLMClient_litellm
+ penify_hook::llm_client::LLMClientgenerate_commit_summary
+ penify_hook::llm_client::LLMClientlitellm
+ penify_hook::llm_client::LLMClientmodel
+
+
+
diff --git a/docs343/xml/classpenify__hook_1_1utils_1_1GitRepoNotFoundError.xml b/docs343/xml/classpenify__hook_1_1utils_1_1GitRepoNotFoundError.xml
new file mode 100644
index 0000000..f40e622
--- /dev/null
+++ b/docs343/xml/classpenify__hook_1_1utils_1_1GitRepoNotFoundError.xml
@@ -0,0 +1,38 @@
+
+
+
+ penify_hook::utils::GitRepoNotFoundError
+ Exception
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/classtests_1_1test__commit__commands_1_1TestCommitCommands.xml b/docs343/xml/classtests_1_1test__commit__commands_1_1TestCommitCommands.xml
new file mode 100644
index 0000000..74c6a42
--- /dev/null
+++ b/docs343/xml/classtests_1_1test__commit__commands_1_1TestCommitCommands.xml
@@ -0,0 +1,551 @@
+
+
+
+ tests::test_commit_commands::TestCommitCommands
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.mock_api_client
+ (self)
+ mock_api_client
+ tests.test_commit_commands.TestCommitCommands.mock_api_client
+
+ self
+ self
+
+
+
+
+Mocks an instance of APIClient using unittest.mock.
+
+This function creates a mock object for APIClient and yields it along
+with the mocked instance. It is useful for testing purposes where real
+API calls should be avoided.
+
+Yields:
+ tuple: A tuple containing the mock of APIClient and the mocked instance of
+ APIClient.
+
+
+
+
+
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.mock_llm_client
+ (self)
+ mock_llm_client
+ tests.test_commit_commands.TestCommitCommands.mock_llm_client
+
+ self
+ self
+
+
+
+
+Mock an instance of LLMClient for testing purposes.
+
+This function yields a mock object representing an instance of
+LLMClient, which can be used to simulate interactions with a language
+model during testing. The mock is patched to replace the actual
+LLMClient class from the penify_hook module.
+
+Yields:
+ tuple: A tuple containing two elements:
+ - mock (MagicMock): The mock object for LLMClient.
+ - llm_client_instance (MagicMock): An instance of the mocked LLMClient.
+
+
+
+
+
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.mock_jira_client
+ (self)
+ mock_jira_client
+ tests.test_commit_commands.TestCommitCommands.mock_jira_client
+
+ self
+ self
+
+
+
+
+Create a mock JIRA client for testing purposes.
+
+This function yields a tuple containing a mock JIRA client instance and
+its `is_connected` method. The mock client is configured to simulate an
+active connection. This is useful for unit tests that require
+interaction with a JIRA client without making actual network calls.
+
+Yields:
+ tuple: A tuple containing the mocked JIRA client instance and its
+ `is_connected` method.
+
+
+
+
+
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.mock_commit_doc_gen
+ (self)
+ mock_commit_doc_gen
+ tests.test_commit_commands.TestCommitCommands.mock_commit_doc_gen
+
+ self
+ self
+
+
+
+
+Mocks the CommitDocGenHook class and returns a MagicMock instance.
+
+This function uses the `patch` decorator from the `unittest.mock` module
+to create a mock of the `CommitDocGenHook` class. It then sets up this
+mock to return a new `MagicMock` instance when invoked. The function
+yields both the mock object and the mocked instance, allowing for easy
+testing of functions that rely on `CommitDocGenHook`.
+
+Returns:
+ tuple: A tuple containing two elements:
+ - mock (patch): The patch object used to mock the `CommitDocGenHook`
+ class.
+ - doc_gen_instance (MagicMock): The mocked instance of
+ `CommitDocGenHook`.
+
+
+
+
+
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.mock_git_folder_search
+ (self)
+ mock_git_folder_search
+ tests.test_commit_commands.TestCommitCommands.mock_git_folder_search
+
+ self
+ self
+
+
+
+
+Mock the `recursive_search_git_folder` function to return a predefined
+git folder path.
+
+This function uses the `patch` decorator from the `unittest.mock` module
+to intercept calls to `penify_hook.utils.recursive_search_git_folder`.
+When called, it will return '/mock/git/folder' instead of performing an
+actual search. This is useful for testing purposes where you need a
+consistent response without interacting with the file system.
+
+Yields:
+ MagicMock: A mock object that simulates the `recursive_search_git_folder` function.
+
+
+
+
+
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.mock_print_functions
+ (self)
+ mock_print_functions
+ tests.test_commit_commands.TestCommitCommands.mock_print_functions
+
+ self
+ self
+
+
+
+
+Mocks the print functions from `penify_hook.ui_utils` for testing
+purposes.
+
+This function uses Python's `unittest.mock.patch` to replace the actual
+print functions (`print`, `print_warning`, and `print_error`) with mock
+objects. These mock objects can be used in tests to capture calls made
+to these print functions without actually printing anything.
+
+Yields:
+ tuple: A tuple containing three mock objects corresponding to `print_info`,
+ `print_warning`,
+ and `print_error`.
+
+
+
+
+
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.test_commit_code_with_llm_client
+ (self, mock_error, mock_warning, mock_info, mock_git_folder_search, mock_doc_gen, mock_llm_client, mock_api_client)
+ test_commit_code_with_llm_client
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_with_llm_client
+
+ self
+ self
+
+
+ mock_error
+ mock_error
+
+
+ mock_warning
+ mock_warning
+
+
+ mock_info
+ mock_info
+
+
+ [mock_git_folder_search]
+ mock_git_folder_search
+
+
+ mock_doc_gen
+ mock_doc_gen
+
+
+ [mock_llm_client]
+ mock_llm_client
+
+
+ [mock_api_client]
+ mock_api_client
+
+
+
+
+Test committing code using an LLM client.
+
+This function sets up mock objects for various components and then calls
+the `commit_code` function with specified parameters. It verifies that
+the correct mocks are created and called with the appropriate arguments.
+
+Args:
+ mock_error (MagicMock): Mock object for error handling.
+ mock_warning (MagicMock): Mock object for warning logging.
+ mock_info (MagicMock): Mock object for info logging.
+ mock_git_folder_search (MagicMock): Mock object to simulate git folder search.
+ mock_doc_gen (MagicMock): Mock object for document generation.
+ mock_llm_client (MagicMock): Mock object for LLM client interaction.
+ mock_api_client (MagicMock): Mock object for API client interaction.
+
+
+
+
+
+ penify_hook.commands.commit_commands.commit_code
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.test_commit_code_with_jira_client
+ (self, mock_error, mock_warning, mock_info, mock_git_folder_search, mock_doc_gen, mock_jira_client, mock_llm_client, mock_api_client)
+ test_commit_code_with_jira_client
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_with_jira_client
+
+ self
+ self
+
+
+ mock_error
+ mock_error
+
+
+ mock_warning
+ mock_warning
+
+
+ mock_info
+ mock_info
+
+
+ [mock_git_folder_search]
+ mock_git_folder_search
+
+
+ mock_doc_gen
+ mock_doc_gen
+
+
+ [mock_jira_client]
+ mock_jira_client
+
+
+ [mock_llm_client]
+ mock_llm_client
+
+
+ [mock_api_client]
+ mock_api_client
+
+
+
+
+Test committing code using a JIRA client.
+
+This function tests the commit_code function with various parameters,
+including API and JIRA credentials. It sets up mock objects for
+dependencies such as the JIRA client, LLM client, and doc generator to
+simulate the behavior of the real classes. The function then calls
+commit_code and verifies that the JIRA client and doc generator are
+called with the correct parameters.
+
+Args:
+ mock_error (MagicMock): A MagicMock object for simulating error logging.
+ mock_warning (MagicMock): A MagicMock object for simulating warning logging.
+ mock_info (MagicMock): A MagicMock object for simulating info logging.
+ mock_git_folder_search (MagicMock): A MagicMock object for simulating the git folder search function.
+ mock_doc_gen (MagicMock): A MagicMock object for simulating the doc generator function.
+ mock_jira_client (MagicMock): A MagicMock object for simulating the JIRA client class.
+ mock_llm_client (MagicMock): A MagicMock object for simulating the LLM client class.
+ mock_api_client (MagicMock): A MagicMock object for simulating the API client class.
+
+
+
+
+
+ penify_hook.commands.commit_commands.commit_code
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.test_commit_code_with_jira_connection_failure
+ (self, mock_error, mock_warning, mock_info, mock_git_folder_search, mock_doc_gen, mock_jira_client, mock_api_client)
+ test_commit_code_with_jira_connection_failure
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_with_jira_connection_failure
+
+ self
+ self
+
+
+ mock_error
+ mock_error
+
+
+ mock_warning
+ mock_warning
+
+
+ mock_info
+ mock_info
+
+
+ [mock_git_folder_search]
+ mock_git_folder_search
+
+
+ mock_doc_gen
+ mock_doc_gen
+
+
+ [mock_jira_client]
+ mock_jira_client
+
+
+ [mock_api_client]
+ mock_api_client
+
+
+
+
+Test the commit_code function when JIRA connection fails.
+
+This function tests the scenario where the JIRA connection fails during
+a code commit. It sets up various mocks to simulate different components
+of the system and then calls the `commit_code` function with specific
+parameters. The function is expected to handle the JIRA connection
+failure gracefully by logging an appropriate warning.
+
+Args:
+ mock_error (MagicMock): Mock for error logging.
+ mock_warning (MagicMock): Mock for warning logging.
+ mock_info (MagicMock): Mock for info logging.
+ mock_git_folder_search (MagicMock): Mock for searching the Git folder.
+ mock_doc_gen (MagicMock): Mock for generating documentation.
+ mock_jira_client (MagicMock): Mock for creating a JIRA client.
+ mock_api_client (MagicMock): Mock for creating an API client.
+
+
+
+
+
+ penify_hook.commands.commit_commands.commit_code
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.test_commit_code_error_handling
+ (self, mock_print, mock_exit, mock_git_folder_search, mock_doc_gen, mock_api_client)
+ test_commit_code_error_handling
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_error_handling
+
+ self
+ self
+
+
+ mock_print
+ mock_print
+
+
+ mock_exit
+ mock_exit
+
+
+ [mock_git_folder_search]
+ mock_git_folder_search
+
+
+ mock_doc_gen
+ mock_doc_gen
+
+
+ [mock_api_client]
+ mock_api_client
+
+
+
+
+Test the error handling in the test_commit_code function.
+
+This function sets up mocks to simulate exceptions and test the error
+handling of the commit_code function. It verifies that the function
+correctly prints an error message and exits with a status code of 1 when
+an exception occurs during documentation generation.
+
+Args:
+ mock_print (MagicMock): Mock for the print function, used to verify error message output.
+ mock_exit (MagicMock): Mock for the sys.exit function, used to verify exit behavior.
+ mock_git_folder_search (MagicMock): Mock for the git_folder_search function, returning a mock Git folder
+ path.
+ mock_doc_gen (MagicMock): Mock for the doc_gen function, simulating an exception during
+ documentation generation.
+ mock_api_client (MagicMock): Mock for the API client class, not directly used but referenced in the
+ function signature.
+
+
+
+
+
+ penify_hook.commands.commit_commands.commit_code
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.test_setup_commit_parser
+ (self)
+ test_setup_commit_parser
+ tests.test_commit_commands.TestCommitCommands.test_setup_commit_parser
+
+ self
+ self
+
+
+
+
+Set up the argument parser for the commit command.
+
+This function configures an argument parser to handle various options
+for committing changes. It adds three arguments: - '-m' or '--message':
+An optional argument to specify a contextual commit message with a
+default value of "N/A". - '-e' or '--terminal': A boolean flag to open
+an edit terminal before committing. - '-d' or '--description': A boolean
+flag that, when set to False, indicates the generation of a commit
+message with title and description.
+
+Args:
+ parser (MagicMock): The argument parser to be configured.
+
+
+
+
+
+ penify_hook.commands.commit_commands.setup_commit_parser
+
+
+ def
+ def tests.test_commit_commands.TestCommitCommands.test_handle_commit
+ (self, mock_print_info, mock_commit_code, mock_get_token, mock_get_llm_config, mock_get_jira_config)
+ test_handle_commit
+ tests.test_commit_commands.TestCommitCommands.test_handle_commit
+
+ self
+ self
+
+
+ mock_print_info
+ mock_print_info
+
+
+ mock_commit_code
+ mock_commit_code
+
+
+ mock_get_token
+ mock_get_token
+
+
+ mock_get_llm_config
+ mock_get_llm_config
+
+
+ mock_get_jira_config
+ mock_get_jira_config
+
+
+
+
+Test the handle_commit function with various mock objects.
+
+This function sets up mocks for retrieving LLM configuration, JIRA
+configuration, and commit code. It then creates an argument object and
+calls the handle_commit function. Finally, it verifies that the mock
+functions were called with the expected arguments.
+
+Args:
+ mock_print_info (MagicMock): Mock object for printing information.
+ mock_commit_code (MagicMock): Mock object for committing code.
+ mock_get_token (MagicMock): Mock object for retrieving API token.
+ mock_get_llm_config (MagicMock): Mock object for retrieving LLM configuration.
+ mock_get_jira_config (MagicMock): Mock object for retrieving JIRA configuration.
+
+
+
+
+
+ penify_hook.commands.commit_commands.handle_commit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tests::test_commit_commands::TestCommitCommandsmock_api_client
+ tests::test_commit_commands::TestCommitCommandsmock_commit_doc_gen
+ tests::test_commit_commands::TestCommitCommandsmock_git_folder_search
+ tests::test_commit_commands::TestCommitCommandsmock_jira_client
+ tests::test_commit_commands::TestCommitCommandsmock_llm_client
+ tests::test_commit_commands::TestCommitCommandsmock_print_functions
+ tests::test_commit_commands::TestCommitCommandstest_commit_code_error_handling
+ tests::test_commit_commands::TestCommitCommandstest_commit_code_with_jira_client
+ tests::test_commit_commands::TestCommitCommandstest_commit_code_with_jira_connection_failure
+ tests::test_commit_commands::TestCommitCommandstest_commit_code_with_llm_client
+ tests::test_commit_commands::TestCommitCommandstest_handle_commit
+ tests::test_commit_commands::TestCommitCommandstest_setup_commit_parser
+
+
+
diff --git a/docs343/xml/classtests_1_1test__config__commands_1_1TestConfigCommands.xml b/docs343/xml/classtests_1_1test__config__commands_1_1TestConfigCommands.xml
new file mode 100644
index 0000000..dacd0b1
--- /dev/null
+++ b/docs343/xml/classtests_1_1test__config__commands_1_1TestConfigCommands.xml
@@ -0,0 +1,578 @@
+
+
+
+ tests::test_config_commands::TestConfigCommands
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_penify_config_existing_dir
+ (self, mock_file_open, mock_makedirs, mock_path, mock_git_folder)
+ test_get_penify_config_existing_dir
+ tests.test_config_commands.TestConfigCommands.test_get_penify_config_existing_dir
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_makedirs
+ mock_makedirs
+
+
+ mock_path
+ mock_path
+
+
+ mock_git_folder
+ mock_git_folder
+
+
+
+
+Test the get_penify_config function when the .penify config directory
+exists.
+
+It should not create a new directory and assert that all mocked
+functions were called correctly.
+
+Args:
+ mock_file_open (MagicMock): A MagicMock object simulating the open() function.
+ mock_makedirs (MagicMock): A MagicMock object simulating the os.makedirs() function.
+ mock_path (MagicMock): A MagicMock object simulating the Path class from pathlib module.
+ mock_git_folder (MagicMock): A MagicMock object simulating the git_folder_search() function.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_penify_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_penify_config_new_dir
+ (self, mock_file_open, mock_makedirs, mock_path, mock_git_folder)
+ test_get_penify_config_new_dir
+ tests.test_config_commands.TestConfigCommands.test_get_penify_config_new_dir
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_makedirs
+ mock_makedirs
+
+
+ mock_path
+ mock_path
+
+
+ mock_git_folder
+ mock_git_folder
+
+
+
+
+Test the behavior of get_penify_config when the .penify directory does
+not exist.
+
+This function mocks various system calls to simulate a scenario where
+the .penify directory is not present. It then asserts that the
+appropriate actions are taken to create the directory and write an empty
+JSON file.
+
+Args:
+ mock_file_open (MagicMock): A MagicMock object simulating the `open` function.
+ mock_makedirs (MagicMock): A MagicMock object simulating the `os.makedirs` function.
+ mock_path (MagicMock): A MagicMock object simulating the `Path` class from `pathlib`.
+ mock_git_folder (MagicMock): A MagicMock object simulating a git folder search function.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_penify_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_llm_config_exists
+ (self, mock_file_open, mock_get_config)
+ test_get_llm_config_exists
+ tests.test_config_commands.TestConfigCommands.test_get_llm_config_exists
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_get_config
+ mock_get_config
+
+
+
+
+Test the get_llm_config function when the configuration file exists.
+
+This function sets up a mock configuration file that exists and returns
+it when called. It then calls the get_llm_config function and asserts
+that it returns the correct configuration dictionary. Additionally, it
+checks that the mock_file_open function was called with the correct
+arguments.
+
+Args:
+ mock_file_open (MagicMock): A mock for the open() function.
+ mock_get_config (MagicMock): A mock for the get_config() function.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_llm_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_llm_config_empty
+ (self, mock_file_open, mock_get_config)
+ test_get_llm_config_empty
+ tests.test_config_commands.TestConfigCommands.test_get_llm_config_empty
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_get_config
+ mock_get_config
+
+
+
+
+Test the behavior of get_llm_config when called with an empty
+configuration file.
+
+This function sets up a mock configuration file that exists but returns
+no content. It then calls the `get_llm_config` function and asserts that
+it returns an empty dictionary and that the file open method was called
+exactly once with the correct arguments.
+
+Args:
+ mock_file_open (MagicMock): A MagicMock object simulating the built-in open function.
+ mock_get_config (MagicMock): A MagicMock object simulating the get_config function.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_llm_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_llm_config_invalid_json
+ (self, mock_print, mock_file_open, mock_get_config)
+ test_get_llm_config_invalid_json
+ tests.test_config_commands.TestConfigCommands.test_get_llm_config_invalid_json
+
+ self
+ self
+
+
+ mock_print
+ mock_print
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_get_config
+ mock_get_config
+
+
+
+
+Test function to verify the behavior of get_llm_config when reading an
+invalid JSON file.
+
+It sets up a mock configuration file that exists but contains invalid
+JSON. The function is expected to handle this gracefully by printing an
+error message and returning an empty dictionary.
+
+Args:
+ mock_print (MagicMock): Mock for the print function.
+ mock_file_open (MagicMock): Mock for the open function.
+ mock_get_config (MagicMock): Mock for the get_config function, which returns the mock configuration
+ file.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_llm_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_jira_config_exists
+ (self, mock_file_open, mock_get_config)
+ test_get_jira_config_exists
+ tests.test_config_commands.TestConfigCommands.test_get_jira_config_exists
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_get_config
+ mock_get_config
+
+
+
+
+Test that get_jira_config returns the correct JIRA configuration when
+the configuration file exists.
+
+It sets up a mock for the configuration file to simulate its existence
+and verifies that the function reads from the correct file and returns
+the expected JIRA configuration dictionary. Additionally, it checks that
+the mock file open is called with the appropriate arguments.
+
+Args:
+ mock_file_open (MagicMock): A mock for the `open` function.
+ mock_get_config (MagicMock): A mock for the `get_config` function, which is expected to return a mock
+ configuration file object.
+
+Returns:
+ None: This test function does not explicitly return anything. Its assertions
+ serve as the verification of its correctness.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_jira_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_save_llm_config_success
+ (self, mock_print, mock_json_dump, mock_file_open, mock_get_config)
+ test_save_llm_config_success
+ tests.test_config_commands.TestConfigCommands.test_save_llm_config_success
+
+ self
+ self
+
+
+ mock_print
+ mock_print
+
+
+ mock_json_dump
+ mock_json_dump
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_get_config
+ mock_get_config
+
+
+
+
+Test the save_llm_config function successfully.
+
+This function tests that the save_llm_config function correctly saves an
+LLM configuration and handles various mock objects and side effects. It
+ensures that the function returns True upon successful execution, writes
+the expected configuration to a file, and prints a confirmation message.
+
+Args:
+ mock_print (MagicMock): A mock object for the print function.
+ mock_json_dump (MagicMock): A mock object for json.dump.
+ mock_file_open (MagicMock): A mock object for file opening.
+ mock_get_config (MagicMock): A mock object to return a configuration file mock.
+
+
+
+
+
+ penify_hook.commands.config_commands.save_llm_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_save_llm_config_failure
+ (self, mock_print, mock_file_open, mock_get_config)
+ test_save_llm_config_failure
+ tests.test_config_commands.TestConfigCommands.test_save_llm_config_failure
+
+ self
+ self
+
+
+ mock_print
+ mock_print
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_get_config
+ mock_get_config
+
+
+
+
+Test function to verify that the save_llm_config function returns False
+and prints an error message when it fails to save the LLM configuration
+due to a permission error.
+
+It sets up a mock configuration file that exists and calls the
+save_llm_config function with valid parameters. The function is expected
+to return False and print "Error saving LLM configuration: Permission
+denied" in case of a failure.
+
+Args:
+ self (TestLLMConfig): An instance of the test class.
+ mock_print (MagicMock): A MagicMock object representing the print function, which will be used
+ to assert that it was called with the expected error message.
+ mock_file_open (MagicMock): A MagicMock object representing the open function, which is not used in
+ this test but is included as a parameter for completeness.
+ mock_get_config (MagicMock): A MagicMock object representing the get_config function, which will be
+ used to return the mock configuration file.
+
+
+
+
+
+ penify_hook.commands.config_commands.save_llm_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_save_jira_config_success
+ (self, mock_print, mock_json_dump, mock_file_open, mock_path)
+ test_save_jira_config_success
+ tests.test_config_commands.TestConfigCommands.test_save_jira_config_success
+
+ self
+ self
+
+
+ mock_print
+ mock_print
+
+
+ mock_json_dump
+ mock_json_dump
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_path
+ mock_path
+
+
+
+
+Test the save_jira_config function to ensure it saves JIRA configuration
+successfully.
+
+This function sets up mocks for various dependencies and tests the
+functionality of saving a JIRA configuration. It asserts that the
+function returns `True`, the JSON dump is called with the correct
+configuration, and the print statement contains the expected message.
+
+Args:
+ mock_print (MagicMock): Mock for the print function.
+ mock_json_dump (MagicMock): Mock for the json.dump function.
+ mock_file_open (MagicMock): Mock for the open function.
+ mock_path (MagicMock): Mock for the path module.
+
+
+
+
+
+ penify_hook.commands.config_commands.save_jira_config
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_token_from_env
+ (self, mock_file_open, mock_path, mock_getenv)
+ test_get_token_from_env
+ tests.test_config_commands.TestConfigCommands.test_get_token_from_env
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_path
+ mock_path
+
+
+ mock_getenv
+ mock_getenv
+
+
+
+
+Test retrieving a token from the environment variable.
+
+This function tests the behavior of `get_token` when an environment
+variable is set. It verifies that if the 'PENIFY_API_TOKEN' environment
+variable exists, the function returns its value without attempting to
+read a file.
+
+Args:
+ mock_file_open (MagicMock): A MagicMock object for simulating file operations.
+ mock_path (MagicMock): A MagicMock object for simulating path operations.
+ mock_getenv (MagicMock): A MagicMock object for simulating environment variable retrieval.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_token
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_token_from_config
+ (self, mock_file_open, mock_path, mock_getenv)
+ test_get_token_from_config
+ tests.test_config_commands.TestConfigCommands.test_get_token_from_config
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_path
+ mock_path
+
+
+ mock_getenv
+ mock_getenv
+
+
+
+
+Test retrieving a token from the configuration.
+
+This function sets up mocks for environment variables and configuration
+files, calls the `get_token` function, and asserts its behavior. It
+verifies that when the environment variable is not found, the function
+reads a token from a configuration file located in the user's home
+directory.
+
+Args:
+ mock_file_open (MagicMock): A mock for the `open` function.
+ mock_path (MagicMock): A mock for the `pathlib.Path` class.
+ mock_getenv (MagicMock): A mock for the `os.getenv` function.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_token
+
+
+ def
+ def tests.test_config_commands.TestConfigCommands.test_get_token_not_found
+ (self, mock_file_open, mock_path, mock_getenv)
+ test_get_token_not_found
+ tests.test_config_commands.TestConfigCommands.test_get_token_not_found
+
+ self
+ self
+
+
+ mock_file_open
+ mock_file_open
+
+
+ mock_path
+ mock_path
+
+
+ mock_getenv
+ mock_getenv
+
+
+
+
+Test the get_token function when the API token environment variable is
+not found.
+
+This function tests the scenario where the `PENIFY_API_TOKEN`
+environment variable is not set. It mocks the environment variable to
+return `None`, and verifies that the function returns `None`. The test
+also checks that the environment variable is accessed once and that a
+file open operation is attempted on a configuration file located in the
+user's home directory.
+
+Args:
+ mock_file_open (MagicMock): Mock for the built-in `open` function.
+ mock_path (MagicMock): Mock for the `pathlib.Path` module.
+ mock_getenv (MagicMock): Mock for the `os.getenv` function.
+
+Returns:
+ None: The function does not return anything; it asserts conditions to verify
+ correctness.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_token
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tests::test_config_commands::TestConfigCommandstest_get_jira_config_exists
+ tests::test_config_commands::TestConfigCommandstest_get_llm_config_empty
+ tests::test_config_commands::TestConfigCommandstest_get_llm_config_exists
+ tests::test_config_commands::TestConfigCommandstest_get_llm_config_invalid_json
+ tests::test_config_commands::TestConfigCommandstest_get_penify_config_existing_dir
+ tests::test_config_commands::TestConfigCommandstest_get_penify_config_new_dir
+ tests::test_config_commands::TestConfigCommandstest_get_token_from_config
+ tests::test_config_commands::TestConfigCommandstest_get_token_from_env
+ tests::test_config_commands::TestConfigCommandstest_get_token_not_found
+ tests::test_config_commands::TestConfigCommandstest_save_jira_config_success
+ tests::test_config_commands::TestConfigCommandstest_save_llm_config_failure
+ tests::test_config_commands::TestConfigCommandstest_save_llm_config_success
+
+
+
diff --git a/docs343/xml/classtests_1_1test__web__config_1_1TestWebConfig.xml b/docs343/xml/classtests_1_1test__web__config_1_1TestWebConfig.xml
new file mode 100644
index 0000000..d218b6d
--- /dev/null
+++ b/docs343/xml/classtests_1_1test__web__config_1_1TestWebConfig.xml
@@ -0,0 +1,112 @@
+
+
+
+ tests::test_web_config::TestWebConfig
+
+
+ def
+ def tests.test_web_config.TestWebConfig.test_config_llm_web_server_setup
+ (self, mock_resource_filename, mock_server, mock_webbrowser)
+ test_config_llm_web_server_setup
+ tests.test_web_config.TestWebConfig.test_config_llm_web_server_setup
+
+ self
+ self
+
+
+ mock_resource_filename
+ mock_resource_filename
+
+
+ mock_server
+ mock_server
+
+
+ mock_webbrowser
+ mock_webbrowser
+
+
+
+
+Set up and test the web server configuration for an LLM (Large Language
+Model) web interface.
+
+This function configures a mock web server for testing purposes,
+including setting up resource filenames, mocking server behavior, and
+verifying that the web browser is opened and the server starts
+correctly. The function uses various mocks to simulate external
+dependencies such as `resource_filename` and `server`.
+
+Args:
+ mock_resource_filename (MagicMock): A MagicMock object simulating the `resource_filename` function.
+ mock_server (MagicMock): A MagicMock object simulating the context manager for the web server.
+ mock_webbrowser (MagicMock): A MagicMock object simulating the `webbrowser` module.
+
+
+
+
+
+ penify_hook.commands.config_commands.config_llm_web
+
+
+ def
+ def tests.test_web_config.TestWebConfig.test_config_jira_web_server_setup
+ (self, mock_resource_filename, mock_server, mock_webbrowser)
+ test_config_jira_web_server_setup
+ tests.test_web_config.TestWebConfig.test_config_jira_web_server_setup
+
+ self
+ self
+
+
+ mock_resource_filename
+ mock_resource_filename
+
+
+ mock_server
+ mock_server
+
+
+ mock_webbrowser
+ mock_webbrowser
+
+
+
+
+Test the configuration and setup of a JIRA web server.
+
+This function tests the entire process of setting up a JIRA web server,
+including mocking necessary resources, configuring the server to shut
+down after handling one request, and verifying that the web browser is
+opened with the correct URL. The function uses several mocks to simulate
+external dependencies such as resource files, servers, and web browsers.
+
+Args:
+ mock_resource_filename (MagicMock): A MagicMock object for simulating the `resource_filename` function.
+ mock_server (MagicMock): A MagicMock object for simulating the server setup.
+ mock_webbrowser (MagicMock): A MagicMock object for simulating the web browser opening.
+
+
+
+
+
+ penify_hook.commands.config_commands.config_jira_web
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tests::test_web_config::TestWebConfigtest_config_jira_web_server_setup
+ tests::test_web_config::TestWebConfigtest_config_llm_web_server_setup
+
+
+
diff --git a/docs343/xml/combine.xslt b/docs343/xml/combine.xslt
new file mode 100644
index 0000000..3bfa82c
--- /dev/null
+++ b/docs343/xml/combine.xslt
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/commit-commands_8md.xml b/docs343/xml/commit-commands_8md.xml
new file mode 100644
index 0000000..4ff7b63
--- /dev/null
+++ b/docs343/xml/commit-commands_8md.xml
@@ -0,0 +1,174 @@
+
+
+
+ commit-commands.md
+
+
+
+
+
+#PenifyCLI-CommitCommands
+
+The`commit`commandallowsyoutogeneratesmart,AI-poweredcommitmessagesforyourGitchanges.Thisdocumentexplainsallavailableoptionsandcombinations.
+
+##BasicUsage
+
+```bash
+penifycommit
+```
+
+Bydefault,thiscommand:
+-AnalyzesyourstagedGitchanges
+-Generatesaconcisecommittitleonly
+-UseslocalLLMifconfigured,orfallsbacktoPenifyAPI
+
+##CommandOptions
+
+###`-m,--message`
+
+Providecontextforthecommitmessagegeneration:
+
+```bash
+penifycommit-m"Fixloginflow"
+```
+
+ThishinthelpstheAIunderstandyourintentionandimprovesthequalityofthegeneratedmessage.
+
+###`-e,--terminal`
+
+Openaneditortoreviewandeditthegeneratedcommitmessagebeforecommitting:
+
+```bash
+penifycommit-e
+```
+
+ThisopensyourdefaultGiteditorwiththegeneratedmessageforreview.
+
+###`-d,--description`
+
+Generateadetailedcommitmessagewithbothtitleanddescription:
+
+```bash
+penifycommit-d
+```
+
+Withoutthisflag,onlythecommittitleisgenerated.
+
+##OptionCombinations
+
+Youcancombinetheseoptionsfordifferentworkflows:
+
+###GenerateTitleOnlywithContext
+
+```bash
+penifycommit-m"UpdateloginUI"
+```
+
+###GenerateTitleandDescriptionwithContext
+
+```bash
+penifycommit-m"UpdateloginUI"-d
+```
+
+###GenerateandEditFullCommitMessage
+
+```bash
+penifycommit-d-e
+```
+
+###Generate,Edit,andProvideContext
+
+```bash
+penifycommit-m"Refactorauthentication"-d-e
+```
+
+##LLMandJIRAIntegration
+
+###UsingLocalLLM
+
+Ifyou'veconfiguredalocalLLMusing`penifyconfigllm`,thecommitcommandwillautomaticallyuseitformessagegeneration.
+
+Benefits:
+-Privacy:yourcodechangesdon'tleaveyourmachine
+-Speed:nonetworklatency
+-Worksoffline
+
+###JIRAEnhancement
+
+Ifyou'veconfiguredJIRAintegrationusing`penifyconfigjira`,thecommitcommandwill:
+
+1.DetectJIRAissuereferencesinyourchanges
+2.FetchissuedetailsfromyourJIRAinstance
+3.Includeissueinformationinthecommitmessage
+4.FormatthecommitmessageaccordingtoJIRA'ssmartcommitformat
+
+Exampleoutput:
+```
+PROJ-123:Fixauthenticationbuginloginflow
+
+-UpdatedOAuthtokenvalidation
+-Fixedsessiontimeouthandling
+-Addedunittestsforedgecases
+
+[PROJ-123]
+```
+
+##ConfigurationRequirements
+
+Forthe`commit`commandtowork:
+
+1.Youmusthaveconfiguredeither:
+-LocalLLMvia`penifyconfigllm`,OR
+-Loggedinvia`penifylogin`
+
+2.ForJIRAenhancement(optional):
+-ConfigureJIRAvia`penifyconfigjira`
+
+##Examples
+
+###BasicCommitwithDefaultSettings
+
+```bash
+#Stageyourchanges
+gitadd.
+
+#Generatecommitmessage
+penifycommit
+
+#Commitwiththegeneratedmessage
+gitcommit-m"Generatedmessagehere"
+```
+
+###FullWorkflowwithAllFeatures
+
+```bash
+#Stageyourchanges
+gitadd.
+
+#GeneratedetailedcommitmessagewithJIRAintegration,
+#providecontext,andopeneditorforreview
+penifycommit-m"Fixloginissue"-d-e
+
+#Thecommitisautomaticallycompletedafteryousaveandexittheeditor
+```
+
+##Troubleshooting
+
+###CommonIssues
+
+1.**"NoLLMmodelorAPItokenprovided"**
+-Run`penifyconfigllm`toconfigurealocalLLM,or
+-Run`penifylogin`toauthenticatewithPenify
+
+2.**"FailedtoconnecttoJIRA"**
+-CheckyourJIRAconfigurationwith`cat~/.penify`
+-Verifyyournetworkconnection
+-EnsureyourJIRAcredentialsarevalid
+
+3.**"ErrorinitializingLLMclient"**
+-VerifyyourLLMconfigurationsettings
+-EnsuretheLLMAPIisaccessible
+
+
+
+
diff --git a/docs343/xml/commit__analyzer_8py.xml b/docs343/xml/commit__analyzer_8py.xml
new file mode 100644
index 0000000..07676b8
--- /dev/null
+++ b/docs343/xml/commit__analyzer_8py.xml
@@ -0,0 +1,198 @@
+
+
+
+ commit_analyzer.py
+ penify_hook::commit_analyzer::CommitDocGenHook
+ penify_hook
+ penify_hook::commit_analyzer
+
+
+
+
+
+importos
+importre
+importsubprocess
+importtempfile
+fromtypingimportOptional,List
+fromgitimportRepo
+fromtqdmimporttqdm
+
+from[penify_hook.base_analyzer]importBaseAnalyzer
+from[penify_hook.jira_client]importJiraClient
+from[penify_hook.ui_utils]importprint_info,print_success,print_warning
+from.api_clientimportAPIClient
+
+class[CommitDocGenHook]([BaseAnalyzer]):
+def[__init__](self,repo_path:str,api_client:APIClient,llm_client=None,jira_client=None):
+super().[__init__](repo_path,api_client)
+
+self.[llm_client]=llm_client
+self.jira_client:JiraClient=jira_client
+
+def[get_summary](self,instruction:str,generate_description:bool)->dict:
+"""Generateasummaryforthecommitbasedonthestagedchanges.
+
+Thisfunctionretrievesthedifferencesofthestagedchangesinthe
+repositoryandgeneratesacommitsummaryusingtheprovided
+instruction.Iftherearenochangesstagedforcommit,anexceptionis
+raised.IfaJIRAclientisconnected,itwillattempttoextractissue
+keysfromthecurrentbranchandusethemtofetchcontext.Thesummary
+canbegeneratedeitherwithaLanguageModel(LLM)clientorthrough
+theAPIclient.
+
+Args:
+instruction(str):Astringcontaininginstructionsforgeneratingthecommitsummary.
+generate_description(bool):Whethertoincludedetaileddescriptionsinthesummary.
+
+Returns:
+dict:Thegeneratedcommitsummarybasedonthestagedchanges,provided
+instruction,andanyrelevantJIRAcontext.Thedictionarycontainskeys
+suchas'summary','description',etc.,dependingonwhethera
+descriptionwasrequested.
+
+Raises:
+ValueError:Iftherearenochangesstagedforcommit.
+"""
+diff=self.[repo].git.diff('--cached')
+ifnotdiff:
+raiseValueError("Nochangestocommit")
+
+
+jira_context=None
+ifself.jira_clientandself.jira_client.is_connected():
+try:
+
+current_branch=self.[repo].active_branch.name
+issue_keys=self.jira_client.extract_issue_keys_from_branch(current_branch)
+
+
+ifissue_keys:
+jira_context=self.jira_client.get_commit_context_from_issues(issue_keys)
+exceptExceptionase:
+print(f"CouldnotgetJIRAcontext:{e}")
+
+
+[print_info]("FetchingcommitsummaryfromLLM...")
+ifself.[llm_client]:
+returnself.[api_client].generate_commit_summary_with_llm(
+diff,instruction,generate_description,self.[repo_details],self.[llm_client],jira_context
+)
+else:
+returnself.[api_client].generate_commit_summary(diff,instruction,self.[repo_details],jira_context)
+
+
+def[run](self,msg:Optional[str],edit_commit_message:bool,generate_description:bool):
+"""Runthepost-commithook.
+
+Thismethodprocessesthemodifiedfilesfromthelastcommit,stages
+them,andcreatesanauto-commitwithanoptionalmessage.Italso
+handlesJIRAintegrationifavailable.Ifthereisanerrorgenerating
+thecommitsummary,anexceptionisraised.
+
+Args:
+msg(Optional[str]):Anoptionalmessagetoincludeinthecommit.
+edit_commit_message(bool):Aflagindicatingwhethertoopenthegitcommiteditterminalafter
+committing.
+generate_description(bool):Aflagindicatingwhethertoincludeadescriptioninthecommit
+message.
+
+Raises:
+Exception:Ifthereisanerrorgeneratingthecommitsummary.
+"""
+summary:dict=self.[get_summary](msg,True)
+ifnotsummary:
+raise[Exception]("Errorgeneratingcommitsummary")
+
+title=summary.get('title',"")
+description=summary.get('description',"")
+
+
+ifself.jira_clientandself.jira_client.is_connected():
+
+self.[process_jira_integration](title,description,msg)
+
+
+commit_msg=f"{title}\n\n{description}"ifgenerate_descriptionelsetitle
+self.[repo].git.commit('-m',commit_msg)
+[print_success](f"Commit:{commit_msg}")
+
+ifedit_commit_message:
+
+[print_info]("Openinggitcommiteditterminal...")
+self.[_amend_commit]()
+
+def[process_jira_integration](self,title:str,description:str,msg:str)->tuple:
+"""ProcessJIRAintegrationforthecommitmessage.
+
+Args:
+title(str):Generatedcommittitle.
+description(str):Generatedcommitdescription.
+msg(str):OriginalusermessagethatmightcontainJIRAreferences.
+
+Returns:
+tuple:Atuplecontainingtheupdatedcommittitleanddescriptionwith
+includedJIRAinformation.
+"""
+
+issue_keys=[]
+ifself.jira_client:
+
+issue_keys=self.jira_client.extract_issue_keys(f"{title}{description}{msg}")
+
+
+try:
+current_branch=self.[repo].active_branch.name
+branch_issue_keys=self.jira_client.extract_issue_keys_from_branch(current_branch)
+
+
+forkeyinbranch_issue_keys:
+ifkeynotinissue_keys:
+issue_keys.append(key)
+[print_info](f"AddedJIRAissue{key}frombranchname:{current_branch}")
+exceptExceptionase:
+[print_warning](f"CouldnotextractJIRAissuesfrombranchname:{e}")
+
+ifissue_keys:
+[print_info](f"FoundJIRAissues:{','.join(issue_keys)}")
+
+
+
+
+forissue_keyinissue_keys:
+comment=(
+f"Commitrelatedtothisissue:\n\n"
+f"**{title}**\n\n"
+f"{description}\n\n"
+)
+self.jira_client.add_comment(issue_key,comment)
+else:
+[print_warning]("NoJIRAissuesfoundincommitmessageorbranchname")
+
+returntitle,description
+
+def[_amend_commit](self):
+"""Openthedefaultgiteditorforeditingthecommitmessage.
+
+Thisfunctionchangesthecurrentworkingdirectorytotherepository
+path,runsthegitcommandtoamendthelastcommit,andopensthe
+defaulteditorfortheusertomodifythecommitmessage.Afterthe
+operation,itreturnstotheoriginaldirectory.
+"""
+try:
+
+os.chdir(self.[repo_path])
+
+
+subprocess.run(['git','commit','--amend'],check=True)
+
+print("Commitmessageamendedsuccessfully.")
+exceptsubprocess.CalledProcessErrorase:
+print(f"Erroramendingcommitmessage:{e}")
+finally:
+
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+
+
+
diff --git a/docs343/xml/commit__commands_8py.xml b/docs343/xml/commit__commands_8py.xml
new file mode 100644
index 0000000..91f0914
--- /dev/null
+++ b/docs343/xml/commit__commands_8py.xml
@@ -0,0 +1,184 @@
+
+
+
+ commit_commands.py
+ penify_hook
+ penify_hook::commands
+ penify_hook::commands::commit_commands
+
+
+
+
+
+importos
+importsys
+importargparse
+
+from[penify_hook.ui_utils]importprint_info,print_warning
+
+
+def[commit_code](api_url,token,message,open_terminal,generate_description,
+llm_model=None,llm_api_base=None,llm_api_key=None,
+jira_url=None,jira_user=None,jira_api_token=None):
+"""EnhanceGitcommitswithAI-poweredcommitmessages.
+
+Thisfunctionallowsforthegenerationofenhancedcommitmessages
+usingnaturallanguageprocessingmodelsandoptionallyintegrateswith
+JIRAforadditionalcontext.ItprocessesthecurrentGitfoldertofind
+relevantfilesandgeneratesadetailedcommitmessagebasedonthe
+providedparameters.
+
+Args:
+api_url(str):URLoftheAPIendpoint.
+token(str):AuthenticationtokenfortheAPI.
+message(str):Initialcommitmessageprovidedbytheuser.
+open_terminal(bool):Whethertoopentheterminalaftercommitting.
+generate_description(bool):Whethertogenerateadetaileddescriptioninthecommitmessage.
+llm_model(str?):Thelanguagemodeltouseforgeneratingthecommitmessage.Defaultsto
+None.
+llm_api_base(str?):BaseURLoftheLLMAPI.DefaultstoNone.
+llm_api_key(str?):APIkeyforaccessingtheLLMservice.DefaultstoNone.
+jira_url(str?):URLoftheJIRAinstance.DefaultstoNone.
+jira_user(str?):UsernameforauthenticatingwithJIRA.DefaultstoNone.
+jira_api_token(str?):APItokenforaccessingJIRA.DefaultstoNone.
+"""
+
+from[penify_hook.ui_utils]importprint_error
+from[penify_hook.utils]importrecursive_search_git_folder
+from..commit_analyzerimportCommitDocGenHook
+from..api_clientimportAPIClient
+
+
+try:
+from..llm_clientimportLLMClient
+exceptImportError:
+LLMClient=None
+
+try:
+from..jira_clientimportJiraClient
+exceptImportError:
+JiraClient=None
+
+api_client=APIClient(api_url,token)
+
+
+llm_client=None
+ifLLMClientisnotNoneandllm_model:
+try:
+llm_client=LLMClient(
+model=llm_model,
+api_base=llm_api_base,
+api_key=llm_api_key
+)
+[print_info](f"UsingLLMmodel:{llm_model}")
+exceptExceptionase:
+[print_error](f"ErrorinitializingLLMclient:{e}")
+[print_error]("FallingbacktoAPIforcommitsummarygeneration")
+else:
+ifnottoken:
+[print_error]("NoLLMmodelorAPItokenprovided.PleaseprovideanLLMmodelorAPItoken.")
+
+
+jira_client=None
+ifJiraClientisnotNoneandjira_urlandjira_userandjira_api_token:
+try:
+jira_client=JiraClient(
+jira_url=jira_url,
+jira_user=jira_user,
+jira_api_token=jira_api_token
+)
+ifjira_client.is_connected():
+[print_info](f"ConnectedtoJIRA:{jira_url}")
+else:
+[print_warning](f"FailedtoconnecttoJIRA:{jira_url}")
+jira_client=None
+exceptExceptionase:
+[print_warning](f"ErrorinitializingJIRAclient:{e}")
+jira_client=None
+
+try:
+
+gf_path=[recursive_search_git_folder](os.getcwd())
+analyzer=CommitDocGenHook(gf_path,api_client,llm_client,jira_client)
+analyzer.run(message,open_terminal,generate_description)
+exceptExceptionase:
+print(f"Error:{e}")
+sys.exit(1)
+
+
+
+
+
+def[setup_commit_parser](parser):
+"""Generatesaparserforsettingupacommandtogeneratesmartcommit
+messages.
+
+Thisfunctionsetsupanargumentparserthatcanbeusedtogenerate
+commitmessageswithcontextualinformation.Itallowsuserstospecify
+optionssuchasincludingamessage,openinganeditterminalbefore
+committing,andgeneratingadetailedcommitmessage.
+
+Args:
+parser(argparse.ArgumentParser):TheArgumentParserobjecttobeconfigured.
+"""
+
+commit_parser_description="""
+Itgeneratessmartcommitmessages.Bydefault,itwilljustgeneratejusttheTitleofthecommitmessage.
+1.IfyouhavenotconfiguredLLM,itwillgiveanerror.YoueitherneedtoconfigureLLMorusetheAPIkey.
+2.IfyouhavenotconfiguredJIRA.ItwillnotenhancethecommitmessagewithJIRAissuedetails.
+3.Formoreinformation,visithttps://penify.wiki/dcsgc1
+"""
+parser.help="Generatesmartcommitmessagesusinglocal-LLM(nologinrequired)."
+parser.description=commit_parser_description
+parser.formatter_class=argparse.RawDescriptionHelpFormatter
+
+
+parser.add_argument("-m","--message",required=False,help="Commitwithcontextualcommitmessage.",default="N/A")
+parser.add_argument("-e","--terminal",action="store_true",help="Openeditterminalbeforecommitting.")
+parser.add_argument("-d","--description",action="store_false",help="Itwillgeneratecommitmessagewithtitleanddescription.",default=False)
+
+def[handle_commit](args):
+"""Handlethecommitfunctionalitybyprocessingargumentsandinvokingthe
+appropriatecommands.
+
+Thisfunctionprocessestheprovidedcommand-lineargumentstoconfigure
+settingsforcommitoperations,includingLLM(LanguageModel)andJira
+configurations.Itthencallsthe`commit_code`functionwiththese
+configurationstoperformtheactualcommitoperation.
+
+Args:
+args(argparse.Namespace):Theparsedcommand-lineargumentscontainingoptionsliketerminal,
+description,message,etc.
+"""
+
+from[penify_hook.commands.commit_commands]importcommit_code
+from[penify_hook.commands.config_commands]importget_jira_config,get_llm_config,get_token
+from[penify_hook.constants]importAPI_URL
+
+
+open_terminal=args.terminal
+generate_description=args.description
+[print_info](f"GenerateCommitDescription:{generate_description}")
+
+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]()
+
+
+
+
+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)
+
+
+
+
diff --git a/docs343/xml/compound.xsd b/docs343/xml/compound.xsd
new file mode 100644
index 0000000..e0ffe43
--- /dev/null
+++ b/docs343/xml/compound.xsd
@@ -0,0 +1,1290 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The mentioned file will be located in the directory as specified by XML_OUTPUT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/config-commands_8md.xml b/docs343/xml/config-commands_8md.xml
new file mode 100644
index 0000000..4eb0949
--- /dev/null
+++ b/docs343/xml/config-commands_8md.xml
@@ -0,0 +1,179 @@
+
+
+
+ config-commands.md
+
+
+
+
+
+#PenifyCLI-ConfigurationCommands
+
+The`config`commandallowsyoutosetupandmanageconfigurationsettingsforPenifyCLI.Thisdocumentexplainsallavailableconfigurationoptionsandhowtousethem.
+
+##ConfigurationOverview
+
+PenifyCLIstoresconfigurationinaJSONfileat`~/.penify/config.json`.Theconfigurationincludes:
+
+-LLM(LargeLanguageModel)settingsforlocalcommitmessagegeneration
+-JIRAintegrationsettingsforenhancedcommitmessages
+-APItokensandothercredentials
+
+##BasicUsage
+
+```bash
+#ConfigureLLMsettings
+penifyconfigllm
+
+#ConfigureJIRAintegration
+penifyconfigjira
+```
+
+##LLMConfiguration
+
+###WebInterface
+
+Running`penifyconfigllm`opensawebinterfaceinyourbrowserwhereyoucanconfigure:
+
+1.**Model**:TheLLMmodeltouse(e.g.,`gpt-3.5-turbo`)
+2.**APIBaseURL**:TheendpointURLforyourLLMAPI(e.g.,`https://api.openai.com/v1`)
+3.**APIKey**:YourauthenticationkeyfortheLLMAPI
+
+###SupportedLLMs
+
+PenifyCLIsupportsvariousLLMproviders:
+
+####OpenAI
+-Model:`gpt-3.5-turbo`or`gpt-4`
+-APIBase:`https://api.openai.com/v1`
+-APIKey:YourOpenAIAPIkey
+
+####Anthropic
+-Model:`claude-instant-1`or`claude-2`
+-APIBase:`https://api.anthropic.com/v1`
+-APIKey:YourAnthropicAPIkey
+
+####Ollama(Local)
+-Model:`llama2`oranymodelyouhaveinstalled
+-APIBase:`http://localhost:11434`
+-APIKey:(leaveblank)
+
+####AzureOpenAI
+-Model:Yourdeployedmodelname
+-APIBase:YourAzureendpoint
+-APIKey:YourAzureAPIkey
+
+###ConfigurationFileStructure
+
+Afterconfiguration,your`~/.penify/config.json`willcontain:
+
+```json
+{
+"llm":{
+"model":"gpt-3.5-turbo",
+"api_base":"https://api.openai.com/v1",
+"api_key":"sk-..."
+}
+}
+```
+
+##JIRAConfiguration
+
+###WebInterface
+
+Running`penifyconfigjira`opensawebinterfacewhereyoucanconfigure:
+
+1.**JIRAURL**:YourJIRAinstanceURL(e.g.,`https://yourcompany.atlassian.net`)
+2.**Username**:YourJIRAusername(typicallyyouremail)
+3.**APIToken**:YourJIRAAPItoken
+
+###CreatingaJIRAAPIToken
+
+1.Loginto[https://id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens)
+2.Click"CreateAPItoken"
+3.Giveitaname(e.g.,"PenifyCLI")
+4.Copythegeneratedtokenandpasteitintotheconfiguration
+
+###ConfigurationFileStructure
+
+Afterconfiguration,your`~/.penify/config.json`willcontain:
+
+```json
+{
+"jira":{
+"url":"https://yourcompany.atlassian.net",
+"username":"your.email@example.com",
+"api_token":"your-jira-api-token"
+}
+}
+```
+
+##ConfigurationLocations
+
+PenifyCLIlooksforconfigurationinmultiplelocations:
+
+1.Project-specific:`.penify/config.json`intheGitrepositoryroot
+2.User-specific:`~/.penify/config.json`inyourhomedirectory
+
+Theproject-specificconfigurationtakesprecedenceifbothexist.
+
+##EnvironmentVariables
+
+Youcanoverrideconfigurationsettingsusingenvironmentvariables:
+
+-`PENIFY_API_TOKEN`:OverridethestoredAPItoken
+-`PENIFY_LLM_MODEL`:OverridetheconfiguredLLMmodel
+-`PENIFY_LLM_API_BASE`:OverridetheconfiguredLLMAPIbaseURL
+-`PENIFY_LLM_API_KEY`:OverridetheconfiguredLLMAPIkey
+-`PENIFY_JIRA_URL`:OverridetheconfiguredJIRAURL
+-`PENIFY_JIRA_USER`:OverridetheconfiguredJIRAusername
+-`PENIFY_JIRA_TOKEN`:OverridetheconfiguredJIRAAPItoken
+
+Example:
+```bash
+exportPENIFY_LLM_MODEL="gpt-4"
+penifycommit
+```
+
+##Command-LineConfiguration
+
+Foradvancedusersorscripting,youcandirectlyedittheconfigurationfile:
+
+```bash
+#Viewcurrentconfiguration
+cat~/.penify/config.json
+
+#Editconfigurationwithyourpreferrededitor
+nano~/.penify/config.json
+```
+
+##SharingConfiguration
+
+Youcanshareconfigurationbetweenmachinesbycopyingthe`.penify/config.json`file.However,becautiouswithAPIkeysandcredentials.
+
+Forteamsettings,consider:
+1.Usingaproject-specific`.penify/config.json`withsharedsettings
+2.ExcludingAPIkeysfromsharedconfiguration
+3.Usingenvironmentvariablesforsensitivecredentials
+
+##Troubleshooting
+
+###CommonIssues
+
+1.**"Errorreadingconfigurationfile"**
+-Checkifthefileexists:`ls-la~/.penify`
+-EnsureitcontainsvalidJSON:`cat~/.penify/config.json`
+
+2.**"FailedtoconnecttoLLMAPI"**
+-VerifyAPIbaseURLandAPIkey
+-ChecknetworkconnectivitytotheAPIendpoint
+-Ensureyouraccounthasaccesstothespecifiedmodel
+
+3.**"FailedtoconnecttoJIRA"**
+-CheckJIRAURLformat(shouldinclude`https://`)
+-VerifyusernameandAPItoken
+-EnsureyourJIRAaccounthasAPIaccesspermissions
+
+
+
+
diff --git a/docs343/xml/config__command_8py.xml b/docs343/xml/config__command_8py.xml
new file mode 100644
index 0000000..4bf3e78
--- /dev/null
+++ b/docs343/xml/config__command_8py.xml
@@ -0,0 +1,112 @@
+
+
+
+ config_command.py
+ penify_hook
+ penify_hook::config_command
+
+
+
+
+
+
+
+
+def[setup_config_parser](parent_parser):
+"""Setupaconfigurationparserwithsubparsersfordifferenttypesof
+configurations.
+
+Thisfunctionconfiguresandaddssubcommandstotheparentparser.Each
+subcommandcorrespondstoaspecifictypeofconfiguration,suchasLLM
+(LanguageModel)orJIRA.Itallowsuserstoconfiguresettingsfor
+thesesystemsthroughcommand-linearguments.
+
+Args:
+parent_parser(argparse.ArgumentParser):Theparentparsertowhichtheconfigsubparserswillbeadded.
+"""
+
+
+parser=parent_parser.add_subparsers(title="config_type",dest="config_type")
+
+
+llm_config_parser=parser.add_parser("llm-cmd",help="ConfigureLLMsettings.")
+llm_config_parser.add_argument("--model",required=True,help="LLMmodeltouse")
+llm_config_parser.add_argument("--api-base",help="APIbaseURLfortheLLMservice")
+llm_config_parser.add_argument("--api-key",help="APIkeyfortheLLMservice")
+
+
+parser.add_parser("llm",help="ConfigureLLMsettingsthroughawebinterface")
+
+
+jira_config_parser=parser.add_parser("jira-cmd",help="ConfigureJIRAsettings.")
+jira_config_parser.add_argument("--url",required=True,help="JIRAbaseURL")
+jira_config_parser.add_argument("--username",required=True,help="JIRAusernameoremail")
+jira_config_parser.add_argument("--api-token",required=True,help="JIRAAPItoken")
+jira_config_parser.add_argument("--verify",action="store_true",help="VerifyJIRAconnection")
+
+
+parser.add_parser("jira",help="ConfigureJIRAsettingsthroughawebinterface")
+
+
+
+def[handle_config](args):
+"""Handleconfigurationsettingsbasedonthespecifiedconfigtype.
+
+ThisfunctionprocessesdifferenttypesofconfigurationssuchasLLM
+(LanguageModel)andJIRA.Itsavesconfigurations,setsupweb-based
+configurations,andverifiesJIRAconnections.
+
+Args:
+args(argparse.Namespace):Command-lineargumentscontainingthetypeofconfigurationtohandle.
+
+Returns:
+int:Exitcodeindicatingsuccessorfailure.
+"""
+
+
+
+
+
+ifargs.config_type=="llm-cmd":
+from[penify_hook.commands.config_commands]importsave_llm_config
+[save_llm_config](args.model,args.api_base,args.api_key)
+print(f"LLMconfigurationset:Model={args.model},APIBase={args.api_baseor'default'}")
+
+elifargs.config_type=="llm":
+from[penify_hook.commands.config_commands]importconfig_llm_web
+[config_llm_web]()
+
+elifargs.config_type=="jira-cmd":
+from[penify_hook.commands.config_commands]importsave_jira_config
+[save_jira_config](args.url,args.username,args.api_token)
+print(f"JIRAconfigurationset:URL={args.url},Username={args.username}")
+from[penify_hook.jira_client]importJiraClient
+
+
+ifargs.verify:
+ifJiraClient:
+jira_client=JiraClient(
+jira_url=args.url,
+jira_user=args.username,
+jira_api_token=args.api_token
+)
+ifjira_client.is_connected():
+print("JIRAconnectionverifiedsuccessfully!")
+else:
+print("FailedtoconnecttoJIRA.Pleasecheckyourcredentials.")
+else:
+print("JIRApackagenotinstalled.Cannotverifyconnection.")
+
+elifargs.config_type=="jira":
+from[penify_hook.commands.config_commands]importconfig_jira_web
+[config_jira_web]()
+
+else:
+print("Pleasespecifyaconfigtype:llm,jira")
+return1
+
+return0
+
+
+
+
diff --git a/docs343/xml/config__commands_8py.xml b/docs343/xml/config__commands_8py.xml
new file mode 100644
index 0000000..34725a6
--- /dev/null
+++ b/docs343/xml/config__commands_8py.xml
@@ -0,0 +1,597 @@
+
+
+
+ config_commands.py
+ penify_hook
+ penify_hook::commands
+ penify_hook::commands::config_commands
+
+
+
+
+
+importjson
+importos
+importrandom
+importwebbrowser
+importhttp.server
+importsocketserver
+importpkg_resources
+frompathlibimportPath
+fromthreadingimportThread
+importlogging
+importsys
+fromtypingimportDict,Any,Optional,Union
+
+
+try:
+fromdotenvimportload_dotenv
+DOTENV_AVAILABLE=True
+exceptImportError:
+DOTENV_AVAILABLE=False
+
+
+def[load_env_files]()->None:
+"""
+Loadenvironmentvariablesfrom.envfilesinvariouslocations,
+withproperpriority(laterfilesoverrideearlierones):
+1.Userhomedirectory.env(lowestpriority)
+2.Gitreporootdirectory.env(ifinagitrepo)
+3.Currentdirectory.env(highestpriority)
+
+Thisfunctioniscalledwhenthemoduleisimported,ensuringenvvariables
+areavailablethroughouttheapplicationlifecycle.
+"""
+ifnotDOTENV_AVAILABLE:
+logging.warning("python-dotenvisnotinstalled..envfileloadingisdisabled.")
+logging.warning("Run'pipinstallpython-dotenv'toenable.envfilesupport.")
+return
+
+
+try:
+home_env=Path.home()/'.env'
+ifhome_env.exists():
+load_dotenv(dotenv_path=home_env,override=False)
+exceptExceptionase:
+logging.warning(f"Failedtoload.envfromhomedirectory:{str(e)}")
+
+
+try:
+from[penify_hook.utils]importrecursive_search_git_folder
+current_dir=os.getcwd()
+repo_root=[recursive_search_git_folder](current_dir)
+ifrepo_rootandrepo_root!=str(Path.home()):
+repo_env=Path(repo_root)/'.env'
+ifrepo_env.exists()andrepo_env!=home_env:
+load_dotenv(dotenv_path=repo_env,override=True)
+exceptExceptionase:
+logging.warning(f"Failedtoload.envfromGitrepo:{str(e)}")
+
+
+current_env=Path(os.getcwd())/'.env'
+ifcurrent_env.exists()and(notrepo_rootorcurrent_env!=Path(repo_root)/'.env'):
+load_dotenv(dotenv_path=current_env,override=True)
+
+
+
+[load_env_files]()
+
+
+def[get_penify_config]()->Path:
+"""Getthehomedirectoryforthe.penifyconfigurationfile.
+
+Thisfunctionsearchesforthe`.penify`fileinthecurrentdirectory
+anditsparentdirectoriesuntilitfindsitorreachesthehome
+directory.Ifnotfound,itcreatesthe`.penify`directoryandanempty
+`config.json`file.
+
+Returns:
+Path:Thepathtothe`config.json`filewithinthe`.penify`directory.
+"""
+current_dir=os.getcwd()
+from[penify_hook.utils]importrecursive_search_git_folder
+home_dir=[recursive_search_git_folder](current_dir)
+
+
+ifnothome_dir:
+home_dir=Path.home()
+else:
+home_dir=Path(home_dir)
+
+penify_dir=home_dir/'.penify'
+ifpenify_dir.exists():
+returnpenify_dir/'config.json'
+else:
+
+os.makedirs(penify_dir,exist_ok=True)
+
+
+
+os.makedirs(penify_dir,exist_ok=True)
+
+withopen(penify_dir/'config.json','w')asf:
+json.dump({},f)
+returnpenify_dir/'config.json'
+
+
+def[get_env_var_or_default](env_var:str,default:Any=None)->Any:
+"""
+Getenvironmentvariableorreturndefaultvalue.
+
+Args:
+env_var:Theenvironmentvariablename
+default:Defaultvalueifenvironmentvariableisnotset
+
+Returns:
+Valueoftheenvironmentvariableordefault
+"""
+returnos.environ.get(env_var,default)
+
+
+def[save_llm_config](model,api_base,api_key):
+"""
+SaveLLMconfigurationsettingsto.envfile.
+
+ThisfunctionsavesLLMconfigurationinthefollowingpriority:
+1.Gitreporoot.env(ifinsideagitrepo)
+2.Userhomedirectory.env
+"""
+frompathlibimportPath
+importos
+
+ifnotDOTENV_AVAILABLE:
+print("python-dotenvisnotinstalled.Run'pipinstallpython-dotenv'toenable.envfilesupport.")
+returnFalse
+
+
+try:
+from[penify_hook.utils]importrecursive_search_git_folder
+current_dir=os.getcwd()
+repo_root=[recursive_search_git_folder](current_dir)
+env_file=Path(repo_root)/'.env'ifrepo_rootelsePath.home()/'.env'
+exceptExceptionase:
+print(f"FailedtodetermineGitreporoot:{str(e)}")
+env_file=Path.home()/'.env'
+
+
+env_content={}
+ifenv_file.exists():
+withopen(env_file,'r')asf:
+forlineinf:
+line=line.strip()
+iflineandnotline.startswith('#')and'='inline:
+key,value=line.split('=',1)
+env_content[key.strip()]=value.strip()
+
+
+env_content['PENIFY_LLM_MODEL']=model
+env_content['PENIFY_LLM_API_BASE']=api_base
+env_content['PENIFY_LLM_API_KEY']=api_key
+
+
+try:
+withopen(env_file,'w')asf:
+forkey,valueinenv_content.items():
+f.write(f"{key}={value}\n")
+print(f"LLMconfigurationsavedto{env_file}")
+
+
+ifDOTENV_AVAILABLE:
+fromdotenvimportload_dotenv
+load_dotenv(dotenv_path=env_file,override=True)
+
+returnTrue
+exceptExceptionase:
+print(f"ErrorsavingLLMconfiguration:{str(e)}")
+returnFalse
+
+
+def[save_jira_config](url,username,api_token):
+"""
+SaveJIRAconfigurationsettingsto.envfile.
+
+ThisfunctionsavesJIRAconfigurationinthefollowingpriority:
+1.Gitreporoot.env(ifinsideagitrepo)
+2.Userhomedirectory.env
+"""
+frompathlibimportPath
+importos
+
+ifnotDOTENV_AVAILABLE:
+print("python-dotenvisnotinstalled.Run'pipinstallpython-dotenv'toenable.envfilesupport.")
+returnFalse
+
+
+try:
+from[penify_hook.utils]importrecursive_search_git_folder
+current_dir=os.getcwd()
+repo_root=[recursive_search_git_folder](current_dir)
+env_file=Path(repo_root)/'.env'ifrepo_rootelsePath.home()/'.env'
+exceptExceptionase:
+print(f"FailedtodetermineGitreporoot:{str(e)}")
+env_file=Path.home()/'.env'
+
+
+env_content={}
+ifenv_file.exists():
+withopen(env_file,'r')asf:
+forlineinf:
+line=line.strip()
+iflineandnotline.startswith('#')and'='inline:
+key,value=line.split('=',1)
+env_content[key.strip()]=value.strip()
+
+
+env_content['PENIFY_JIRA_URL']=url
+env_content['PENIFY_JIRA_USER']=username
+env_content['PENIFY_JIRA_TOKEN']=api_token
+
+
+try:
+withopen(env_file,'w')asf:
+forkey,valueinenv_content.items():
+f.write(f"{key}={value}\n")
+print(f"JIRAconfigurationsavedto{env_file}")
+
+
+ifDOTENV_AVAILABLE:
+fromdotenvimportload_dotenv
+load_dotenv(dotenv_path=env_file,override=True)
+
+returnTrue
+exceptExceptionase:
+print(f"ErrorsavingJIRAconfiguration:{str(e)}")
+returnFalse
+
+
+def[get_llm_config]()->Dict[str,str]:
+"""
+GetLLMconfigurationfromenvironmentvariables.
+
+Environmentvariables:
+-PENIFY_LLM_MODEL:Modelname
+-PENIFY_LLM_API_BASE:APIbaseURL
+-PENIFY_LLM_API_KEY:APIkey
+
+Returns:
+dict:Configurationdictionarywithmodel,api_base,andapi_key
+"""
+
+ifDOTENV_AVAILABLE:
+[load_env_files]()
+
+
+config={
+'model':[get_env_var_or_default]('PENIFY_LLM_MODEL',''),
+'api_base':[get_env_var_or_default]('PENIFY_LLM_API_BASE',''),
+'api_key':[get_env_var_or_default]('PENIFY_LLM_API_KEY','')
+}
+
+
+config={k:vfork,vinconfig.items()ifv}
+
+returnconfig
+
+
+def[get_jira_config]()->Dict[str,str]:
+"""
+GetJIRAconfigurationfromenvironmentvariables.
+
+Environmentvariables:
+-PENIFY_JIRA_URL:JIRAURL
+-PENIFY_JIRA_USER:JIRAusername
+-PENIFY_JIRA_TOKEN:JIRAAPItoken
+
+Returns:
+dict:Configurationdictionarywithurl,username,andapi_token
+"""
+
+ifDOTENV_AVAILABLE:
+[load_env_files]()
+
+
+config={
+'url':[get_env_var_or_default]('PENIFY_JIRA_URL',''),
+'username':[get_env_var_or_default]('PENIFY_JIRA_USER',''),
+'api_token':[get_env_var_or_default]('PENIFY_JIRA_TOKEN','')
+}
+
+
+config={k:vfork,vinconfig.items()ifv}
+
+returnconfig
+
+
+def[config_llm_web]():
+"""OpenawebbrowserinterfaceforconfiguringLLMsettings.
+
+ThisfunctionstartsatemporaryHTTPserverthatservesanHTML
+templateforconfiguringLargeLanguageModel(LLM)settings.Ithandles
+GETandPOSTrequeststoretrievethecurrentconfiguration,savenew
+configurations,andsuppresslogmessages.Theserverrunsonarandom
+portbetween30000and50000,anditisaccessibleviaaURLlike
+http://localhost:<redirect_port>.ThefunctionopensthisURLinthe
+defaultwebbrowserforconfiguration.Onceconfigured,theservershuts
+down.
+"""
+redirect_port=random.randint(30000,50000)
+server_url=f"http://localhost:{redirect_port}"
+
+print(f"Startingconfigurationserveron{server_url}")
+
+classConfigHandler(http.server.SimpleHTTPRequestHandler):
+defdo_GET(self):
+"""HandleHTTPGETrequests.
+
+ThisfunctionprocessesincomingGETrequestsandsendsappropriate
+responsesbasedontherequestedpath.ItservesanHTMLtemplatefor
+therootpath("/")andreturnsaJSONresponsewiththecurrentLLM
+configurationforthe"/get_config"path.Foranyotherpaths,it
+returnsa"NotFound"error.
+"""
+
+ifself.path=="/":
+self.send_response(200)
+self.send_header("Content-type","text/html")
+self.end_headers()
+
+
+template_path=pkg_resources.resource_filename(
+"penify_hook","templates/llm_config.html"
+)
+
+withopen(template_path,'r')asf:
+content=f.read()
+
+self.wfile.write(content.encode())
+elifself.path=="/get_config":
+self.send_response(200)
+self.send_header("Content-type","application/json")
+self.end_headers()
+
+
+current_config=[get_llm_config]()
+
+ifcurrent_config:
+response={
+"success":True,
+"config":current_config
+}
+else:
+response={
+"success":False,
+"message":"Noconfigurationfound"
+}
+
+self.wfile.write(json.dumps(response).encode())
+else:
+self.send_response(404)
+self.send_header("Content-type","text/plain")
+self.end_headers()
+self.wfile.write(b"NotFound")
+
+defdo_POST(self):
+"""HandlePOSTrequestsonthe/saveendpoint.
+
+ThismethodprocessesincomingPOSTrequeststosavelanguagemodel
+configurationdata.Itextractsthenecessaryparametersfromthe
+requestbody,savestheconfigurationusingtheprovideddetails,and
+thenschedulestheservertoshutdownafterasuccessfulsave.
+
+Args:
+self(HTTPRequestHandler):TheinstanceoftheHTTPRequestHandlerclasshandlingtherequest.
+"""
+
+ifself.path=="/save":
+content_length=int(self.headers['Content-Length'])
+post_data=self.rfile.read(content_length)
+data=json.loads(post_data.decode())
+
+model=data.get('model')
+api_base=data.get('api_base')
+api_key=data.get('api_key')
+
+try:
+[save_llm_config](model,api_base,api_key)
+
+self.send_response(200)
+self.send_header("Content-type","application/json")
+self.end_headers()
+response={
+"success":True,
+"message":f"LLMconfigurationsavedsuccessfully.Usingmodel:{model}"
+}
+self.wfile.write(json.dumps(response).encode())
+
+
+thread=Thread(target=self.server.shutdown)
+thread.daemon=True
+thread.start()
+
+exceptExceptionase:
+self.send_response(500)
+self.send_header("Content-type","application/json")
+self.end_headers()
+response={"success":False,"message":f"Errorsavingconfiguration:{str(e)}"}
+self.wfile.write(json.dumps(response).encode())
+else:
+self.send_response(404)
+self.send_header("Content-type","application/json")
+self.end_headers()
+self.wfile.write(json.dumps({"success":False,"message":"NotFound"}).encode())
+
+deflog_message(self,format,*args):
+
+return
+
+withsocketserver.TCPServer(("",redirect_port),ConfigHandler)ashttpd:
+print(f"Openingconfigurationpageinyourbrowser...")
+webbrowser.open(server_url)
+print(f"Waitingforconfigurationtobesubmitted...")
+httpd.serve_forever()
+
+print("Configurationcompleted.")
+
+
+def[config_jira_web]():
+"""OpenawebbrowserinterfaceforconfiguringJIRAsettings.
+
+ThisfunctionsetsupasimpleHTTPserverusingPython'sbuilt-in
+`http.server`moduletohandleGETandPOSTrequests.Theserverserves
+anHTMLpageforconfigurationandhandlessavingtheJIRAconfiguration
+detailsthroughAPItokensandURLs.Uponsuccessfulconfiguration,it
+shutsdowntheservergracefully.
+"""
+redirect_port=random.randint(30000,50000)
+server_url=f"http://localhost:{redirect_port}"
+
+print(f"Startingconfigurationserveron{server_url}")
+
+classConfigHandler(http.server.SimpleHTTPRequestHandler):
+defdo_GET(self):
+"""HandleGETrequestsfordifferentpaths.
+
+ThisfunctionprocessesGETrequestsbasedonthepathrequested.It
+servesanHTMLtemplatefortherootpath,returnsaJSONconfiguration
+foraspecificendpoint,andhandlesanyotherpathsbyreturninga404
+error.
+"""
+
+ifself.path=="/":
+self.send_response(200)
+self.send_header("Content-type","text/html")
+self.end_headers()
+
+
+template_path=pkg_resources.resource_filename(
+"penify_hook","templates/jira_config.html"
+)
+
+withopen(template_path,'r')asf:
+content=f.read()
+
+self.wfile.write(content.encode())
+elifself.path=="/get_config":
+self.send_response(200)
+self.send_header("Content-type","application/json")
+self.end_headers()
+
+
+current_config=[get_jira_config]()
+
+ifcurrent_config:
+response={
+"success":True,
+"config":current_config
+}
+else:
+response={
+"success":False,
+"message":"NoJIRAconfigurationfound"
+}
+
+self.wfile.write(json.dumps(response).encode())
+else:
+self.send_response(404)
+self.send_header("Content-type","text/plain")
+self.end_headers()
+self.wfile.write(b"NotFound")
+
+defdo_POST(self):
+"""HandleHTTPPOSTrequeststosaveJIRAconfiguration.
+
+ThismethodprocessesincomingPOSTrequeststosaveJIRAconfiguration
+details.ItreadsJSONdatafromtherequestbody,extractsnecessary
+parameters(URL,username,APItoken,andverify),savesthe
+configurationusingthe`save_jira_config`function,andrespondswith
+successorerrormessages.Ifanexceptionoccursduringtheprocess,it
+sendsa500InternalServerErrorresponse.
+"""
+
+ifself.path=="/save":
+content_length=int(self.headers['Content-Length'])
+post_data=self.rfile.read(content_length)
+data=json.loads(post_data.decode())
+
+url=data.get('url')
+username=data.get('username')
+api_token=data.get('api_token')
+verify=data.get('verify',False)
+
+try:
+
+[save_jira_config](url,username,api_token)
+
+
+self.send_response(200)
+self.send_header("Content-type","application/json")
+self.end_headers()
+response={
+"success":True,
+"message":f"JIRAconfigurationsavedsuccessfully."
+}
+self.wfile.write(json.dumps(response).encode())
+
+
+thread=Thread(target=self.server.shutdown)
+thread.daemon=True
+thread.start()
+
+exceptExceptionase:
+self.send_response(500)
+self.send_header("Content-type","application/json")
+self.end_headers()
+response={"success":False,"message":f"Errorsavingconfiguration:{str(e)}"}
+self.wfile.write(json.dumps(response).encode())
+else:
+self.send_response(404)
+self.send_header("Content-type","application/json")
+self.end_headers()
+self.wfile.write(json.dumps({"success":False,"message":"NotFound"}).encode())
+
+deflog_message(self,format,*args):
+
+return
+
+withsocketserver.TCPServer(("",redirect_port),ConfigHandler)ashttpd:
+print(f"Openingconfigurationpageinyourbrowser...")
+webbrowser.open(server_url)
+print(f"Waitingforconfigurationtobesubmitted...")
+httpd.serve_forever()
+
+print("Configurationcompleted.")
+
+
+def[get_token]()->Optional[str]:
+"""
+GettheAPItokenbasedonpriority:
+1.EnvironmentvariablePENIFY_API_TOKENfromany.envfile
+2.Configfile'api_keys'value
+
+Returns:
+strorNone:APItokeniffound,Noneotherwise
+"""
+
+ifDOTENV_AVAILABLE:
+[load_env_files]()
+
+
+env_token=[get_env_var_or_default]('PENIFY_API_TOKEN')
+ifenv_token:
+returnenv_token
+
+
+config_file=[get_penify_config]()
+ifconfig_file.exists():
+try:
+withopen(config_file,'r')asf:
+config=json.load(f)
+returnconfig.get('api_keys')
+except(json.JSONDecodeError,Exception)ase:
+print(f"Errorreading.penifyconfigfile:{str(e)}")
+
+returnNone
+
+
+
+
diff --git a/docs343/xml/conftest_8py.xml b/docs343/xml/conftest_8py.xml
new file mode 100644
index 0000000..1f83991
--- /dev/null
+++ b/docs343/xml/conftest_8py.xml
@@ -0,0 +1,23 @@
+
+
+
+ conftest.py
+ tests
+ tests::conftest
+
+
+
+
+
+importpytest
+importos
+importsys
+
+
+sys.path.insert(0,os.path.abspath(os.path.join(os.path.dirname(__file__),'..')))
+
+
+
+
+
+
diff --git a/docs343/xml/constants_8py.xml b/docs343/xml/constants_8py.xml
new file mode 100644
index 0000000..ba635e1
--- /dev/null
+++ b/docs343/xml/constants_8py.xml
@@ -0,0 +1,17 @@
+
+
+
+ constants.py
+ penify_hook
+ penify_hook::constants
+
+
+
+
+
+API_URL='http://localhost:8000/api'
+DASHBOARD_URL="https://dashboard.penify.dev/auth/localhost/login"
+
+
+
+
diff --git a/docs343/xml/detailed-usage_8md.xml b/docs343/xml/detailed-usage_8md.xml
new file mode 100644
index 0000000..cb55f77
--- /dev/null
+++ b/docs343/xml/detailed-usage_8md.xml
@@ -0,0 +1,173 @@
+
+
+
+ detailed-usage.md
+
+
+
+
+
+#PenifyCLI-DetailedUsageGuide
+
+Thisdocumentprovidesin-depthinformationaboutallfeaturesandcapabilitiesofthePenifyCLItool.
+
+##TableofContents
+
+-[PenifyCLI-DetailedUsageGuide](#penify-cli---detailed-usage-guide)
+-[TableofContents](#table-of-contents)
+-[Authentication](#authentication)
+-[LoginProcess](#login-process)
+-[APITokenStorage](#api-token-storage)
+-[TokenPrecedence](#token-precedence)
+-[CommandOverview](#command-overview)
+-[CommitMessageGeneration](#commit-message-generation)
+-[CodeDocumentationGeneration](#code-documentation-generation)
+-[UseCases](#use-cases)
+-[AuthenticationRequirement](#authentication-requirement)
+-[ConfigurationSettings](#configuration-settings)
+-[GitHooks](#git-hooks)
+-[Post-CommitHook](#post-commit-hook)
+-[CustomHookLocation](#custom-hook-location)
+-[AdvancedUseCases](#advanced-use-cases)
+-[CI/CDIntegration](#cicd-integration)
+-[RemoteRepositoryDocumentation](#remote-repository-documentation)
+-[Troubleshooting](#troubleshooting)
+-[CommonIssues](#common-issues)
+-[Logs](#logs)
+-[Support](#support)
+
+##Authentication
+
+###LoginProcess
+
+Whenyourun`penifylogin`,thetool:
+
+1.Opensyourdefaultwebbrowser
+2.RedirectsyoutoPenify'sloginpage
+3.Capturestheauthenticationtokenaftersuccessfullogin
+4.Savesthetokenin`~/.penify`file
+
+###APITokenStorage
+
+APItokensarestoredinyourhomedirectoryinthe`.penify`file.ThisJSONfilecontains:
+
+```json
+{
+"api_keys":"your-api-token",
+"llm":{"model":"...","api_base":"...","api_key":"..."},
+"jira":{"url":"...","username":"...","api_token":"..."}
+}
+```
+
+###TokenPrecedence
+
+1.Environmentvariable`PENIFY_API_TOKEN`(highestpriority)
+2.Tokenin`~/.penify`file
+
+##CommandOverview
+
+```
+penify
+├──commitGeneratesmartcommitmessages
+├──configConfigurelocalLLMandJIRA
+│├──llmConfigurelocalLLMsettings
+│└──jiraConfigureJIRAintegration
+├──loginLogintoPenifyaccount
+└──docgenGeneratecodedocumentation
+├──install-hookInstallGitpost-commithook
+└──uninstall-hookRemoveGitpost-commithook
+```
+
+##CommitMessageGeneration
+
+The`commit`commandanalyzesyourstagedchangesandgeneratesmeaningfulcommitmessages.Itcan:
+
+-UsealocalLLMifconfigured
+-EnhancemessageswithJIRAissuedetails
+-Providebothtitleanddescription
+
+Forspecificoptionsandexamples,see[docs/commit-commands.md](commit-commands.md).
+
+##CodeDocumentationGeneration
+
+The`docgen`commandgeneratesdocumentationforyourcode:
+
+###UseCases
+
+1.**CurrentGitDiff**:Defaultbehavior,documentsonlychangedfiles
+2.**SpecificFile**:Passafilepathwith`-lpath/to/file.py`
+3.**EntireFolder**:Passafolderpathwith`-lpath/to/folder`
+
+###AuthenticationRequirement
+
+ThisfeaturerequiresauthenticationwithaPenifyaccount.Run`penifylogin`beforeusingdocumentationfeatures.
+
+##ConfigurationSettings
+
+Configurelocalsettingsusingthe`config`command:
+
+-**LLMSettings**:ConfigurealocalLLMforcommitmessagegeneration
+-**JIRASettings**:SetupJIRAintegrationforenhancedcommitmessages
+
+Fordetailedconfigurationoptions,see[docs/config-commands.md](config-commands.md).
+
+##GitHooks
+
+PenifycaninstallGithookstoautomatedocumentationgeneration:
+
+###Post-CommitHook
+
+-**Install**:`penifydocgeninstall-hook`
+-**Whatitdoes**:Automaticallygeneratesdocumentationforchangedfilesaftereachcommit
+-**Uninstall**:`penifydocgenuninstall-hook`
+
+###CustomHookLocation
+
+YoucanspecifyacustomlocationforGithooks:
+
+```bash
+penifydocgeninstall-hook-l/path/to/git/repo
+```
+
+##AdvancedUseCases
+
+###CI/CDIntegration
+
+ForCI/CDpipelines:
+
+1.Set`PENIFY_API_TOKEN`asanenvironmentvariable
+2.Runcommandswithoutrequiringinteractivelogin
+
+###RemoteRepositoryDocumentation
+
+Generatedocumentationforanentirerepository:
+
+```bash
+gitclonehttps://github.com/user/repo
+cdrepo
+penifydocgen-l.
+```
+
+##Troubleshooting
+
+###CommonIssues
+
+1.**APIKeyErrors**:Ensureyou'verun`penifylogin`orset`PENIFY_API_TOKEN`
+2.**LLMConfiguration**:CheckyourLLMsettingswith`cat~/.penify`
+3.**JIRAIntegration**:VerifyJIRAcredentialsinyourconfiguration
+
+###Logs
+
+Formoredetailedlogs,youcansettheenvironmentvariable:
+
+```bash
+exportPENIFY_DEBUG=1
+```
+
+###Support
+
+Foradditionalhelp,visit[https://docs.penify.dev/](https://docs.penify.dev/)orcontactsupport@penify.dev
+
+
+
+
diff --git a/docs343/xml/dir_063e2d5fe58a131099a7fe4200cca78c.xml b/docs343/xml/dir_063e2d5fe58a131099a7fe4200cca78c.xml
new file mode 100644
index 0000000..64ba2d0
--- /dev/null
+++ b/docs343/xml/dir_063e2d5fe58a131099a7fe4200cca78c.xml
@@ -0,0 +1,17 @@
+
+
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/tests
+ __init__.py
+ conftest.py
+ test_commit_commands.py
+ test_config_commands.py
+ test_doc_commands.py
+ test_web_config.py
+
+
+
+
+
+
+
diff --git a/docs343/xml/dir_1648a057408aae8db85b8e3797335623.xml b/docs343/xml/dir_1648a057408aae8db85b8e3797335623.xml
new file mode 100644
index 0000000..300e1cd
--- /dev/null
+++ b/docs343/xml/dir_1648a057408aae8db85b8e3797335623.xml
@@ -0,0 +1,11 @@
+
+
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/docs
+
+
+
+
+
+
+
diff --git a/docs343/xml/dir_624fa2a8bce97f0444ac5cca335d4e23.xml b/docs343/xml/dir_624fa2a8bce97f0444ac5cca335d4e23.xml
new file mode 100644
index 0000000..52eaaa8
--- /dev/null
+++ b/docs343/xml/dir_624fa2a8bce97f0444ac5cca335d4e23.xml
@@ -0,0 +1,17 @@
+
+
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/penify_hook/commands
+ __init__.py
+ auth_commands.py
+ commit_commands.py
+ config_commands.py
+ doc_commands.py
+ hook_commands.py
+
+
+
+
+
+
+
diff --git a/docs343/xml/dir_b3b22d2ab7966b65f6b237e3231b41be.xml b/docs343/xml/dir_b3b22d2ab7966b65f6b237e3231b41be.xml
new file mode 100644
index 0000000..2a7c175
--- /dev/null
+++ b/docs343/xml/dir_b3b22d2ab7966b65f6b237e3231b41be.xml
@@ -0,0 +1,15 @@
+
+
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/docs
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/penify_hook
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/tests
+ setup.py
+
+
+
+
+
+
+
diff --git a/docs343/xml/dir_f88c3381c1861b3f7ca1f3d63cf244b5.xml b/docs343/xml/dir_f88c3381c1861b3f7ca1f3d63cf244b5.xml
new file mode 100644
index 0000000..9f4f478
--- /dev/null
+++ b/docs343/xml/dir_f88c3381c1861b3f7ca1f3d63cf244b5.xml
@@ -0,0 +1,27 @@
+
+
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/penify_hook
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/penify_hook/commands
+ __init__.py
+ api_client.py
+ base_analyzer.py
+ commit_analyzer.py
+ config_command.py
+ constants.py
+ file_analyzer.py
+ folder_analyzer.py
+ git_analyzer.py
+ jira_client.py
+ llm_client.py
+ login_command.py
+ main.py
+ ui_utils.py
+ utils.py
+
+
+
+
+
+
+
diff --git a/docs343/xml/doc__commands_8md.xml b/docs343/xml/doc__commands_8md.xml
new file mode 100644
index 0000000..839cd71
--- /dev/null
+++ b/docs343/xml/doc__commands_8md.xml
@@ -0,0 +1,340 @@
+
+
+
+ doc_commands.md
+
+
+
+
+
+#PenifyCLI-DocumentationGenerationCommands
+
+Thisdocumentprovidesadetailedguidetoallpermutationsandcombinationsofthe`docgen`command,includingextensiveinformationaboutGithookcommandsforautomatingdocumentationgeneration.
+
+##TableofContents
+
+-[BasicUsage](#basic-usage)
+-[CommandOptions](#command-options)
+-[OptionCombinations](#option-combinations)
+-[GitHookCommands](#git-hook-commands)
+-[HookInstallation](#hook-installation)
+-[HookCustomization](#hook-customization)
+-[HookUninstallation](#hook-uninstallation)
+-[AdvancedUseCases](#advanced-use-cases)
+-[Troubleshooting](#troubleshooting)
+
+##BasicUsage
+
+```bash
+penifydocgen
+```
+
+Bydefault,thiscommand:
+-AnalyzesthecurrentGitdiff(changessincelastcommit)
+-Generatesdocumentationforchangedfilesonly
+-Requiresauthenticationvia`penifylogin`
+
+##CommandOptions
+
+###`-l,--location`
+
+Specifyatargetfordocumentationgeneration:
+
+```bash
+#Generatedocumentationforaspecificfile
+penifydocgen-lpath/to/file.py
+
+#Generatedocumentationforaspecificfolder
+penifydocgen-lpath/to/folder
+```
+
+Withoutthisflag,PenifyanalyzesonlyGit-trackedmodifiedfiles.
+
+###Subcommands
+
+####`install-hook`
+
+InstallaGitpost-commithooktoautomaticallygeneratedocumentation:
+
+```bash
+penifydocgeninstall-hook
+```
+
+####`uninstall-hook`
+
+RemovetheGitpost-commithook:
+
+```bash
+penifydocgenuninstall-hook
+```
+
+##OptionCombinations
+
+###GenerateDocumentationforCurrentGitDiff
+
+```bash
+#Basicusage-currentGitdiff
+penifydocgen
+```
+
+###GenerateDocumentationforaSpecificFile
+
+```bash
+#Singlefiledocumentation
+penifydocgen-lsrc/main.py
+```
+
+###GenerateDocumentationforaFolder
+
+```bash
+#Folderdocumentation
+penifydocgen-lsrc/models/
+```
+
+###InstallHookinCurrentRepository
+
+```bash
+#InstallhookincurrentGitrepository
+penifydocgeninstall-hook
+```
+
+###InstallHookinSpecificRepository
+
+```bash
+#InstallhookinaspecificGitrepository
+penifydocgeninstall-hook-l/path/to/repo
+```
+
+###UninstallHookfromCurrentRepository
+
+```bash
+#UninstallhookfromcurrentGitrepository
+penifydocgenuninstall-hook
+```
+
+###UninstallHookfromSpecificRepository
+
+```bash
+#UninstallhookfromaspecificGitrepository
+penifydocgenuninstall-hook-l/path/to/repo
+```
+
+##GitHookCommands
+
+PenifyprovidesGithookcommandstoautomatedocumentationgenerationaspartofyourGitworkflow.
+
+###HookInstallation
+
+####HowHooksWork
+
+WhenyouinstallaGithookwith`penifydocgeninstall-hook`,Penify:
+
+1.Createsapost-commithookscriptinthe`.git/hooks`directory
+2.Makesthescriptexecutable
+3.Configuresthehooktorun`penifydocgen`aftereachcommit
+
+####HookScriptContent
+
+Thegeneratedpost-commithookcontains:
+
+```bash
+#!/bin/sh
+#Thisisapost-commithookgeneratedbypenify.
+#Automaticallygeneratesdocumentationforchangedfilesaftereachcommit.
+
+penifydocgen-gf/path/to/git/repository-tyour_api_token
+```
+
+####InstallationLocation
+
+Bydefault,hooksareinstalledinthecurrentGitrepository.Youcanspecifyadifferentlocation:
+
+```bash
+penifydocgeninstall-hook-l/path/to/repo
+```
+
+####InstallationRequirements
+
+Toinstallhooks,youneed:
+-AvalidPenifyAPItoken(loginfirstwith`penifylogin`)
+-Writepermissionstothe`.git/hooks`directory
+
+####VerifyingInstallation
+
+Afterinstallation,youcanverifythatthehookisinstalled:
+
+```bash
+cat.git/hooks/post-commit
+```
+
+###HookCustomization
+
+Youcancustomizethepost-commithookafterinstallation:
+
+####ModifyingHookBehavior
+
+1.Editthe`.git/hooks/post-commit`file
+2.Addadditionaloptionstothe`penifydocgen`command
+3.Addothercommandstorunaftercommit
+
+Exampleofacustomizedhook:
+
+```bash
+#!/bin/sh
+#Thisisapost-commithookgeneratedbypenify.
+#Automaticallygeneratesdocumentationforchangedfilesaftereachcommit.
+
+#Generatedocumentation
+penifydocgen-gf/path/to/git/repository-tyour_api_token
+
+#Additionalcustomcommands
+echo"Documentationgenerationcomplete!"
+```
+
+####AdvancedHookScenarios
+
+**ConditionalDocumentationGeneration**:
+
+```bash
+#!/bin/sh
+#Onlygeneratedocumentationforcommitstothemainbranch
+BRANCH=$(gitrev-parse--abbrev-refHEAD)
+if["$BRANCH"="main"];then
+penifydocgen-gf/path/to/git/repository-tyour_api_token
+fi
+```
+
+**DocumentingSpecificFiles/Folders**:
+
+```bash
+#!/bin/sh
+#OnlydocumentPythonfilesinthesrcdirectory
+penifydocgen-lsrc/-gf/path/to/git/repository-tyour_api_token
+```
+
+###HookUninstallation
+
+####StandardUninstallation
+
+Toremoveahookfromthecurrentrepository:
+
+```bash
+penifydocgenuninstall-hook
+```
+
+####SpecificRepositoryUninstallation
+
+Toremoveahookfromaspecificrepository:
+
+```bash
+penifydocgenuninstall-hook-l/path/to/repo
+```
+
+####ManualHookRemoval
+
+Ifneeded,youcanmanuallyremovethehook:
+
+```bash
+rm.git/hooks/post-commit
+```
+
+####VerifyingUninstallation
+
+Checkthatthehookwassuccessfullyremoved:
+
+```bash
+ls-la.git/hooks/post-commit#Shouldreturn"Nosuchfileordirectory"
+```
+
+##AdvancedUseCases
+
+###ContinuousIntegration
+
+RundocumentationgenerationinCIpipelines:
+
+```bash
+#InyourCIscript
+exportPENIFY_API_TOKEN=your_api_token
+penifydocgen-lsrc/
+```
+
+###BatchDocumentation
+
+Generatedocumentationformultiplerepositories:
+
+```bash
+#Bashscriptforbatchdocumentation
+forrepoinrepo1repo2repo3;do
+cd/path/to/$repo
+penifydocgen-l.
+done
+```
+
+###CustomGitHookIntegration
+
+IntegratewithotherGithooks:
+
+```bash
+#In.git/hooks/pre-push
+penifydocgen-lsrc/
+```
+
+###DocumentingReleaseTags
+
+Generatedocumentationwhencreatingareleasetag:
+
+```bash
+#Documenteverythingwhencreatingatag
+gittag-av1.0.0
+penifydocgen-l.#Documententirecodebase
+gitcommit--amend-m"Releasev1.0.0withupdateddocumentation"
+```
+
+##Troubleshooting
+
+###CommonIssues
+
+1.**"Authenticationrequired"**
+-Run`penifylogin`beforeusingdocumentationfeatures
+-CheckyourAPItokenwith`cat~/.penify`
+
+2.**"Permissiondeniedwheninstallinghook"**
+-CheckGitrepositorypermissions
+-Tryrunningwithsudo(ifappropriateforyourenvironment)
+-Ensurethe`.git/hooks`directoryexists
+
+3.**"Hookinstalledbutnotrunning"**
+-Checkifthehookisexecutable:`ls-la.git/hooks/post-commit`
+-Makeitexecutableifneeded:`chmod+x.git/hooks/post-commit`
+-Checkforsyntaxerrorsinthehookscript
+
+4.**"Fileordirectorynotfound"**
+-Verifythepathprovidedtothe`-l`option
+-Ensureyou'rerunningthecommandfromthecorrectdirectory
+
+5.**"Hookuninstallationfailed"**
+-Checkpermissionsonthe`.git/hooks`directory
+-Trymanualremoval:`rm.git/hooks/post-commit`
+
+###Debugging
+
+Fordetailedoutputwhenrunningdocumentationcommands:
+
+```bash
+exportPENIFY_DEBUG=1
+penifydocgen-lsrc/
+```
+
+###GettingHelp
+
+Forcommand-specifichelp:
+
+```bash
+penifydocgen--help
+penifydocgeninstall-hook--help
+penifydocgenuninstall-hook--help
+```
+
+
+
+
diff --git a/docs343/xml/doc__commands_8py.xml b/docs343/xml/doc__commands_8py.xml
new file mode 100644
index 0000000..86be493
--- /dev/null
+++ b/docs343/xml/doc__commands_8py.xml
@@ -0,0 +1,173 @@
+
+
+
+ doc_commands.py
+ penify_hook
+ penify_hook::commands
+ penify_hook::commands::doc_commands
+
+
+
+
+
+
+importargparse
+importlogging
+importos
+importsys
+importtime
+
+def[generate_doc](api_url,token,location=None):
+"""Generatesdocumentationbasedonthegivenparameters.
+
+ThisfunctioninitializesanAPIclientusingtheprovidedAPIURLand
+token.Itthengeneratesdocumentationbyanalyzingthespecified
+location,whichcanbeafolder,afile,orthecurrentworking
+directoryifnolocationisprovided.Thefunctionhandlesdifferent
+typesofanalysisbasedontheinputlocationandreportsanyerrors
+encounteredduringtheprocess.
+
+Args:
+api_url(str):TheURLoftheAPItoconnecttofordocumentationgeneration.
+token(str):TheauthenticationtokenforaccessingtheAPI.
+location(str?):Thepathtoaspecificfileorfoldertoanalyze.Ifnotprovided,the
+currentworkingdirectoryisused.
+"""
+t1=time.time()
+from..api_clientimportAPIClient
+print(f"TimetakentolaodAPIClinet:{time.time()-t1:.2f}seconds")
+"""Generatesdocumentationbasedonthegivenparameters.
+
+ThisfunctioninitializesanAPIclientusingtheprovidedAPIURLand
+token.Itthengeneratesdocumentationbyanalyzingthespecified
+location,whichcanbeafolder,afile,orthecurrentworking
+directoryifnolocationisprovided.Thefunctionhandlesdifferent
+typesofanalysisbasedontheinputlocationandreportsanyerrors
+encounteredduringtheprocess.
+
+Args:
+api_url(str):TheURLoftheAPItoconnecttofordocumentationgeneration.
+token(str):TheauthenticationtokenforaccessingtheAPI.
+location(str?):Thepathtoaspecificfileorfoldertoanalyze.
+Ifnotprovided,thecurrentworkingdirectoryisused.
+"""
+api_client=APIClient(api_url,token)
+iflocationisNone:
+current_folder_path=os.getcwd()
+try:
+from..git_analyzerimportGitDocGenHook
+analyzer=GitDocGenHook(current_folder_path,api_client)
+analyzer.run()
+exceptExceptionase:
+print(f"Error:{e}")
+sys.exit(1)
+
+
+eliflen(location.split('.'))>1:
+try:
+from..file_analyzerimportFileAnalyzerGenHook
+analyzer=FileAnalyzerGenHook(location,api_client)
+analyzer.run()
+exceptExceptionase:
+print(f"Error:{e}")
+sys.exit(1)
+
+else:
+try:
+from..folder_analyzerimportFolderAnalyzerGenHook
+analyzer=FolderAnalyzerGenHook(location,api_client)
+analyzer.run()
+exceptExceptionase:
+print(f"Error:{e}")
+sys.exit(1)
+
+
+
+docgen_description="""GeneratecodedocumentationusingPenify.
+
+ThiscommandrequiresyoutobeloggedintoyourPenifyaccount.
+Youcangeneratedocumentationfor:
+-CurrentGitdiff(default)
+-Specificfile
+-Specificfolder
+"""
+
+def[setup_docgen_parser](parser):
+"""SetupandconfigureaparserfordocumentationgenerationusingGit
+commands.
+
+Thisfunctionconfiguresaparserwithvarioussubcommandsandarguments
+necessaryforgeneratingdocumentationforGitdiffs,files,orfolders.
+Italsoinstallsanduninstallscommithookstoautomatedocumentation
+generationoncommits.
+
+Args:
+parser(argparse.ArgumentParser):Theparsertoconfigure.
+"""
+
+
+docgen_parser_description="""
+ItgeneratesDocumentationfortheGitdiff,fileorfolder.
+1.Bydefault,itwillgitdiffdocumentation-visithttps://penify.wiki/dcdcformoredetails.
+2.Iffileisprovided,itwillgeneratedocumentationforthatfile-visithttps://penify.wiki/dfdc
+3.Iffolderisprovided,itwillgeneratedocumentationforthatfolder-visithttps://penify.wiki/drdc
+4.CommitHookswillautomaticallygeneratedocumentationfortheGitdiffoncommit-https://penify.wiki/dpchc
+5.YouneedtobeloggedintoyourPenifyaccounttousethesecommands.
+"""
+
+parser.description=docgen_parser_description
+parser.formatter_class=argparse.RawDescriptionHelpFormatter
+docgen_subparsers=parser.add_subparsers(title="docgen_subcommand",dest="docgen_subcommand")
+
+
+parser.add_argument("-l","--location",help="[Optional]PathtothefolderorfiletoGenerateDocumentation.Bydefaultitwillpicktherootdirectory.",default=None)
+
+
+install_hook_parser=docgen_subparsers.add_parser("install-hook",help="InstalltheGitpost-commithook.")
+install_hook_parser.add_argument("-l","--location",required=False,
+help="LocationinwhichtoinstalltheGithook.Defaultstocurrentdirectory.",
+default=os.getcwd())
+
+
+uninstall_hook_parser=docgen_subparsers.add_parser("uninstall-hook",help="UninstalltheGitpost-commithook.")
+uninstall_hook_parser.add_argument("-l","--location",required=False,
+help="LocationfromwhichtouninstalltheGithook.Defaultstocurrentdirectory.",
+default=os.getcwd())
+
+def[handle_docgen](args):
+"""Handlevarioussubcommandsrelatedtodocumentgenerationandhook
+management.
+
+Thisfunctionprocessesdifferentsubcommandssuchasinstallingor
+uninstallinggithooks,anddirectlygeneratingdocumentationbasedon
+providedarguments.
+
+Args:
+args(Namespace):Parsedcommand-lineargumentscontainingthesubcommandandlocation
+details.
+"""
+
+
+from[penify_hook.commands.config_commands]importget_token
+importsys
+from[penify_hook.commands.doc_commands]importgenerate_doc
+from[penify_hook.commands.hook_commands]importinstall_git_hook,uninstall_git_hook
+from[penify_hook.constants]importAPI_URL
+
+token=[get_token]()
+ifnottoken:
+logging.error("Error:Unabletoauthenticate.Pleaserun'penifylogin'.")
+sys.exit(1)
+
+ifargs.docgen_subcommand=="install-hook":
+[install_git_hook](args.location,token)
+
+elifargs.docgen_subcommand=="uninstall-hook":
+[uninstall_git_hook](args.location)
+
+else:
+[generate_doc](API_URL,token,args.location)
+
+
+
+
diff --git a/docs343/xml/doxyfile.xsd b/docs343/xml/doxyfile.xsd
new file mode 100644
index 0000000..fbfc2c1
--- /dev/null
+++ b/docs343/xml/doxyfile.xsd
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/example-workflows_8md.xml b/docs343/xml/example-workflows_8md.xml
new file mode 100644
index 0000000..24722e9
--- /dev/null
+++ b/docs343/xml/example-workflows_8md.xml
@@ -0,0 +1,156 @@
+
+
+
+ example-workflows.md
+
+
+
+
+
+#PenifyCLIExampleWorkflows
+
+ThisdocumentdemonstrateshowtousePenifyCLIinreal-worlddevelopmentworkflowstoimproveyourproductivity.
+
+##Workflow1:EfficientGitCommitswithAI
+
+###Setup
+
+First,configureyourlocalLLMforofflineoperation:
+
+```bash
+penifyconfigllm
+```
+
+ConfigureyourJIRAintegrationforenhancedcommitmessages:
+
+```bash
+penifyconfigjira
+```
+
+###DailyWorkflow
+
+1.Makeyourcodechangesasusual
+2.Whenreadytocommit,usePenifytogenerateasmartcommitmessage:
+
+```bash
+penifycommit
+```
+
+3.Reviewandconfirmthegeneratedcommitmessage
+4.Gitcommitandpushasusual
+
+###Benefits
+
+-Consistentanddescriptivecommitmessages
+-AutomaticinclusionofrelevantJIRAticketinformation
+-Timesavedfromwritingdetailedcommitmessages
+
+##Workflow2:DocumentationGenerationPipeline
+
+###Setup
+
+LogintoPenifytoaccessadvanceddocumentationfeatures:
+
+```bash
+penifylogin
+```
+
+InstalltheGithookforautomaticdocumentationgeneration:
+
+```bash
+penifydocgeninstall-hook
+```
+
+###DailyWorkflow
+
+1.Makeyourcodechangesasusual
+2.Commityourchanges
+3.Documentationisautomaticallygeneratedforchangedfiles
+4.Reviewthegenerateddocumentation
+
+###ManualDocumentation
+
+Forspecificfilesorfolders:
+
+```bash
+penifydocgen-lsrc/components/authentication
+```
+
+###Benefits
+
+-Alwaysup-to-datedocumentation
+-Consistentdocumentationstyle
+-Timesavedfromwritingdetaileddocumentation
+
+##Workflow3:CodeReviewEnhancement
+
+###Setup
+
+Ensureyou'reloggedintoPenify:
+
+```bash
+penifylogin
+```
+
+###Workflow
+
+1.BeforesubmittingaPR,generatedocumentationforchangedfiles:
+
+```bash
+penifydocgen
+```
+
+2.IncludethegenerateddocumentationinyourPR
+3.ReviewerscanbetterunderstandyourchangeswiththeAI-generatedexplanations
+
+###Benefits
+
+-ImprovedPRquality
+-Fastercodereviews
+-Betterteamunderstandingofcodechanges
+
+##Workflow4:OnboardingNewTeamMembers
+
+###ForTeamLeads
+
+Generatecomprehensivedocumentationfortheentirecodebase:
+
+```bash
+penifydocgen-l.
+```
+
+###ForNewTeamMembers
+
+Generatefocuseddocumentationforcomponentsyou'reworkingon:
+
+```bash
+penifydocgen-lsrc/components/my-feature
+```
+
+###Benefits
+
+-Fasteronboarding
+-Betterunderstandingofcodestructure
+-Reducedquestionstoseniorteammembers
+
+##Workflow5:LegacyCodeUnderstanding
+
+Whenworkingwithunfamiliarlegacycode:
+
+```bash
+#Documentaspecificcomplexfile
+penifydocgen-lsrc/legacy/complex_module.py
+
+#Documentanentirelegacycomponent
+penifydocgen-lsrc/legacy/old_component
+```
+
+###Benefits
+
+-Quicklyunderstandcomplexlegacysystems
+-Reducetimespentdecipheringundocumentedcode
+-Makesaferchangestolegacysystems
+
+
+
+
diff --git a/docs343/xml/file__analyzer_8py.xml b/docs343/xml/file__analyzer_8py.xml
new file mode 100644
index 0000000..f47ec12
--- /dev/null
+++ b/docs343/xml/file__analyzer_8py.xml
@@ -0,0 +1,159 @@
+
+
+
+ file_analyzer.py
+ penify_hook::file_analyzer::FileAnalyzerGenHook
+ penify_hook
+ penify_hook::file_analyzer
+
+
+
+
+
+importos
+importsys
+fromgitimportRepo
+fromtqdmimporttqdm
+importtime
+
+from[penify_hook.base_analyzer]importBaseAnalyzer
+from[penify_hook.utils]importget_repo_details,recursive_search_git_folder
+from.api_clientimportAPIClient
+importlogging
+from.ui_utilsimport(
+format_highlight,print_info,print_success,print_warning,print_error,
+print_status,create_stage_progress_bar,
+update_stage,format_file_path
+)
+
+
+logger=logging.getLogger(__name__)
+
+class[FileAnalyzerGenHook]([BaseAnalyzer]):
+def[__init__](self,file_path:str,api_client:APIClient):
+self.[file_path]=file_path
+super().[__init__](file_path,api_client)
+
+
+
+def[process_file](self,file_path,pbar,new_param:str=""):
+"""Processesafilebyvalidatingitsextension,readingcontent,generatingdocumentation,
+andwritingchangesbacktothefile.
+
+Args:
+file_path(str):Thepathofthefiletobeprocessed.
+pbar(tqdm.tqdm):Aprogressbarobjecttoupdatethestatusofprocessingstages."""
+file_abs_path=os.path.join(os.getcwd(),file_path)
+file_extension=os.path.splitext(file_path)[1].lower()
+
+
+[update_stage](pbar,"Validating")
+ifnotfile_extension:
+[print_warning](f"Emptyextensionisnotsupported.Skipping'{self.relative_file_path}'.")
+returnFalse
+
+file_extension=file_extension[1:]
+
+iffile_extensionnotinself.[supported_file_types]:
+[print_warning](f"Filetype'{file_extension}'isnotsupported.Skipping'{self.relative_file_path}'.")
+returnFalse
+
+
+pbar.update(1)
+
+
+[update_stage](pbar,"Readingcontent")
+try:
+withopen(file_abs_path,'r')asfile:
+content=file.read()
+exceptExceptionase:
+logger.error(f"Errorreadingfile{file_path}:{str(e)}")
+returnFalse
+
+modified_lines=[iforiinrange(len(content.splitlines()))]
+
+
+pbar.update(1)
+
+
+[update_stage](pbar,"Documenting")
+
+response=self.[api_client].send_file_for_docstring_generation(self.[relative_file_path],content,modified_lines,self.[repo_details])
+
+ifresponseisNone:
+returnFalse
+
+ifresponse==content:
+logger.info(f"Nochangesneededfor{file_path}")
+returnFalse
+
+
+pbar.update(1)
+
+
+[update_stage](pbar,"Writingchanges")
+
+try:
+withopen(file_abs_path,'w')asfile:
+file.write(response)
+logger.info(f"Updatedfile{file_path}withgenerateddocumentation")
+
+
+pbar.update(1)
+returnTrue
+exceptExceptionase:
+logger.error(f"Errorwritingfile{file_path}:{str(e)}")
+returnFalse
+
+def[print_processing](self,file_path):
+"""Printsaformattedmessageindicatingthatafileisbeingprocessed."""
+formatted_path=[format_file_path](file_path)
+print(f"\n{format_highlight(f'Processingfile:{formatted_path}')}")
+
+def[run](self):
+
+
+"""Runsthedocumentationprocesswithaprogressbar."""
+stages=["Validating","Readingcontent","Documenting","Writingchanges","Completed"]
+pbar,_=[create_stage_progress_bar](stages,f"Startingdocumenting")
+
+try:
+
+
+
+
+result=self.[process_file](self.[file_path],pbar)
+
+
+remaining_steps=len(stages)-pbar.n
+pbar.update(remaining_steps)
+
+
+
+remaining=len(stages)-pbar.n
+ifremaining>0:
+pbar.update(remaining)
+[update_stage](pbar,"Complete")
+pbar.clear()
+pbar.close()
+
+exceptExceptionase:
+remaining=len(stages)-pbar.n
+ifremaining>0:
+pbar.update(remaining)
+[update_stage](pbar,"Complete")
+pbar.clear()
+pbar.close()
+[print_status]('error',e)
+sys.exit(1)
+
+
+ifresult:
+[print_success](f"\n✓Documentationupdatedfor{self.relative_file_path}")
+else:
+[print_success](f"\n✓Nochangesneededfor{self.relative_file_path}")
+
+
+
+
+
diff --git a/docs343/xml/folder__analyzer_8py.xml b/docs343/xml/folder__analyzer_8py.xml
new file mode 100644
index 0000000..37829c6
--- /dev/null
+++ b/docs343/xml/folder__analyzer_8py.xml
@@ -0,0 +1,82 @@
+
+
+
+ folder_analyzer.py
+ penify_hook::folder_analyzer::FolderAnalyzerGenHook
+ penify_hook
+ penify_hook::folder_analyzer
+
+
+
+
+
+importos
+fromgitimportRepo
+
+from[penify_hook.base_analyzer]importBaseAnalyzer
+from.api_clientimportAPIClient
+from.file_analyzerimportFileAnalyzerGenHook
+fromtqdmimporttqdm
+
+class[FolderAnalyzerGenHook]([BaseAnalyzer]):
+def[__init__](self,dir_path:str,api_client:APIClient):
+self.[dir_path]=dir_path
+super().[__init__](dir_path,api_client)
+
+def[list_all_files_in_dir](self,dir_path:str):
+"""Listallnon-hiddenfilesinadirectoryanditssubdirectories.
+
+Thisfunctionrecursivelytraversesthespecifieddirectoryandits
+subdirectories,collectingpathsofallnon-hiddenfiles.Itfiltersout
+hiddendirectoriesandfiles(thosestartingwithadot)toensureonly
+visiblefilesarereturned.
+
+Args:
+dir_path(str):Thepathtothedirectorywhosefilesandsubdirectoryfilesneedtobe
+listed.
+
+Returns:
+list:Alistcontainingthefullpathsofallnon-hiddenfileswithinthe
+specifieddirectoryanditssubdirectories.
+"""
+
+files=[]
+fordirpath,dirnames,filenamesinos.walk(dir_path):
+dirnames[:]=[dfordindirnamesifnotd.startswith(".")]
+forfilenameinfilenames:
+
+full_path=os.path.join(dirpath,filename)
+files.append(full_path)
+returnfiles
+
+def[run](self):
+"""Runthepost-commithook.
+
+Thisfunctionprocessesallfilesinaspecifieddirectoryusinga
+progressbar.Itlistsallfiles,initializesa`FileAnalyzerGenHook`
+foreachfile,andrunsit.Errorsduringprocessingofindividualfiles
+arecaughtandlogged,butdonotstoptheprocessingofotherfiles.A
+progressbarisdisplayedindicatingthenumberoffilesprocessed.
+
+Args:
+self(PostCommitHook):Theinstanceofthepost-commithookclass.
+"""
+try:
+file_list=self.[list_all_files_in_dir](self.[dir_path])
+total_files=len(file_list)
+print(f"Processing{total_files}filesinfolder[{self.dir_path}]")
+
+withtqdm(total=total_files,desc="Processingfiles",unit="file",ncols=80,ascii=True)aspbar:
+forfile_pathinfile_list:
+try:
+analyzer=[FileAnalyzerGenHook](file_path,self.[api_client])
+analyzer.run()
+exceptExceptionasfile_error:
+print(f"Errorprocessingfile[{file_path}]:{file_error}")
+pbar.update(1)
+exceptExceptionase:
+print(f"File[{self.dir_path}]wasnotprocessedduetoerror:{e}")
+
+
+
+
diff --git a/docs343/xml/git__analyzer_8py.xml b/docs343/xml/git__analyzer_8py.xml
new file mode 100644
index 0000000..0414b73
--- /dev/null
+++ b/docs343/xml/git__analyzer_8py.xml
@@ -0,0 +1,212 @@
+
+
+
+ git_analyzer.py
+ penify_hook::git_analyzer::GitDocGenHook
+ penify_hook
+ penify_hook::git_analyzer
+
+
+
+
+
+importos
+importre
+fromgitimportRepo
+fromtqdmimporttqdm
+
+from[penify_hook.base_analyzer]importBaseAnalyzer
+from[penify_hook.utils]importget_repo_details,recursive_search_git_folder
+from.api_clientimportAPIClient
+importlogging
+from.ui_utilsimport(
+print_info,print_success,print_warning,print_error,
+print_processing,print_status,create_progress_bar,
+format_file_path
+)
+
+
+logger=logging.getLogger(__name__)
+
+class[GitDocGenHook]([BaseAnalyzer]):
+def[__init__](self,repo_path:str,api_client:APIClient):
+super().[__init__](repo_path,api_client)
+
+def[get_modified_files_in_last_commit](self):
+"""Getthelistoffilesmodifiedinthelastcommit.
+
+Thisfunctionretrievesthefilesthatweremodifiedinthemostrecent
+commitoftherepository.Itaccessesthelastcommitanditerates
+throughthedifferencestocompilealistofuniquefilepathsthatwere
+changed.Thefunctionreturnsthislistforfurtherprocessingor
+analysis.
+
+Returns:
+list:Alistoffilepathsthatweremodifiedinthelastcommit.
+"""
+last_commit=self.[repo].head.commit
+modified_files=[]
+fordiffinlast_commit.diff('HEAD~1'):
+ifdiff.a_pathnotinmodified_files:
+modified_files.append(diff.a_path)
+returnmodified_files
+
+def[get_modified_lines](self,diff_text):
+"""Extractmodifiedlinenumbersfromadifftext.
+
+Thisfunctionprocessesadifftexttoidentifyandextracttheline
+numbersthathavebeenmodified.Itdistinguishesbetweenaddedand
+deletedlinesandkeepstrackofthecurrentlinenumberasitparses
+throughthediff.Thefunctionhandleshunkheadersandensuresthatany
+deletionsattheendofthefilearealsocaptured.
+
+Args:
+diff_text(str):Astringcontainingthedifftexttobeprocessed.
+
+Returns:
+list:Asortedlistofuniquelinenumbersthathavebeenmodified.
+"""
+modified_lines=[]
+current_line=0
+deletion_start=None
+
+forlineindiff_text.splitlines():
+ifline.startswith('@@'):
+
+_,old,new,_=line.split('',3)
+current_line=int(new.split(',')[0].strip('+'))
+deletion_start=None
+elifline.startswith('-'):
+
+ifdeletion_startisNone:
+deletion_start=current_line
+elifline.startswith('+'):
+
+modified_lines.append(current_line)
+current_line+=1
+ifdeletion_startisnotNone:
+modified_lines.append(deletion_start)
+deletion_start=None
+else:
+
+current_line+=1
+ifdeletion_startisnotNone:
+modified_lines.append(deletion_start)
+deletion_start=None
+
+
+ifdeletion_startisnotNone:
+modified_lines.append(deletion_start)
+
+returnsorted(set(modified_lines))
+
+def[process_file](self,file_path):
+"""Processafilebycheckingitstype,readingitscontent,andsendingit
+toanAPI.
+
+Thismethodconstructstheabsolutepathofthespecifiedfileand
+verifiesifthefilehasavalidextension.Ifthefiletypeis
+supported,itreadsthecontentofthefileandretrievesthe
+differencesfromthelastcommitintherepository.Ifchangesare
+detected,itsendsthefilecontentalongwiththemodifiedlinestoan
+APIforfurtherprocessing.IftheAPIresponseindicatesnochanges,
+theoriginalfilewillnotbeoverwritten.
+
+Args:
+file_path(str):Therelativepathtothefiletobeprocessed.
+
+Returns:
+bool:Trueifthefilewassuccessfullyprocessedandupdated,False
+otherwise.
+"""
+file_abs_path=os.path.join(self.[repo_path],file_path)
+file_extension=os.path.splitext(file_path)[1].lower()
+
+ifnotfile_extension:
+logger.info(f"File{file_path}hasnoextension.Skipping.")
+returnFalse
+
+file_extension=file_extension[1:]
+
+iffile_extensionnotinself.[supported_file_types]:
+logger.info(f"Filetype{file_extension}isnotsupported.Skipping{file_path}.")
+returnFalse
+
+withopen(file_abs_path,'r')asfile:
+content=file.read()
+
+
+last_commit=self.[repo].head.commit
+prev_commit=last_commit.parents[0]iflast_commit.parentselselast_commit
+
+
+diff_text=self.[repo].git.diff(prev_commit.hexsha,last_commit.hexsha,'--',file_path)
+
+ifnotdiff_text:
+logger.info(f"Nochangesdetectedfor{file_path}")
+returnFalse
+
+modified_lines=self.[get_modified_lines](diff_text)
+
+response=self.[api_client].send_file_for_docstring_generation(file_path,content,modified_lines,self.[repo_details])
+ifresponseisNone:
+returnFalse
+
+ifresponse==content:
+logger.info(f"Nochangesdetectedfor{file_path}")
+returnFalse
+
+withopen(file_abs_path,'w')asfile:
+file.write(response)
+logger.info(f"Updatedfile{file_path}withgenerateddocumentation")
+returnTrue
+
+def[run](self):
+"""Runthepost-commithook.
+
+Thismethodretrievesthelistofmodifiedfilesfromthelastcommit
+andprocesseseachfile.Itstagesanyfilesthathavebeenmodified
+duringprocessingandcreatesanauto-commitifchangesweremade.A
+progressbarisdisplayedtoindicatetheprocessingstatusofeach
+file.Themethodhandlesanyexceptionsthatoccurduringfile
+processing,printinganerrormessageforeachfilethatfailsto
+process.Ifanymodificationsaremadetothefiles,anauto-commitis
+createdtosavethosechanges.
+"""
+logger.info("Startingdoc_gen_hookprocessing")
+[print_info]("Startingdoc_gen_hookprocessing")
+
+modified_files=self.[get_modified_files_in_last_commit]()
+changes_made=False
+total_files=len(modified_files)
+
+with[create_progress_bar](total_files,"Processingfiles","file")aspbar:
+forfileinmodified_files:
+[print_processing](file)
+logging.info(f"Processingfile:{file}")
+try:
+ifself.[process_file](file):
+
+self.[repo].git.add(file)
+changes_made=True
+[print_status]('success',"Documentationupdated")
+else:
+[print_status]('warning',"Nochangesneeded")
+exceptExceptionasfile_error:
+error_msg=f"Errorprocessingfile[{file}]:{file_error}"
+logger.error(error_msg)
+[print_status]('error',error_msg)
+pbar.update(1)
+
+
+ifchanges_made:
+
+logger.info("Auto-commitcreatedwithchanges.")
+[print_success]("\n✓Auto-commitcreatedwithchanges")
+else:
+logger.info("doc_gen_hookcomplete.Nochangesmade.")
+[print_info]("\n✓doc_gen_hookcomplete.Nochangesmade.")
+
+
+
+
diff --git a/docs343/xml/hook__commands_8py.xml b/docs343/xml/hook__commands_8py.xml
new file mode 100644
index 0000000..4f9c773
--- /dev/null
+++ b/docs343/xml/hook__commands_8py.xml
@@ -0,0 +1,69 @@
+
+
+
+ hook_commands.py
+ penify_hook
+ penify_hook::commands
+ penify_hook::commands::hook_commands
+
+
+
+
+
+importsys
+frompathlibimportPath
+
+HOOK_FILENAME="post-commit"
+HOOK_TEMPLATE="""#!/bin/sh
+#Thisisapost-commithookgeneratedbypenify.
+#Automaticallygeneratesdocumentationforchangedfilesaftereachcommit.
+
+penifydocgen-gf{git_folder_path}-t{token}
+"""
+
+def[install_git_hook](location,token):
+"""Installapost-commithookinthespecifiedlocationthatgenerates
+documentation
+forchangedfilesaftereachcommit.
+
+Args:
+location(str):ThepathtotheGitrepositorywherethehookshouldbeinstalled.
+token(str):Theauthenticationtokenrequiredtoaccessthedocumentationgeneration
+service.
+"""
+hooks_dir=Path(location)/".git/hooks"
+hook_path=hooks_dir/HOOK_FILENAME
+
+ifnothooks_dir.exists():
+print(f"Error:Thehooksdirectory{hooks_dir}doesnotexist.")
+sys.exit(1)
+
+hook_content=HOOK_TEMPLATE.format(token=token,git_folder_path=location)
+hook_path.write_text(hook_content)
+hook_path.chmod(0o755)
+
+print(f"Post-commithookinstalledin{hook_path}")
+print(f"Documentationwillnowbeautomaticallygeneratedaftereachcommit.")
+
+def[uninstall_git_hook](location):
+"""Uninstallsthepost-commithookfromthespecifiedlocation.
+
+Thisfunctionattemptstoremoveapost-commitgithooklocatedatthe
+givenpath.Itconstructsthepathtothehookandchecksifitexists.
+Ifthehookisfound,itisdeleted,andaconfirmationmessageis
+printed.Ifnohookisfound,amessageindicatingthisisalsoprinted.
+
+Args:
+location(Path):Thebasedirectorywherethe.git/hooksdirectoryislocated.
+"""
+hook_path=Path(location)/".git/hooks"/HOOK_FILENAME
+
+ifhook_path.exists():
+hook_path.unlink()
+print(f"Post-commithookuninstalledfrom{hook_path}")
+else:
+print(f"Nopost-commithookfoundin{hook_path}")
+
+
+
+
diff --git a/docs343/xml/index.xml b/docs343/xml/index.xml
new file mode 100644
index 0000000..01b2ebc
--- /dev/null
+++ b/docs343/xml/index.xml
@@ -0,0 +1,351 @@
+
+
+ penify_hook::api_client::APIClient
+ api_url
+ AUTH_TOKEN
+ BEARER_TOKEN
+ __init__
+ send_file_for_docstring_generation
+ generate_commit_summary
+ get_supported_file_types
+ generate_commit_summary_with_llm
+ get_api_key
+
+ penify_hook::base_analyzer::BaseAnalyzer
+ folder_path
+ repo_path
+ repo
+ repo_details
+ relative_file_path
+ api_client
+ supported_file_types
+ __init__
+
+ penify_hook::commit_analyzer::CommitDocGenHook
+ llm_client
+ __init__
+ get_summary
+ run
+ process_jira_integration
+ _amend_commit
+
+ Exception
+
+ penify_hook::file_analyzer::FileAnalyzerGenHook
+ file_path
+ __init__
+ process_file
+ print_processing
+ run
+
+ penify_hook::folder_analyzer::FolderAnalyzerGenHook
+ dir_path
+ __init__
+ list_all_files_in_dir
+ run
+
+ penify_hook::git_analyzer::GitDocGenHook
+ __init__
+ get_modified_files_in_last_commit
+ get_modified_lines
+ process_file
+ run
+
+ penify_hook::utils::GitRepoNotFoundError
+
+ penify_hook::jira_client::JiraClient
+ jira_url
+ jira_user
+ jira_api_token
+ jira_client
+ __init__
+ is_connected
+ extract_issue_keys_from_branch
+ extract_issue_keys
+ get_issue_details
+ add_comment
+ update_issue_status
+ format_commit_message_with_jira_info
+ get_detailed_issue_context
+ get_commit_context_from_issues
+ enhance_commit_message
+
+ penify_hook::llm_client::LLMClient
+ model
+ _litellm
+ __init__
+ litellm
+ generate_commit_summary
+
+ tests::test_commit_commands::TestCommitCommands
+ mock_api_client
+ mock_llm_client
+ mock_jira_client
+ mock_commit_doc_gen
+ mock_git_folder_search
+ mock_print_functions
+ test_commit_code_with_llm_client
+ test_commit_code_with_jira_client
+ test_commit_code_with_jira_connection_failure
+ test_commit_code_error_handling
+ test_setup_commit_parser
+ test_handle_commit
+
+ tests::test_config_commands::TestConfigCommands
+ test_get_penify_config_existing_dir
+ test_get_penify_config_new_dir
+ test_get_llm_config_exists
+ test_get_llm_config_empty
+ test_get_llm_config_invalid_json
+ test_get_jira_config_exists
+ test_save_llm_config_success
+ test_save_llm_config_failure
+ test_save_jira_config_success
+ test_get_token_from_env
+ test_get_token_from_config
+ test_get_token_not_found
+
+ tests::test_web_config::TestWebConfig
+ test_config_llm_web_server_setup
+ test_config_jira_web_server_setup
+
+ penify_hook
+
+ penify_hook::api_client
+
+ penify_hook::base_analyzer
+
+ penify_hook::commands
+
+ penify_hook::commands::auth_commands
+ save_credentials
+ login
+
+ penify_hook::commands::commit_commands
+ commit_code
+ setup_commit_parser
+ handle_commit
+
+ penify_hook::commands::config_commands
+ DOTENV_AVAILABLE
+ path
+ load_env_files
+ get_penify_config
+ get_env_var_or_default
+ save_llm_config
+ save_jira_config
+ get_llm_config
+ get_jira_config
+ config_llm_web
+ config_jira_web
+ get_token
+
+ penify_hook::commands::doc_commands
+ docgen_description
+ generate_doc
+ setup_docgen_parser
+ handle_docgen
+
+ penify_hook::commands::hook_commands
+ HOOK_FILENAME
+ HOOK_TEMPLATE
+ install_git_hook
+ uninstall_git_hook
+
+ penify_hook::commit_analyzer
+
+ penify_hook::config_command
+ setup_config_parser
+ handle_config
+
+ penify_hook::constants
+ API_URL
+ DASHBOARD_URL
+
+ penify_hook::file_analyzer
+ logger
+
+ penify_hook::folder_analyzer
+
+ penify_hook::git_analyzer
+ logger
+
+ penify_hook::jira_client
+ JIRA_AVAILABLE
+
+ penify_hook::llm_client
+
+ penify_hook::login_command
+ setup_login_parser
+ handle_login
+
+ penify_hook::main
+ main
+
+ penify_hook::ui_utils
+ autoreset
+ INFO_COLOR
+ SUCCESS_COLOR
+ WARNING_COLOR
+ ERROR_COLOR
+ HIGHLIGHT_COLOR
+ NEUTRAL_COLOR
+ SUCCESS_SYMBOL
+ WARNING_SYMBOL
+ ERROR_SYMBOL
+ PROCESSING_SYMBOL
+ format_info
+ format_success
+ format_warning
+ format_error
+ format_highlight
+ format_file_path
+ print_info
+ print_success
+ print_warning
+ print_error
+ print_processing
+ print_status
+ create_progress_bar
+ create_stage_progress_bar
+ update_stage
+
+ penify_hook::utils
+ logger
+ get_repo_details
+ recursive_search_git_folder
+ find_git_parent
+
+ setup
+ name
+ version
+ packages
+ install_requires
+ entry_points
+ author
+ author_email
+ description
+ long_description
+ long_description_content_type
+ url
+ classifiers
+ python_requires
+
+ std
+
+ tests
+
+ tests::conftest
+
+ tests::test_commit_commands
+
+ tests::test_config_commands
+
+ tests::test_doc_commands
+ test_generate_doc_no_location
+ test_generate_doc_file_location
+ test_generate_doc_folder_location
+ test_generate_doc_error_handling
+ test_setup_docgen_parser
+ test_handle_docgen_install_hook
+ test_handle_docgen_uninstall_hook
+ test_handle_docgen_generate
+ test_handle_docgen_no_token
+ test_generate_doc_with_file_exception
+ test_generate_doc_with_folder_exception
+
+ tests::test_web_config
+
+ commit-commands.md
+
+ config-commands.md
+
+ detailed-usage.md
+
+ doc_commands.md
+
+ example-workflows.md
+
+ penify-cli-documentation.md
+
+ api_client.py
+
+ base_analyzer.py
+
+ __init__.py
+
+ __init__.py
+
+ __init__.py
+
+ auth_commands.py
+
+ commit_commands.py
+
+ config_commands.py
+
+ doc_commands.py
+
+ hook_commands.py
+
+ commit_analyzer.py
+
+ config_command.py
+
+ constants.py
+
+ file_analyzer.py
+
+ folder_analyzer.py
+
+ git_analyzer.py
+
+ jira_client.py
+
+ llm_client.py
+
+ login_command.py
+
+ main.py
+
+ ui_utils.py
+
+ utils.py
+
+ README.md
+
+ setup.py
+
+ conftest.py
+
+ test_commit_commands.py
+
+ test_config_commands.py
+
+ test_doc_commands.py
+
+ test_web_config.py
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_commit_commands
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_config_commands
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_detailed_usage
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_doc_commands
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_example_workflows
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_README
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/penify_hook/commands
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/docs
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/penify_hook
+
+ /tmp/github_reposRepoArchDocGenContext/Penify-dev/penify-cli/tests
+
+
diff --git a/docs343/xml/index.xsd b/docs343/xml/index.xsd
new file mode 100644
index 0000000..cfb7041
--- /dev/null
+++ b/docs343/xml/index.xsd
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/jira__client_8py.xml b/docs343/xml/jira__client_8py.xml
new file mode 100644
index 0000000..d7cc43a
--- /dev/null
+++ b/docs343/xml/jira__client_8py.xml
@@ -0,0 +1,472 @@
+
+
+
+ jira_client.py
+ penify_hook::jira_client::JiraClient
+ penify_hook
+ penify_hook::jira_client
+
+
+
+
+
+importre
+importlogging
+fromtypingimportOptional,Dict,List,Any
+
+from[penify_hook.ui_utils]importprint_info,print_success
+try:
+fromjiraimportJIRA
+JIRA_AVAILABLE=True
+exceptImportError:
+JIRA_AVAILABLE=False
+
+class[JiraClient]:
+"""
+ClientforinteractingwithJIRAAPI
+"""
+
+def[__init__](self,jira_url:str=None,jira_user:str=None,jira_api_token:str=None):
+"""
+InitializetheJIRAclient.
+
+Args:
+jira_url:BaseURLforJIRAinstance(e.g.,"https://your-domain.atlassian.net")
+jira_user:JIRAusernameoremail
+jira_api_token:JIRAAPItoken
+"""
+self.[jira_url]=jira_url
+self.[jira_user]=jira_user
+self.[jira_api_token]=jira_api_token
+self.[jira_client]=None
+
+ifnotJIRA_AVAILABLE:
+logging.warning("JIRApackagenotavailable.JIRAintegrationwillnotwork.")
+return
+
+ifjira_urlandjira_userandjira_api_token:
+try:
+self.[jira_client]=JIRA(
+server=jira_url,
+basic_auth=(jira_user,jira_api_token)
+)
+logging.info("JIRAclientinitializedsuccessfully")
+exceptExceptionase:
+logging.error(f"FailedtoinitializeJIRAclient:{e}")
+self.[jira_client]=None
+
+def[is_connected](self)->bool:
+"""CheckiftheJIRAclientisconnected.
+
+ThisfunctionverifieswhethertheJIRAclienthassuccessfully
+establishedaconnection.Itreturns`True`iftheclientisconnected,
+and`False`otherwise.
+
+Returns:
+bool:TrueiftheJIRAclientisconnected,Falseotherwise
+"""
+returnself.[jira_client]isnotNone
+
+def[extract_issue_keys_from_branch](self,branch_name:str)->List[str]:
+"""ExtractsJIRAissuekeysfromabranchname.
+
+Thisfunctionsearchesthroughagivengitbranchnametofindand
+returnanyJIRAissuekeysthatmatchthepattern.Commonconventions
+forJIRAissuekeysinbranchnamesinclude:-
+feature/PROJECT-123-description-bugfix/PROJECT-123-fix-something-
+hotfix/PROJECT-123/short-desc
+
+Args:
+branch_name(str):ThenameofthegitbranchtosearchforJIRAissuekeys.
+
+Returns:
+List[str]:AlistofuniqueJIRAissuekeysfoundinthebranchname.
+
+Examples:
+[extract_issue_keys_from_branch]("feature/PROJ-456-add-new-feature")
+
+"""
+
+pattern=r'[A-Z][A-Z0-9_]+-[0-9]+'
+matches=re.findall(pattern,branch_name)
+ifmatches:
+[print_info](f"FetchingrelevantJIRAissues")
+returnlist(set(matches))
+
+def[extract_issue_keys](self,text:str)->List[str]:
+"""ExtractJIRAissuekeysfromagiventext.
+
+Thisfunctionsearchesthroughtheprovidedtexttofindandreturnall
+uniqueJIRAissuekeys.AJIRAissuekeytypicallyfollowsthepattern
+ofPROJECT-123,wherePROJECTisalphanumericandconsistsofatleast
+oneuppercaseletterfollowedbyoneormorealphanumericcharacters,
+and123isanumericsequence.
+
+Args:
+text(str):ThetextinwhichtosearchforJIRAissuekeys.
+
+Returns:
+List[str]:AlistofuniqueJIRAissuekeysfoundinthetext.
+"""
+
+pattern=r'[A-Z][A-Z0-9_]+-[0-9]+'
+matches=re.findall(pattern,text)
+returnlist(set(matches))
+
+def[get_issue_details](self,issue_key:str)->Optional[Dict[str,Any]]:
+"""RetrievedetailsofaJIRAissuebasedonitskey.
+
+ThisfunctionfetchesdetailedinformationaboutaspecifiedJIRAissue
+usingtheprovidedissuekey.ItchecksiftheJIRAclientisconnected
+beforeattemptingtoretrievetheissue.Iftheclientisnotconnected,
+itlogsawarningandreturns`None`.Thefunctionthenattemptsto
+fetchtheissuefromtheJIRAserverandconstructsadictionary
+containingvariousdetailsabouttheissuesuchasitskey,summary,
+status,description,assignee,reporter,type,priority,andURL.Ifany
+errorsoccurduringthisprocess,theyarelogged,and`None`is
+returned.
+
+Args:
+issue_key(str):TheJIRAissuekey(e.g.,"PROJECT-123").
+
+Returns:
+Dict[str,Any]orNone:AdictionarycontainingthedetailsoftheJIRA
+issueiffound,otherwise`None`.
+"""
+ifnotself.[is_connected]():
+logging.warning("JIRAclientnotconnected")
+returnNone
+
+try:
+issue=self.[jira_client].issue(issue_key)
+return{
+'key':issue.key,
+'summary':issue.fields.summary,
+'status':issue.fields.status.name,
+'description':issue.fields.description,
+'assignee':issue.fields.assignee.displayNameifissue.fields.assigneeelseNone,
+'reporter':issue.fields.reporter.displayNameifissue.fields.reporterelseNone,
+'type':issue.fields.issuetype.name,
+'priority':issue.fields.priority.nameifhasattr(issue.fields,'priority')andissue.fields.priorityelseNone,
+'url':f"{self.jira_url}/browse/{issue.key}"
+}
+exceptExceptionase:
+logging.error(f"Errorfetchingissue{issue_key}:{e}")
+returnNone
+
+def[add_comment](self,issue_key:str,comment:str)->bool:
+"""AddacommenttoaJIRAissue.
+
+Args:
+issue_key(str):JIRAissuekey(e.g.,"PROJECT-123")
+comment(str):Commenttexttoadd
+
+Returns:
+bool:Trueifthecommentwasaddedsuccessfully,Falseotherwise
+"""
+ifnotself.[is_connected]():
+logging.warning("JIRAclientnotconnected")
+returnFalse
+
+try:
+self.[jira_client].[add_comment](issue_key,comment)
+logging.info(f"Commentaddedto{issue_key}")
+returnTrue
+exceptExceptionase:
+logging.error(f"Erroraddingcommentto{issue_key}:{e}")
+returnFalse
+
+def[update_issue_status](self,issue_key:str,transition_name:str)->bool:
+"""UpdatethestatusofaJIRAissue.
+
+Args:
+issue_key(str):ThekeyoftheJIRAissuetobeupdated.
+transition_name(str):Thenameofthedesiredtransition.
+
+Returns:
+bool:Trueifthestatuswassuccessfullyupdated,Falseotherwise.
+"""
+ifnotself.[is_connected]():
+logging.warning("JIRAclientnotconnected")
+returnFalse
+
+try:
+
+transitions=self.[jira_client].transitions(issue_key)
+
+
+transition_id=None
+fortintransitions:
+ift['name'].lower()==transition_name.lower():
+transition_id=t['id']
+break
+
+iftransition_id:
+self.[jira_client].transition_issue(issue_key,transition_id)
+logging.info(f"Updated{issue_key}statusto{transition_name}")
+returnTrue
+else:
+logging.warning(f"Transition'{transition_name}'notfoundfor{issue_key}")
+returnFalse
+
+exceptExceptionase:
+logging.error(f"Errorupdatingstatusfor{issue_key}:{e}")
+returnFalse
+
+def[format_commit_message_with_jira_info](self,commit_title:str,commit_description:str,issue_keys:List[str]=None)->tuple:
+"""FormatcommitmessagewithJIRAissueinformation.
+
+Args:
+commit_title(str):Theoriginalcommittitle.
+commit_description(str):Theoriginalcommitdescription.
+issue_keys(List[str]?):AlistofJIRAissuekeystoincludeinthecommitmessage.Ifnot
+provided,issuekeyswillbeextractedfromboththetitleandthe
+description.
+
+Returns:
+tuple:AtuplecontainingtheupdatedcommittitleanddescriptionwithJIRA
+informationincluded.
+"""
+
+ifnotissue_keys:
+title_keys=self.[extract_issue_keys](commit_title)
+desc_keys=self.[extract_issue_keys](commit_description)
+issue_keys=list(set(title_keys+desc_keys))
+
+ifnotissue_keysornotself.[is_connected]():
+returncommit_title,commit_description
+
+
+updated_title=commit_title
+ifissue_keysandnotany(keyincommit_titleforkeyinissue_keys):
+
+updated_title=f"{issue_keys[0]}:{commit_title}"
+
+
+updated_description=commit_description
+
+issue_details_section="\n\n##RelatedJIRAIssues\n\n"
+has_issue_details=False
+
+forissue_keyinissue_keys:
+details=self.[get_issue_details](issue_key)
+ifdetails:
+has_issue_details=True
+issue_details_section+=(
+f"***[{details['key']}]({details['url']})**:{details['summary']}\n"
+f"*Status:{details['status']}\n"
+f"*Type:{details['type']}\n"
+)
+
+ifhas_issue_details:
+updated_description+=issue_details_section
+
+returnupdated_title,updated_description
+
+def[get_detailed_issue_context](self,issue_key:str)->Dict[str,Any]:
+"""RetrievecomprehensivedetailsaboutaJIRAissueincludingcontextfor
+bettercommitmessages.
+
+ThisfunctionfetchesdetailedinformationfromaspecifiedJIRAissue
+andconstructsadictionarycontainingvariouscontextfieldssuchas
+theissuesummary,description,type,status,priority,comments,URL,
+andadditionalcustomfieldslikeacceptancecriteriaandsprint
+information.Ifanyerrorsoccurduringthefetchingprocess,
+appropriatewarningsorerrorsarelogged.
+
+Args:
+issue_key(str):TheJIRAissuekey(e.g.,"PROJECT-123").
+
+Returns:
+Dict[str,Any]:Adictionarycontainingbusinessandtechnicalcontextfromtheissue.
+"""
+ifnotself.[is_connected]():
+logging.warning("JIRAclientnotconnected")
+return{}
+
+try:
+issue=self.[jira_client].issue(issue_key)
+
+
+comments=[]
+try:
+forcommentinself.[jira_client].comments(issue):
+comments.append(comment.body)
+exceptExceptionase:
+logging.warning(f"Couldnotfetchcommentsfor{issue_key}:{e}")
+
+
+context={
+'key':issue.key,
+'summary':issue.fields.summary,
+'description':issue.fields.descriptionor"",
+'type':issue.fields.issuetype.name,
+'status':issue.fields.status.name,
+'priority':issue.fields.priority.nameifhasattr(issue.fields,'priority')andissue.fields.priorityelse"None",
+'comments':comments[:3],
+'url':f"{self.jira_url}/browse/{issue.key}"
+}
+
+
+
+acceptance_criteria=None
+try:
+forfield_namein['customfield_10001','acceptance_criteria','customfield_10207']:
+ifhasattr(issue.fields,field_name):
+field_value=getattr(issue.fields,field_name)
+iffield_value:
+acceptance_criteria=field_value
+break
+exceptException:
+pass
+
+ifacceptance_criteria:
+context['acceptance_criteria']=acceptance_criteria
+
+
+try:
+sprint_field=None
+forfield_nameindir(issue.fields):
+if'sprint'infield_name.lower():
+sprint_field=field_name
+break
+
+ifsprint_field:
+sprint_value=getattr(issue.fields,sprint_field)
+ifsprint_value:
+ifisinstance(sprint_value,list)andlen(sprint_value)>0:
+context['sprint']=sprint_value[0]
+else:
+context['sprint']=str(sprint_value)
+exceptExceptionase:
+logging.debug(f"Couldnotextractsprintinformation:{e}")
+
+returncontext
+
+exceptExceptionase:
+logging.error(f"Errorfetchingdetailedinformationfor{issue_key}:{e}")
+return{}
+
+def[get_commit_context_from_issues](self,issue_keys:List[str])->Dict[str,Any]:
+"""GathercontextualinformationfromJIRAissuestoimprovecommit
+messages.
+
+ThisfunctionprocessesalistofJIRAissuekeys,retrievesdetailed
+contextforeachissue,andaggregatesitintoadictionarythatcanbe
+usedtoenhancecommitmessages.Itfirstretrievestheprimaryissue
+(thefirstkeyinthelist)andthengathersbasicdetailsforany
+relatedissues.Theresultingcontextincludesinformationfromboththe
+primaryandrelatedissues,alongwithallissuekeys.
+
+Args:
+issue_keys:ListofJIRAissuekeystogatherinformationfrom
+
+Returns:
+Dictcontainingbusinessandtechnicalcontextfromtheissues
+"""
+ifnotissue_keysornotself.[is_connected]():
+return{}
+
+
+primary_issue=self.[get_detailed_issue_context](issue_keys[0])
+
+
+related_issues=[]
+forkeyinissue_keys[1:]:
+details=self.[get_issue_details](key)
+ifdetails:
+related_issues.append(details)
+
+
+context={
+'primary_issue':primary_issue,
+'related_issues':related_issues,
+'all_keys':issue_keys
+}
+
+returncontext
+
+def[enhance_commit_message](self,title:str,description:str,issue_keys:List[str])->tuple:
+"""EnhanceacommitmessagewithbusinessandtechnicalcontextfromJIRA
+issues.
+
+Args:
+title(str):Originalcommittitle.
+description(str):Originalcommitdescription.
+issue_keys(List[str]):ListofJIRAissuekeystoincludeintheenhancedcommitmessage.
+
+Returns:
+tuple:Atuplecontainingtheenhancedcommittitleanddescriptionwithadded
+contextfromJIRAissues.
+"""
+ifnotissue_keysornotself.[is_connected]():
+returntitle,description
+
+
+context=self.[get_commit_context_from_issues](issue_keys)
+ifnotcontextornotcontext.get('primary_issue'):
+returnself.[format_commit_message_with_jira_info](title,description,issue_keys)
+
+
+primary=context['primary_issue']
+
+
+enhanced_title=title
+ifnotany(keyintitleforkeyinissue_keys):
+key=primary['key']
+
+enhanced_title=f"{key}:{title}"
+
+
+enhanced_description=description
+
+
+business_section="\n\n##BusinessContext\n\n"
+business_section+=f"**Issue**:[{primary['key']}]({primary['url']})-{primary['summary']}\n"
+business_section+=f"**Type**:{primary['type']}\n"
+business_section+=f"**Status**:{primary['status']}\n"
+business_section+=f"**Priority**:{primary['priority']}\n"
+
+if'sprint'inprimary:
+business_section+=f"**Sprint**:{primary['sprint']}\n"
+
+if'acceptance_criteria'inprimary:
+business_section+=f"\n**AcceptanceCriteria**:\n{primary['acceptance_criteria']}\n"
+
+ifprimary.get('description'):
+
+desc=primary['description']
+iflen(desc)>300:
+desc=desc[:300]+"..."
+business_section+=f"\n**IssueDescription**:\n{desc}\n"
+
+
+ifprimary.get('comments'):
+tech_section="\n##TechnicalNotes\n\n"
+
+
+forcommentinprimary['comments']:
+iflen(comment)>200:
+comment=comment[:200]+"..."
+tech_section+=f"-{comment}\n\n"
+
+iflen(tech_section)>50:
+enhanced_description+=business_section+tech_section
+else:
+enhanced_description+=business_section
+else:
+enhanced_description+=business_section
+
+
+ifcontext.get('related_issues'):
+related_section="\n##RelatedIssues\n\n"
+forissueincontext['related_issues']:
+related_section+=f"-[{issue['key']}]({issue['url']}):{issue['summary']}({issue['status']})\n"
+
+enhanced_description+=related_section
+
+returnenhanced_title,enhanced_description
+
+
+
+
diff --git a/docs343/xml/llm__client_8py.xml b/docs343/xml/llm__client_8py.xml
new file mode 100644
index 0000000..e41b329
--- /dev/null
+++ b/docs343/xml/llm__client_8py.xml
@@ -0,0 +1,192 @@
+
+
+
+ llm_client.py
+ penify_hook::llm_client::LLMClient
+ penify_hook
+ penify_hook::llm_client
+
+
+
+
+
+importjson
+importos
+importsys
+fromtypingimportDict,Optional,List,Any,Union
+importtime
+
+
+
+
+class[LLMClient]:
+"""
+ClientforinteractingwithLLMmodelsusingLiteLLM.
+"""
+
+def[__init__](self,model:str=None,api_base:str=None,api_key:str=None):
+"""
+InitializetheLLMclient.
+
+Args:
+model:LLMmodeltouse(e.g.,"gpt-4","ollama/llama2",etc.)
+api_base:BaseURLforAPIrequests(e.g.,"http://localhost:11434"forOllama)
+api_key:APIkeyfortheLLMservice
+"""
+
+self.[model]=model
+ifapi_base:
+os.environ["OPENAI_API_BASE"]=api_base
+ifapi_key:
+os.environ["OPENAI_API_KEY"]=api_key
+self.[_litellm]=None
+
+@property
+def[litellm](self):
+"""Lazyloadlitellmonlywhenneeded."""
+ifself.[_litellm]isNone:
+importlitellm
+self.[_litellm]=litellm
+returnself.[_litellm]
+
+def[generate_commit_summary](self,diff:str,message:str,generate_description:bool,repo_details:Dict,jira_context:Dict=None)->Dict:
+"""GenerateacommitsummaryusingtheLLM.
+
+Thisfunctiongeneratesaconciseanddescriptivecommitsummarybased
+ontheprovidedGitdiff,userinstructions,repositorydetails,and
+optionalJIRAcontext.ItconstructsapromptfortheLLMtoproducea
+committitleandanoptionaldetaileddescription,adheringtoSemantic
+CommitMessagesguidelines.IftheJIRAcontextisprovided,itenriches
+thepromptwithrelevantissueinformation.
+
+Args:
+diff(str):Gitdiffofchanges.
+message(str):User-providedcommitmessageorinstructions.
+generate_description(bool):Flagindicatingwhethertoincludeadetaileddescriptioninthe
+summary.
+repo_details(Dict):Detailsabouttherepository.
+jira_context(Dict?):OptionalJIRAissuecontexttoenhancethesummary.
+
+Returns:
+Dict:Adictionarycontainingthetitleanddescriptionforthecommit.If
+generate_descriptionisFalse,
+the'description'keymaybeabsent.
+
+Raises:
+ValueError:IftheLLMmodelisnotconfigured.
+"""
+ifnotself.[model]:
+raiseValueError("LLMmodelnotconfigured.PleaseprovideamodelwheninitializingLLMClient.")
+
+
+max_diff_chars=10000
+iflen(diff)>max_diff_chars:
+diff=diff[:max_diff_chars]+f"\n...(difftruncated,total{len(diff)}characters)"
+
+
+prompt=f"""
+BasedontheGitdiffbelow,generateaconciseanddescriptivecommitsummary.
+
+Userinstructions:{message}
+"""
+
+
+ifjira_contextandjira_context.get('primary_issue'):
+primary=jira_context['primary_issue']
+prompt+=f"""
+
+JIRAISSUEINFORMATION:
+IssueKey:{primary['key']}
+Summary:{primary['summary']}
+Type:{primary['type']}
+Status:{primary['status']}
+"""
+
+if'description'inprimaryandprimary['description']:
+
+description=primary['description']
+iflen(description)>500:
+description=description[:500]+"..."
+prompt+=f"Description:{description}\n"
+
+if'acceptance_criteria'inprimary:
+prompt+=f"AcceptanceCriteria:{primary['acceptance_criteria']}\n"
+
+prompt+="""
+
+PleasemakesureyourcommitmessageaddressesthebusinessrequirementsintheJIRAissue
+whileaccuratelydescribingthetechnicalchangesinthediff.
+"""
+
+prompt+=f"""
+
+Gitdiff:
+```
+{diff}
+```
+
+Pleaseprovide:
+1.Ashort,focusedcommittitle(50-72characters)inaSemanticCommitMessagesformat.Format:<type>(<scope>):<subject>
+{'2.Adetaileddescriptionthatexplainswhatwaschanged,whyitwaschangedinbothbusinessandtechnicalaspects,andanyimportantcontext'ifgenerate_descriptionelse''}
+
+ListofSemanticCommitMessagetypesthatyoucanuse:
+feat:(newfeaturefortheuser,notanewfeatureforbuildscript)
+fix:(bugfixfortheuser,notafixtoabuildscript)
+docs:(changestothedocumentation)
+style:(formatting,missingsemicolons,etc;noproductioncodechange)
+refactor:(refactoringproductioncode,eg.renamingavariable)
+test:(addingmissingtests,refactoringtests;noproductioncodechange)
+chore:(updatinggrunttasksetc;noproductioncodechange)
+
+FormatyourresponseasvalidJSONwith'title'{"and'description'"ifgenerate_descriptionelse''}keys.
+"""
+
+try:
+
+response=self.[litellm].completion(
+model=self.[model],
+messages=[{"role":"user","content":prompt}],
+temperature=0.2,
+max_tokens=800
+)
+content=response.choices[0].message.content
+
+
+try:
+
+result=json.loads(content)
+ifnotisinstance(result,dict)or'title'notinresultor'description'notinresult:
+raiseValueError("InvalidJSONstructure")
+
+exceptjson.JSONDecodeError:
+
+importre
+json_match=re.search(r'```json\s*(.*?)\s*```',content,re.DOTALL)
+ifjson_match:
+result=json.loads(json_match.group(1))
+else:
+
+lines=content.split('\n')
+title=next((lineforlineinlinesifline.strip()),"Generatedcommit").strip()
+description="\n".join(lineforlineinlines[1:]ifline.strip())
+result={
+"title":title,
+"description":description
+}
+
+ifnotgenerate_descriptionand'description'inresult:
+
+delresult['description']
+returnresult
+
+exceptExceptionase:
+sys.exit(f"Errorgeneratingcommitsummary:{e}")
+
+print(f"ErrorgeneratingcommitsummarywithLLM:{e}")
+return{
+"title":"Updatecode",
+}
+
+
+
+
diff --git a/docs343/xml/login__command_8py.xml b/docs343/xml/login__command_8py.xml
new file mode 100644
index 0000000..c498a49
--- /dev/null
+++ b/docs343/xml/login__command_8py.xml
@@ -0,0 +1,40 @@
+
+
+
+ login_command.py
+ penify_hook
+ penify_hook::login_command
+
+
+
+
+
+def[setup_login_parser](parser):
+parser.add_argument("--token",help="SpecifyAPItokendirectly")
+
+
+def[handle_login](args):
+"""Handlethelogincommand.
+
+Initiatesauserloginprocessbycallingthe`login`functionfromthe
+`[penify_hook.commands.auth_commands]`moduleusingpredefinedconstants
+`API_URL`and`DASHBOARD_URL`fromthe`[penify_hook.constants]`module.
+
+Args:
+args(argparse.Namespace):Parsedargumentscontainingnecessaryparametersforthelogincommand.
+
+Returns:
+None:Thisfunctiondoesnotreturnanyvalue;itisexpectedtohandlethe
+loginprocessinternally.
+"""
+
+from[penify_hook.constants]importAPI_URL,DASHBOARD_URL
+from[penify_hook.commands.auth_commands]importlogin
+
+
+
+return[login](API_URL,DASHBOARD_URL)
+
+
+
+
diff --git a/docs343/xml/main_8py.xml b/docs343/xml/main_8py.xml
new file mode 100644
index 0000000..83db594
--- /dev/null
+++ b/docs343/xml/main_8py.xml
@@ -0,0 +1,104 @@
+
+
+
+ main.py
+ penify_hook
+ penify_hook::main
+
+
+
+
+
+importargparse
+importsys
+importtime
+
+
+def[main]():
+"""Mainfunctiontohandlecommand-lineinterface(CLI)interactionswith
+Penifyservices.
+
+Thistoolprovidesacommand-lineinterfaceforgeneratingsmartcommit
+messages,configuringlocal-LLMandJIRA,andgeneratingcode
+documentation.Itsupportsbasiccommandsthatdonotrequireloginand
+advancedcommandsthatrequireuserauthentication.The`--version`flag
+canbeusedtodisplaytheversioninformation.
+
+Returns:
+int:Exitstatusoftheprogram(0forsuccess,1forerror).
+"""
+
+parser=argparse.ArgumentParser(
+description="""PenifyCLItoolfor:
+1.AIcommitmessagegenerationwithJIRAintegrationtoenhancecommitmessages.
+2.GeneratingCodeDocumentation,itrequiresSignUptoPenify
+3.Formoreinformation,visithttps://penify.wiki/dpc1""",
+formatter_class=argparse.RawDescriptionHelpFormatter
+)
+
+
+parser.add_argument('--version','-v',action='store_true',help='Showversioninformation')
+
+subparsers=parser.add_subparsers(title="options",dest="subcommands")
+
+
+basic_title="BasicCommands(Nologinrequired)"
+advanced_title="AdvancedCommands(Loginrequired)"
+
+
+parser.add_argument_group(basic_title)
+parser.add_argument_group(advanced_title)
+
+
+commit_parser=subparsers.add_parser("commit",help="Generatesmartcommitmessagesusinglocal-LLM(nologinrequired).")
+from.commands.commit_commandsimportsetup_commit_parser
+[setup_commit_parser](commit_parser)
+
+config_parser=subparsers.add_parser("config",help="Configurelocal-LLMandJIRA.")
+from.config_commandimportsetup_config_parser
+[setup_config_parser](config_parser)
+
+login_parser=subparsers.add_parser("login",help="LogintoPenifytouseadvancedfeatureslike'docgen'generation.")
+from.login_commandimportsetup_login_parser
+[setup_login_parser](login_parser)
+
+docgen_parser=subparsers.add_parser("docgen",help="[REQUIRESLOGIN]GeneratecodedocumentationfortheGitdiff,fileorfolder.")
+from.commands.doc_commandsimportsetup_docgen_parser
+[setup_docgen_parser](docgen_parser)
+
+
+if'--version'insys.argvor'-v'insys.argv:
+fromimportlib.metadataimportversion
+try:
+print(f"penifyversion{version('penify')}")
+except:
+print("penifyversion0.2.2")
+return0
+
+
+args=parser.parse_args()
+
+ifargs.subcommands=="commit":
+from[penify_hook.ui_utils]importprint_info
+[print_info]("Pleasewaitwhilewegeneratethecommitmessage...")
+from.commands.commit_commandsimporthandle_commit
+return[handle_commit](args)
+elifargs.subcommands=="config":
+from.config_commandimporthandle_config
+return[handle_config](args)
+elifargs.subcommands=="login":
+from.login_commandimporthandle_login
+return[handle_login](args)
+elifargs.subcommands=="docgen":
+from.commands.doc_commandsimporthandle_docgen
+return[handle_docgen](args)
+else:
+parser.print_help()
+return1
+
+if__name__=="__main__":
+sys.exit([main]())
+
+
+
+
diff --git a/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_README.xml b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_README.xml
new file mode 100644
index 0000000..3f93092
--- /dev/null
+++ b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_README.xml
@@ -0,0 +1,163 @@
+
+
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_README
+ Penify CLI Tool
+
+
+
+
+
+
+A CLI tool to generate smart commit messages, code documentation, and more.
+
+Features
+
+Automatically generate documentation for your code
+Support for multiple programming languages
+Git hook integration for automatic documentation on commits
+Folder and file analysis
+
+
+
+
+Installation
+Install from PyPI:
+pipinstallpenify
+
+
+
+Usage
+Penify CLI provides several subcommands for different functionalities, organized into basic commands (no login required) and advanced commands (login required).
+
+
+Basic Commands (No login required)
+
+Commit
+Generate smart commit messages using local LLM:
+penifycommit[-m"Optionalmessage"][-e][-d]
+
+Options:
+-m, --message: Optional custom commit message
+-e, --terminal: Open editor to modify commit message before committing
+-d, --description: Generate commit message with both title and description (without this flag, only title is generated)
+
+
+
+
+Config
+Configure local LLM and JIRA settings:
+#ConfigureLLMsettings
+penifyconfigllm--modelMODEL_NAME[--api-baseAPI_URL][--api-keyAPI_KEY]
+
+#ConfigureLLMsettingsthroughwebinterface
+penifyconfigllm-web
+
+#ConfigureJIRAsettings
+penifyconfigjira--urlJIRA_URL--usernameUSERNAME--api-tokenTOKEN[--verify]
+
+#ConfigureJIRAsettingsthroughwebinterface
+penifyconfigjira-web
+
+
+
+
+Advanced Commands (Login required)
+
+Login
+To log in and obtain an API token:
+penifylogin
+
+This command will open a browser window for authentication. After successful login, the API key will be saved locally for future use.
+
+
+Documentation Generation
+Generate documentation for Git diff, files or folders:
+#GeneratedocumentationforlatestGitcommitdiff
+penifydocgen
+
+#Generatedocumentationforspecificfileorfolder
+penifydocgen-l/path/to/file/or/folder
+
+Options:
+-l, --location: Path to specific file or folder for documentation generation (defaults to current directory)
+
+
+
+
+Git Hook Management
+Install or uninstall Git post-commit hooks:
+#InstallGithook
+penifydocgeninstall-hook[-l/path/to/repo]
+
+#UninstallGithook
+penifydocgenuninstall-hook[-l/path/to/repo]
+
+Options:
+-l, --location: Path to the Git repository (defaults to current directory)
+
+
+
+
+
+Authentication
+Penify CLI uses an API token for authentication with advanced features.
+If no token is available and you try to access an advanced feature, you'll be prompted to log in.
+
+
+Local LLM Configuration
+For commit message generation, Penify can use a local LLM. Configure it using:
+penifyconfigllm--modelMODEL_NAME--api-baseAPI_URL--api-keyAPI_KEY
+
+Common configurations:
+OpenAI: --model gpt-3.5-turbo --api-base https://api.openai.com/v1 --api-key YOUR_KEY
+Anthropic: --model claude-2 --api-base https://api.anthropic.com --api-key YOUR_KEY
+
+
+
+
+JIRA Integration
+Configure JIRA integration to enhance commit messages with issue details:
+penifyconfigjira--urlhttps://your-domain.atlassian.net--usernameyour-email@example.com--api-tokenYOUR_API_TOKEN
+
+
+
+Development
+To set up the development environment:
+
+Clone the repository: gitclonehttps://github.com/SingularityX-ai/penify-cli.git
+
+Install the package in editable mode: pipinstall-e.
+
+
+
+
+Running Tests
+pytest
+
+
+
+
+License
+This project is licensed under the MIT License.
+
+
+Author
+Suman Saurabh (ss.sumansaurabh92@gmail.com)
+
+
+Contributing
+Contributions are welcome! Please feel free to submit a Pull Request.
+
+
+Issues
+If you encounter any problems or have suggestions, please file an issue on the GitHub repository.
+
+
+Support
+For automated API Documentation, Architecture Documentation, Code Documentation, Pull Request Documentation, or if you need a demo, please join our Discord support channel.
+
+
+
+
+
diff --git a/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_commit_commands.xml b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_commit_commands.xml
new file mode 100644
index 0000000..ddb149f
--- /dev/null
+++ b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_commit_commands.xml
@@ -0,0 +1,172 @@
+
+
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_commit_commands
+ Penify CLI - Commit Commands
+
+
+
+The commit command allows you to generate smart, AI-powered commit messages for your Git changes. This document explains all available options and combinations.
+
+Basic Usage
+penifycommit
+
+By default, this command:
+Analyzes your staged Git changes
+Generates a concise commit title only
+Uses local LLM if configured, or falls back to Penify API
+
+
+
+
+Command Options
+
+<tt>-m, --message</tt>
+Provide context for the commit message generation:
+penifycommit-m"Fixloginflow"
+
+This hint helps the AI understand your intention and improves the quality of the generated message.
+
+
+<tt>-e, --terminal</tt>
+Open an editor to review and edit the generated commit message before committing:
+penifycommit-e
+
+This opens your default Git editor with the generated message for review.
+
+
+<tt>-d, --description</tt>
+Generate a detailed commit message with both title and description:
+penifycommit-d
+
+Without this flag, only the commit title is generated.
+
+
+
+Option Combinations
+You can combine these options for different workflows:
+
+Generate Title Only with Context
+penifycommit-m"UpdateloginUI"
+
+
+
+Generate Title and Description with Context
+penifycommit-m"UpdateloginUI"-d
+
+
+
+Generate and Edit Full Commit Message
+penifycommit-d-e
+
+
+
+Generate, Edit, and Provide Context
+penifycommit-m"Refactorauthentication"-d-e
+
+
+
+
+LLM and JIRA Integration
+
+Using Local LLM
+If you've configured a local LLM using penify config llm, the commit command will automatically use it for message generation.
+Benefits:
+Privacy: your code changes don't leave your machine
+Speed: no network latency
+Works offline
+
+
+
+
+JIRA Enhancement
+If you've configured JIRA integration using penify config jira, the commit command will:
+
+Detect JIRA issue references in your changes
+Fetch issue details from your JIRA instance
+Include issue information in the commit message
+Format the commit message according to JIRA's smart commit format
+
+
+Example output: PROJ-123:Fixauthenticationbuginloginflow
+
+-UpdatedOAuthtokenvalidation
+-Fixedsessiontimeouthandling
+-Addedunittestsforedgecases
+
+[PROJ-123]
+
+
+
+
+Configuration Requirements
+For the commit command to work:
+
+You must have configured either:
+Local LLM via penify config llm, OR
+Logged in via penify login
+
+
+For JIRA enhancement (optional):
+Configure JIRA via penify config jira
+
+
+
+
+
+
+Examples
+
+Basic Commit with Default Settings
+#Stageyourchanges
+gitadd.
+
+#Generatecommitmessage
+penifycommit
+
+#Commitwiththegeneratedmessage
+gitcommit-m"Generatedmessagehere"
+
+
+
+Full Workflow with All Features
+#Stageyourchanges
+gitadd.
+
+#GeneratedetailedcommitmessagewithJIRAintegration,
+#providecontext,andopeneditorforreview
+penifycommit-m"Fixloginissue"-d-e
+
+#Thecommitisautomaticallycompletedafteryousaveandexittheeditor
+
+
+
+
+Troubleshooting
+
+Common Issues
+
+**"No LLM model or API token provided"**
+Run penify config llm to configure a local LLM, or
+Run penify login to authenticate with Penify
+
+
+**"Failed to connect to JIRA"**
+Check your JIRA configuration with cat ~/.penify
+Verify your network connection
+Ensure your JIRA credentials are valid
+
+
+**"Error initializing LLM client"**
+Verify your LLM configuration settings
+Ensure the LLM API is accessible
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_config_commands.xml b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_config_commands.xml
new file mode 100644
index 0000000..6606065
--- /dev/null
+++ b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_config_commands.xml
@@ -0,0 +1,205 @@
+
+
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_config_commands
+ Penify CLI - Configuration Commands
+
+
+
+The config command allows you to set up and manage configuration settings for Penify CLI. This document explains all available configuration options and how to use them.
+
+Configuration Overview
+Penify CLI stores configuration in a JSON file at ~/.penify/config.json. The configuration includes:
+
+LLM (Large Language Model) settings for local commit message generation
+JIRA integration settings for enhanced commit messages
+API tokens and other credentials
+
+
+
+
+Basic Usage
+#ConfigureLLMsettings
+penifyconfigllm
+
+#ConfigureJIRAintegration
+penifyconfigjira
+
+
+
+LLM Configuration
+
+Web Interface
+Running penify config llm opens a web interface in your browser where you can configure:
+
+Model: The LLM model to use (e.g., gpt-3.5-turbo)
+API Base URL: The endpoint URL for your LLM API (e.g., https://api.openai.com/v1)
+API Key: Your authentication key for the LLM API
+
+
+
+
+Supported LLMs
+Penify CLI supports various LLM providers:
+
+OpenAI
+
+Model: gpt-3.5-turbo or gpt-4
+API Base: https://api.openai.com/v1
+API Key: Your OpenAI API key
+
+
+
+
+Anthropic
+
+Model: claude-instant-1 or claude-2
+API Base: https://api.anthropic.com/v1
+API Key: Your Anthropic API key
+
+
+
+
+Ollama (Local)
+
+Model: llama2 or any model you have installed
+API Base: http://localhost:11434
+API Key: (leave blank)
+
+
+
+
+Azure OpenAI
+
+Model: Your deployed model name
+API Base: Your Azure endpoint
+API Key: Your Azure API key
+
+
+
+
+
+Configuration File Structure
+After configuration, your ~/.penify/config.json will contain:
+{
+"llm":{
+"model":"gpt-3.5-turbo",
+"api_base":"https://api.openai.com/v1",
+"api_key":"sk-..."
+}
+}
+
+
+
+
+JIRA Configuration
+
+Web Interface
+Running penify config jira opens a web interface where you can configure:
+
+JIRA URL: Your JIRA instance URL (e.g., https://yourcompany.atlassian.net)
+Username: Your JIRA username (typically your email)
+API Token: Your JIRA API token
+
+
+
+
+Creating a JIRA API Token
+
+Log in to https://id.atlassian.com/manage-profile/security/api-tokens
+Click "Create API token"
+Give it a name (e.g., "Penify CLI")
+Copy the generated token and paste it into the configuration
+
+
+
+
+Configuration File Structure
+After configuration, your ~/.penify/config.json will contain:
+{
+"jira":{
+"url":"https://yourcompany.atlassian.net",
+"username":"your.email@example.com",
+"api_token":"your-jira-api-token"
+}
+}
+
+
+
+
+Configuration Locations
+Penify CLI looks for configuration in multiple locations:
+
+Project-specific: .penify/config.json in the Git repository root
+User-specific: ~/.penify/config.json in your home directory
+
+
+The project-specific configuration takes precedence if both exist.
+
+
+Environment Variables
+You can override configuration settings using environment variables:
+
+PENIFY_API_TOKEN: Override the stored API token
+PENIFY_LLM_MODEL: Override the configured LLM model
+PENIFY_LLM_API_BASE: Override the configured LLM API base URL
+PENIFY_LLM_API_KEY: Override the configured LLM API key
+PENIFY_JIRA_URL: Override the configured JIRA URL
+PENIFY_JIRA_USER: Override the configured JIRA username
+PENIFY_JIRA_TOKEN: Override the configured JIRA API token
+
+
+Example: exportPENIFY_LLM_MODEL="gpt-4"
+penifycommit
+
+
+
+Command-Line Configuration
+For advanced users or scripting, you can directly edit the configuration file:
+#Viewcurrentconfiguration
+cat~/.penify/config.json
+
+#Editconfigurationwithyourpreferrededitor
+nano~/.penify/config.json
+
+
+
+Sharing Configuration
+You can share configuration between machines by copying the .penify/config.json file. However, be cautious with API keys and credentials.
+For team settings, consider:
+Using a project-specific .penify/config.json with shared settings
+Excluding API keys from shared configuration
+Using environment variables for sensitive credentials
+
+
+
+
+Troubleshooting
+
+Common Issues
+
+**"Error reading configuration file"**
+Check if the file exists: ls -la ~/.penify
+Ensure it contains valid JSON: cat ~/.penify/config.json
+
+
+**"Failed to connect to LLM API"**
+Verify API base URL and API key
+Check network connectivity to the API endpoint
+Ensure your account has access to the specified model
+
+
+**"Failed to connect to JIRA"**
+Check JIRA URL format (should include https://)
+Verify username and API token
+Ensure your JIRA account has API access permissions
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_detailed_usage.xml b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_detailed_usage.xml
new file mode 100644
index 0000000..e1fa5b4
--- /dev/null
+++ b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_detailed_usage.xml
@@ -0,0 +1,197 @@
+
+
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_detailed_usage
+ Penify CLI - Detailed Usage Guide
+
+
+
+This document provides in-depth information about all features and capabilities of the Penify CLI tool.
+
+Table of Contents
+
+Penify CLI - Detailed Usage Guide
+Table of Contents
+Authentication
+Login Process
+API Token Storage
+Token Precedence
+
+
+Command Overview
+Commit Message Generation
+Code Documentation Generation
+Use Cases
+Authentication Requirement
+
+
+Configuration Settings
+Git Hooks
+Post-Commit Hook
+Custom Hook Location
+
+
+Advanced Use Cases
+CI/CD Integration
+Remote Repository Documentation
+
+
+Troubleshooting
+Common Issues
+Logs
+Support
+
+
+
+
+
+
+
+
+Authentication
+
+Login Process
+When you run penify login, the tool:
+
+Opens your default web browser
+Redirects you to Penify's login page
+Captures the authentication token after successful login
+Saves the token in ~/.penify file
+
+
+
+
+API Token Storage
+API tokens are stored in your home directory in the .penify file. This JSON file contains:
+{
+"api_keys":"your-api-token",
+"llm":{"model":"...","api_base":"...","api_key":"..."},
+"jira":{"url":"...","username":"...","api_token":"..."}
+}
+
+
+
+Token Precedence
+
+Environment variable PENIFY_API_TOKEN (highest priority)
+Token in ~/.penify file
+
+
+
+
+
+Command Overview
+penify
+├──commitGeneratesmartcommitmessages
+├──configConfigurelocalLLMandJIRA
+│├──llmConfigurelocalLLMsettings
+│└──jiraConfigureJIRAintegration
+├──loginLogintoPenifyaccount
+└──docgenGeneratecodedocumentation
+├──install-hookInstallGitpost-commithook
+└──uninstall-hookRemoveGitpost-commithook
+
+
+
+Commit Message Generation
+The commit command analyzes your staged changes and generates meaningful commit messages. It can:
+
+Use a local LLM if configured
+Enhance messages with JIRA issue details
+Provide both title and description
+
+
+For specific options and examples, see [docs/commit-commands.md].
+
+
+Code Documentation Generation
+The docgen command generates documentation for your code:
+
+Use Cases
+
+Current Git Diff: Default behavior, documents only changed files
+Specific File: Pass a file path with -l path/to/file.py
+Entire Folder: Pass a folder path with -l path/to/folder
+
+
+
+
+Authentication Requirement
+This feature requires authentication with a Penify account. Run penify login before using documentation features.
+
+
+
+Configuration Settings
+Configure local settings using the config command:
+
+LLM Settings: Configure a local LLM for commit message generation
+JIRA Settings: Set up JIRA integration for enhanced commit messages
+
+
+For detailed configuration options, see [docs/config-commands.md].
+
+
+Git Hooks
+Penify can install Git hooks to automate documentation generation:
+
+Post-Commit Hook
+
+Install: penify docgen install-hook
+What it does: Automatically generates documentation for changed files after each commit
+Uninstall: penify docgen uninstall-hook
+
+
+
+
+Custom Hook Location
+You can specify a custom location for Git hooks:
+penifydocgeninstall-hook-l/path/to/git/repo
+
+
+
+
+Advanced Use Cases
+
+CI/CD Integration
+For CI/CD pipelines:
+
+Set PENIFY_API_TOKEN as an environment variable
+Run commands without requiring interactive login
+
+
+
+
+Remote Repository Documentation
+Generate documentation for an entire repository:
+gitclonehttps://github.com/user/repo
+cdrepo
+penifydocgen-l.
+
+
+
+
+Troubleshooting
+
+Common Issues
+
+API Key Errors: Ensure you've run penify login or set PENIFY_API_TOKEN
+LLM Configuration: Check your LLM settings with cat ~/.penify
+JIRA Integration: Verify JIRA credentials in your configuration
+
+
+
+
+Logs
+For more detailed logs, you can set the environment variable:
+exportPENIFY_DEBUG=1
+
+
+
+Support
+For additional help, visit https://docs.penify.dev/ or contact support@penify.dev
+
+
+
+
+
+
diff --git a/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_doc_commands.xml b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_doc_commands.xml
new file mode 100644
index 0000000..7107276
--- /dev/null
+++ b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_doc_commands.xml
@@ -0,0 +1,317 @@
+
+
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_doc_commands
+ Penify CLI - Documentation Generation Commands
+
+
+
+This document provides a detailed guide to all permutations and combinations of the docgen command, including extensive information about Git hook commands for automating documentation generation.
+
+Table of Contents
+
+Basic Usage
+Command Options
+Option Combinations
+Git Hook Commands
+Hook Installation
+Hook Customization
+Hook Uninstallation
+
+
+Advanced Use Cases
+Troubleshooting
+
+
+
+
+Basic Usage
+penifydocgen
+
+By default, this command:
+Analyzes the current Git diff (changes since last commit)
+Generates documentation for changed files only
+Requires authentication via penify login
+
+
+
+
+Command Options
+
+<tt>-l, --location</tt>
+Specify a target for documentation generation:
+#Generatedocumentationforaspecificfile
+penifydocgen-lpath/to/file.py
+
+#Generatedocumentationforaspecificfolder
+penifydocgen-lpath/to/folder
+
+Without this flag, Penify analyzes only Git-tracked modified files.
+
+
+Subcommands
+
+<tt>install-hook</tt>
+Install a Git post-commit hook to automatically generate documentation:
+penifydocgeninstall-hook
+
+
+
+<tt>uninstall-hook</tt>
+Remove the Git post-commit hook:
+penifydocgenuninstall-hook
+
+
+
+
+
+Option Combinations
+
+Generate Documentation for Current Git Diff
+#Basicusage-currentGitdiff
+penifydocgen
+
+
+
+Generate Documentation for a Specific File
+#Singlefiledocumentation
+penifydocgen-lsrc/main.py
+
+
+
+Generate Documentation for a Folder
+#Folderdocumentation
+penifydocgen-lsrc/models/
+
+
+
+Install Hook in Current Repository
+#InstallhookincurrentGitrepository
+penifydocgeninstall-hook
+
+
+
+Install Hook in Specific Repository
+#InstallhookinaspecificGitrepository
+penifydocgeninstall-hook-l/path/to/repo
+
+
+
+Uninstall Hook from Current Repository
+#UninstallhookfromcurrentGitrepository
+penifydocgenuninstall-hook
+
+
+
+Uninstall Hook from Specific Repository
+#UninstallhookfromaspecificGitrepository
+penifydocgenuninstall-hook-l/path/to/repo
+
+
+
+
+Git Hook Commands
+Penify provides Git hook commands to automate documentation generation as part of your Git workflow.
+
+Hook Installation
+
+How Hooks Work
+When you install a Git hook with penify docgen install-hook, Penify:
+
+Creates a post-commit hook script in the .git/hooks directory
+Makes the script executable
+Configures the hook to run penify docgen after each commit
+
+
+
+
+Hook Script Content
+The generated post-commit hook contains:
+#!/bin/sh
+#Thisisapost-commithookgeneratedbypenify.
+#Automaticallygeneratesdocumentationforchangedfilesaftereachcommit.
+
+penifydocgen-gf/path/to/git/repository-tyour_api_token
+
+
+
+Installation Location
+By default, hooks are installed in the current Git repository. You can specify a different location:
+penifydocgeninstall-hook-l/path/to/repo
+
+
+
+Installation Requirements
+To install hooks, you need:
+A valid Penify API token (login first with penify login)
+Write permissions to the .git/hooks directory
+
+
+
+
+Verifying Installation
+After installation, you can verify that the hook is installed:
+cat.git/hooks/post-commit
+
+
+
+
+Hook Customization
+You can customize the post-commit hook after installation:
+
+Modifying Hook Behavior
+
+Edit the .git/hooks/post-commit file
+Add additional options to the penify docgen command
+Add other commands to run after commit
+
+
+Example of a customized hook:
+#!/bin/sh
+#Thisisapost-commithookgeneratedbypenify.
+#Automaticallygeneratesdocumentationforchangedfilesaftereachcommit.
+
+#Generatedocumentation
+penifydocgen-gf/path/to/git/repository-tyour_api_token
+
+#Additionalcustomcommands
+echo"Documentationgenerationcomplete!"
+
+
+
+Advanced Hook Scenarios
+Conditional Documentation Generation:
+#!/bin/sh
+#Onlygeneratedocumentationforcommitstothemainbranch
+BRANCH=$(gitrev-parse--abbrev-refHEAD)
+if["$BRANCH"="main"];then
+penifydocgen-gf/path/to/git/repository-tyour_api_token
+fi
+
+Documenting Specific Files/Folders:
+#!/bin/sh
+#OnlydocumentPythonfilesinthesrcdirectory
+penifydocgen-lsrc/-gf/path/to/git/repository-tyour_api_token
+
+
+
+
+Hook Uninstallation
+
+Standard Uninstallation
+To remove a hook from the current repository:
+penifydocgenuninstall-hook
+
+
+
+Specific Repository Uninstallation
+To remove a hook from a specific repository:
+penifydocgenuninstall-hook-l/path/to/repo
+
+
+
+Manual Hook Removal
+If needed, you can manually remove the hook:
+rm.git/hooks/post-commit
+
+
+
+Verifying Uninstallation
+Check that the hook was successfully removed:
+ls-la.git/hooks/post-commit#Shouldreturn"Nosuchfileordirectory"
+
+
+
+
+
+Advanced Use Cases
+
+Continuous Integration
+Run documentation generation in CI pipelines:
+#InyourCIscript
+exportPENIFY_API_TOKEN=your_api_token
+penifydocgen-lsrc/
+
+
+
+Batch Documentation
+Generate documentation for multiple repositories:
+#Bashscriptforbatchdocumentation
+forrepoinrepo1repo2repo3;do
+cd/path/to/$repo
+penifydocgen-l.
+done
+
+
+
+Custom Git Hook Integration
+Integrate with other Git hooks:
+#In.git/hooks/pre-push
+penifydocgen-lsrc/
+
+
+
+Documenting Release Tags
+Generate documentation when creating a release tag:
+#Documenteverythingwhencreatingatag
+gittag-av1.0.0
+penifydocgen-l.#Documententirecodebase
+gitcommit--amend-m"Releasev1.0.0withupdateddocumentation"
+
+
+
+
+Troubleshooting
+
+Common Issues
+
+**"Authentication required"**
+Run penify login before using documentation features
+Check your API token with cat ~/.penify
+
+
+**"Permission denied when installing hook"**
+Check Git repository permissions
+Try running with sudo (if appropriate for your environment)
+Ensure the .git/hooks directory exists
+
+
+**"Hook installed but not running"**
+Check if the hook is executable: ls -la .git/hooks/post-commit
+Make it executable if needed: chmod +x .git/hooks/post-commit
+Check for syntax errors in the hook script
+
+
+**"File or directory not found"**
+Verify the path provided to the -l option
+Ensure you're running the command from the correct directory
+
+
+**"Hook uninstallation failed"**
+Check permissions on the .git/hooks directory
+Try manual removal: rm .git/hooks/post-commit
+
+
+
+
+
+
+Debugging
+For detailed output when running documentation commands:
+exportPENIFY_DEBUG=1
+penifydocgen-lsrc/
+
+
+
+Getting Help
+For command-specific help:
+penifydocgen--help
+penifydocgeninstall-hook--help
+penifydocgenuninstall-hook--help
+
+
+
+
+
+
+
diff --git a/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_example_workflows.xml b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_example_workflows.xml
new file mode 100644
index 0000000..2e80f2e
--- /dev/null
+++ b/docs343/xml/md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_example_workflows.xml
@@ -0,0 +1,161 @@
+
+
+
+ md__tmp_github_reposRepoArchDocGenContext_Penify_dev_penify_cli_docs_example_workflows
+ Penify CLI Example Workflows
+
+
+
+This document demonstrates how to use Penify CLI in real-world development workflows to improve your productivity.
+
+Workflow 1: Efficient Git Commits with AI
+
+Setup
+First, configure your local LLM for offline operation:
+penifyconfigllm
+
+Configure your JIRA integration for enhanced commit messages:
+penifyconfigjira
+
+
+
+Daily Workflow
+
+Make your code changes as usual
+When ready to commit, use Penify to generate a smart commit message:
+
+
+penifycommit
+
+
+Review and confirm the generated commit message
+Git commit and push as usual
+
+
+
+
+Benefits
+
+Consistent and descriptive commit messages
+Automatic inclusion of relevant JIRA ticket information
+Time saved from writing detailed commit messages
+
+
+
+
+
+Workflow 2: Documentation Generation Pipeline
+
+Setup
+Login to Penify to access advanced documentation features:
+penifylogin
+
+Install the Git hook for automatic documentation generation:
+penifydocgeninstall-hook
+
+
+
+Daily Workflow
+
+Make your code changes as usual
+Commit your changes
+Documentation is automatically generated for changed files
+Review the generated documentation
+
+
+
+
+Manual Documentation
+For specific files or folders:
+penifydocgen-lsrc/components/authentication
+
+
+
+Benefits
+
+Always up-to-date documentation
+Consistent documentation style
+Time saved from writing detailed documentation
+
+
+
+
+
+Workflow 3: Code Review Enhancement
+
+Setup
+Ensure you're logged into Penify:
+penifylogin
+
+
+
+Workflow
+
+Before submitting a PR, generate documentation for changed files:
+
+
+penifydocgen
+
+
+Include the generated documentation in your PR
+Reviewers can better understand your changes with the AI-generated explanations
+
+
+
+
+Benefits
+
+Improved PR quality
+Faster code reviews
+Better team understanding of code changes
+
+
+
+
+
+Workflow 4: Onboarding New Team Members
+
+For Team Leads
+Generate comprehensive documentation for the entire codebase:
+penifydocgen-l.
+
+
+
+For New Team Members
+Generate focused documentation for components you're working on:
+penifydocgen-lsrc/components/my-feature
+
+
+
+Benefits
+
+Faster onboarding
+Better understanding of code structure
+Reduced questions to senior team members
+
+
+
+
+
+Workflow 5: Legacy Code Understanding
+When working with unfamiliar legacy code:
+#Documentaspecificcomplexfile
+penifydocgen-lsrc/legacy/complex_module.py
+
+#Documentanentirelegacycomponent
+penifydocgen-lsrc/legacy/old_component
+
+
+Benefits
+
+Quickly understand complex legacy systems
+Reduce time spent deciphering undocumented code
+Make safer changes to legacy systems
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook.xml b/docs343/xml/namespacepenify__hook.xml
new file mode 100644
index 0000000..2d5d9d8
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook.xml
@@ -0,0 +1,26 @@
+
+
+
+ penify_hook
+ penify_hook::api_client
+ penify_hook::base_analyzer
+ penify_hook::commands
+ penify_hook::commit_analyzer
+ penify_hook::config_command
+ penify_hook::constants
+ penify_hook::file_analyzer
+ penify_hook::folder_analyzer
+ penify_hook::git_analyzer
+ penify_hook::jira_client
+ penify_hook::llm_client
+ penify_hook::login_command
+ penify_hook::main
+ penify_hook::ui_utils
+ penify_hook::utils
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1api__client.xml b/docs343/xml/namespacepenify__hook_1_1api__client.xml
new file mode 100644
index 0000000..763c4c4
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1api__client.xml
@@ -0,0 +1,12 @@
+
+
+
+ penify_hook::api_client
+ penify_hook::api_client::APIClient
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1base__analyzer.xml b/docs343/xml/namespacepenify__hook_1_1base__analyzer.xml
new file mode 100644
index 0000000..82a8bc2
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1base__analyzer.xml
@@ -0,0 +1,12 @@
+
+
+
+ penify_hook::base_analyzer
+ penify_hook::base_analyzer::BaseAnalyzer
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commands.xml b/docs343/xml/namespacepenify__hook_1_1commands.xml
new file mode 100644
index 0000000..4abe35e
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commands.xml
@@ -0,0 +1,16 @@
+
+
+
+ penify_hook::commands
+ penify_hook::commands::auth_commands
+ penify_hook::commands::commit_commands
+ penify_hook::commands::config_commands
+ penify_hook::commands::doc_commands
+ penify_hook::commands::hook_commands
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commands_1_1auth__commands.xml b/docs343/xml/namespacepenify__hook_1_1commands_1_1auth__commands.xml
new file mode 100644
index 0000000..32d304a
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commands_1_1auth__commands.xml
@@ -0,0 +1,82 @@
+
+
+
+ penify_hook::commands::auth_commands
+
+
+ def
+ def penify_hook.commands.auth_commands.save_credentials
+ (api_key)
+ save_credentials
+ penify_hook.commands.auth_commands.save_credentials
+
+ api_key
+ api_key
+
+
+
+
+Save the token and API keys based on priority:
+1. .env file in Git repo root (if in a git repo)
+2. .penify file in home directory (global fallback)
+
+Args:
+ api_key: The API key to save
+
+Returns:
+ bool: True if saved successfully, False otherwise
+
+
+
+
+
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.auth_commands.login
+
+
+ def
+ def penify_hook.commands.auth_commands.login
+ (api_url, dashboard_url)
+ login
+ penify_hook.commands.auth_commands.login
+
+ api_url
+ api_url
+
+
+ dashboard_url
+ dashboard_url
+
+
+
+
+Open the login page in a web browser and listen for the redirect URL to
+capture the token.
+
+This function generates a random redirect port, constructs the full
+login URL with the provided dashboard URL, opens the login page in the
+default web browser, and sets up a simple HTTP server to listen for the
+redirect. Upon receiving the redirect, it extracts the token from the
+query parameters, fetches API keys using the token, saves them if
+successful, and handles login failures by notifying the user.
+
+Args:
+ api_url (str): The URL of the API service to fetch API keys.
+ dashboard_url (str): The URL of the dashboard where the user will be redirected after logging
+ in.
+
+
+
+
+
+ penify_hook.commands.auth_commands.save_credentials
+ penify_hook.login_command.handle_login
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commands_1_1commit__commands.xml b/docs343/xml/namespacepenify__hook_1_1commands_1_1commit__commands.xml
new file mode 100644
index 0000000..1179792
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commands_1_1commit__commands.xml
@@ -0,0 +1,176 @@
+
+
+
+ penify_hook::commands::commit_commands
+
+
+ def
+ def penify_hook.commands.commit_commands.commit_code
+ (api_url, token, message, open_terminal, generate_description, llm_model=None, llm_api_base=None, llm_api_key=None, jira_url=None, jira_user=None, jira_api_token=None)
+ commit_code
+ penify_hook.commands.commit_commands.commit_code
+
+ api_url
+ api_url
+
+
+ token
+ token
+
+
+ message
+ message
+
+
+ open_terminal
+ open_terminal
+
+
+ generate_description
+ generate_description
+
+
+ llm_model
+ llm_model
+ None
+
+
+ llm_api_base
+ llm_api_base
+ None
+
+
+ llm_api_key
+ llm_api_key
+ None
+
+
+ jira_url
+ jira_url
+ None
+
+
+ jira_user
+ jira_user
+ None
+
+
+ jira_api_token
+ jira_api_token
+ None
+
+
+
+
+Enhance Git commits with AI-powered commit messages.
+
+This function allows for the generation of enhanced commit messages
+using natural language processing models and optionally integrates with
+JIRA for additional context. It processes the current Git folder to find
+relevant files and generates a detailed commit message based on the
+provided parameters.
+
+Args:
+ api_url (str): URL of the API endpoint.
+ token (str): Authentication token for the API.
+ message (str): Initial commit message provided by the user.
+ open_terminal (bool): Whether to open the terminal after committing.
+ generate_description (bool): Whether to generate a detailed description in the commit message.
+ llm_model (str?): The language model to use for generating the commit message. Defaults to
+ None.
+ llm_api_base (str?): Base URL of the LLM API. Defaults to None.
+ llm_api_key (str?): API key for accessing the LLM service. Defaults to None.
+ jira_url (str?): URL of the JIRA instance. Defaults to None.
+ jira_user (str?): Username for authenticating with JIRA. Defaults to None.
+ jira_api_token (str?): API token for accessing JIRA. Defaults to None.
+
+
+
+
+
+ penify_hook.ui_utils.print_error
+ penify_hook.ui_utils.print_info
+ penify_hook.ui_utils.print_warning
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.commit_commands.handle_commit
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_error_handling
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_with_jira_client
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_with_jira_connection_failure
+ tests.test_commit_commands.TestCommitCommands.test_commit_code_with_llm_client
+
+
+ def
+ def penify_hook.commands.commit_commands.setup_commit_parser
+ (parser)
+ setup_commit_parser
+ penify_hook.commands.commit_commands.setup_commit_parser
+
+ parser
+ parser
+
+
+
+
+Generates a parser for setting up a command to generate smart commit
+messages.
+
+This function sets up an argument parser that can be used to generate
+commit messages with contextual information. It allows users to specify
+options such as including a message, opening an edit terminal before
+committing, and generating a detailed commit message.
+
+Args:
+ parser (argparse.ArgumentParser): The ArgumentParser object to be configured.
+
+
+
+
+
+ penify_hook.main.main
+ tests.test_commit_commands.TestCommitCommands.test_setup_commit_parser
+
+
+ def
+ def penify_hook.commands.commit_commands.handle_commit
+ (args)
+ handle_commit
+ penify_hook.commands.commit_commands.handle_commit
+
+ args
+ args
+
+
+
+
+Handle the commit functionality by processing arguments and invoking the
+appropriate commands.
+
+This function processes the provided command-line arguments to configure
+settings for commit operations, including LLM (Language Model) and Jira
+configurations. It then calls the `commit_code` function with these
+configurations to perform the actual commit operation.
+
+Args:
+ args (argparse.Namespace): The parsed command-line arguments containing options like terminal,
+ description, message, etc.
+
+
+
+
+
+ penify_hook.commands.commit_commands.commit_code
+ penify_hook.commands.config_commands.get_jira_config
+ penify_hook.commands.config_commands.get_llm_config
+ penify_hook.commands.config_commands.get_token
+ penify_hook.ui_utils.print_info
+ penify_hook.main.main
+ tests.test_commit_commands.TestCommitCommands.test_handle_commit
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commands_1_1config__commands.xml b/docs343/xml/namespacepenify__hook_1_1commands_1_1config__commands.xml
new file mode 100644
index 0000000..87c5934
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commands_1_1config__commands.xml
@@ -0,0 +1,349 @@
+
+
+
+ penify_hook::commands::config_commands
+
+
+ bool
+ bool penify_hook::commands::config_commands::DOTENV_AVAILABLE
+
+ DOTENV_AVAILABLE
+ penify_hook.commands.config_commands.DOTENV_AVAILABLE
+ = True
+
+
+
+
+
+
+
+
+
+
+ penify_hook::commands::config_commands.path
+
+ path
+ penify_hook.commands.config_commands.path
+
+
+
+
+
+
+
+
+
+
+
+ None
+ None penify_hook.commands.config_commands.load_env_files
+ ()
+ load_env_files
+ penify_hook.commands.config_commands.load_env_files
+
+
+
+Load environment variables from .env files in various locations,
+with proper priority (later files override earlier ones):
+1. User home directory .env (lowest priority)
+2. Git repo root directory .env (if in a git repo)
+3. Current directory .env (highest priority)
+
+This function is called when the module is imported, ensuring env variables
+are available throughout the application lifecycle.
+
+
+
+
+
+ penify_hook.commands.config_commands.load_env_files
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.config_commands.get_jira_config
+ penify_hook.commands.config_commands.get_llm_config
+ penify_hook.commands.config_commands.get_token
+ penify_hook.commands.config_commands.load_env_files
+
+
+ Path
+ Path penify_hook.commands.config_commands.get_penify_config
+ ()
+ get_penify_config
+ penify_hook.commands.config_commands.get_penify_config
+
+
+
+Get the home directory for the .penify configuration file.
+
+This function searches for the `.penify` file in the current directory
+and its parent directories until it finds it or reaches the home
+directory. If not found, it creates the `.penify` directory and an empty
+`config.json` file.
+
+Returns:
+ Path: The path to the `config.json` file within the `.penify` directory.
+
+
+
+
+
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.config_commands.get_token
+ tests.test_config_commands.TestConfigCommands.test_get_penify_config_existing_dir
+ tests.test_config_commands.TestConfigCommands.test_get_penify_config_new_dir
+
+
+ Any
+ Any penify_hook.commands.config_commands.get_env_var_or_default
+ (str env_var, Any default=None)
+ get_env_var_or_default
+ penify_hook.commands.config_commands.get_env_var_or_default
+
+ str
+ env_var
+
+
+ Any
+ default
+ None
+
+
+
+
+Get environment variable or return default value.
+
+Args:
+ env_var: The environment variable name
+ default: Default value if environment variable is not set
+
+Returns:
+ Value of the environment variable or default
+
+
+
+
+
+ penify_hook.commands.config_commands.get_jira_config
+ penify_hook.commands.config_commands.get_llm_config
+ penify_hook.commands.config_commands.get_token
+
+
+ def
+ def penify_hook.commands.config_commands.save_llm_config
+ (model, api_base, api_key)
+ save_llm_config
+ penify_hook.commands.config_commands.save_llm_config
+
+ model
+ model
+
+
+ api_base
+ api_base
+
+
+ api_key
+ api_key
+
+
+
+
+Save LLM configuration settings to .env file.
+
+This function saves LLM configuration in the following priority:
+1. Git repo root .env (if inside a git repo)
+2. User home directory .env
+
+
+
+
+
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.config_command.handle_config
+ tests.test_config_commands.TestConfigCommands.test_save_llm_config_failure
+ tests.test_config_commands.TestConfigCommands.test_save_llm_config_success
+
+
+ def
+ def penify_hook.commands.config_commands.save_jira_config
+ (url, username, api_token)
+ save_jira_config
+ penify_hook.commands.config_commands.save_jira_config
+
+ url
+ url
+
+
+ username
+ username
+
+
+ api_token
+ api_token
+
+
+
+
+Save JIRA configuration settings to .env file.
+
+This function saves JIRA configuration in the following priority:
+1. Git repo root .env (if inside a git repo)
+2. User home directory .env
+
+
+
+
+
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.config_commands.config_jira_web
+ penify_hook.config_command.handle_config
+ tests.test_config_commands.TestConfigCommands.test_save_jira_config_success
+
+
+ Dict[str, str]
+ Dict[str, str] penify_hook.commands.config_commands.get_llm_config
+ ()
+ get_llm_config
+ penify_hook.commands.config_commands.get_llm_config
+
+
+
+Get LLM configuration from environment variables.
+
+Environment variables:
+- PENIFY_LLM_MODEL: Model name
+- PENIFY_LLM_API_BASE: API base URL
+- PENIFY_LLM_API_KEY: API key
+
+Returns:
+ dict: Configuration dictionary with model, api_base, and api_key
+
+
+
+
+
+ penify_hook.commands.config_commands.get_env_var_or_default
+ penify_hook.commands.config_commands.load_env_files
+ penify_hook.commands.commit_commands.handle_commit
+ tests.test_config_commands.TestConfigCommands.test_get_llm_config_empty
+ tests.test_config_commands.TestConfigCommands.test_get_llm_config_exists
+ tests.test_config_commands.TestConfigCommands.test_get_llm_config_invalid_json
+
+
+ Dict[str, str]
+ Dict[str, str] penify_hook.commands.config_commands.get_jira_config
+ ()
+ get_jira_config
+ penify_hook.commands.config_commands.get_jira_config
+
+
+
+Get JIRA configuration from environment variables.
+
+Environment variables:
+- PENIFY_JIRA_URL: JIRA URL
+- PENIFY_JIRA_USER: JIRA username
+- PENIFY_JIRA_TOKEN: JIRA API token
+
+Returns:
+ dict: Configuration dictionary with url, username, and api_token
+
+
+
+
+
+ penify_hook.commands.config_commands.get_env_var_or_default
+ penify_hook.commands.config_commands.load_env_files
+ penify_hook.commands.config_commands.config_jira_web
+ penify_hook.commands.commit_commands.handle_commit
+ tests.test_config_commands.TestConfigCommands.test_get_jira_config_exists
+
+
+ def
+ def penify_hook.commands.config_commands.config_llm_web
+ ()
+ config_llm_web
+ penify_hook.commands.config_commands.config_llm_web
+
+
+
+Open a web browser interface for configuring LLM settings.
+
+This function starts a temporary HTTP server that serves an HTML
+template for configuring Large Language Model (LLM) settings. It handles
+GET and POST requests to retrieve the current configuration, save new
+configurations, and suppress log messages. The server runs on a random
+port between 30000 and 50000, and it is accessible via a URL like
+http://localhost:<redirect_port>. The function opens this URL in the
+default web browser for configuration. Once configured, the server shuts
+down.
+
+
+
+
+
+ penify_hook.config_command.handle_config
+ tests.test_web_config.TestWebConfig.test_config_llm_web_server_setup
+
+
+ def
+ def penify_hook.commands.config_commands.config_jira_web
+ ()
+ config_jira_web
+ penify_hook.commands.config_commands.config_jira_web
+
+
+
+Open a web browser interface for configuring JIRA settings.
+
+This function sets up a simple HTTP server using Python's built-in
+`http.server` module to handle GET and POST requests. The server serves
+an HTML page for configuration and handles saving the JIRA configuration
+details through API tokens and URLs. Upon successful configuration, it
+shuts down the server gracefully.
+
+
+
+
+
+ penify_hook.commands.config_commands.get_jira_config
+ penify_hook.commands.config_commands.save_jira_config
+ penify_hook.config_command.handle_config
+ tests.test_web_config.TestWebConfig.test_config_jira_web_server_setup
+
+
+ Optional[str]
+ Optional[str] penify_hook.commands.config_commands.get_token
+ ()
+ get_token
+ penify_hook.commands.config_commands.get_token
+
+
+
+Get the API token based on priority:
+1. Environment variable PENIFY_API_TOKEN from any .env file
+2. Config file 'api_keys' value
+
+Returns:
+ str or None: API token if found, None otherwise
+
+
+
+
+
+ penify_hook.commands.config_commands.get_env_var_or_default
+ penify_hook.commands.config_commands.get_penify_config
+ penify_hook.commands.config_commands.load_env_files
+ penify_hook.commands.commit_commands.handle_commit
+ penify_hook.commands.doc_commands.handle_docgen
+ tests.test_config_commands.TestConfigCommands.test_get_token_from_config
+ tests.test_config_commands.TestConfigCommands.test_get_token_from_env
+ tests.test_config_commands.TestConfigCommands.test_get_token_not_found
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commands_1_1doc__commands.xml b/docs343/xml/namespacepenify__hook_1_1commands_1_1doc__commands.xml
new file mode 100644
index 0000000..7fc41b1
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commands_1_1doc__commands.xml
@@ -0,0 +1,155 @@
+
+
+
+ penify_hook::commands::doc_commands
+
+
+ string
+ string penify_hook::commands::doc_commands.docgen_description
+
+ docgen_description
+ penify_hook.commands.doc_commands.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
+ def penify_hook.commands.doc_commands.generate_doc
+ (api_url, token, location=None)
+ generate_doc
+ penify_hook.commands.doc_commands.generate_doc
+
+ api_url
+ api_url
+
+
+ token
+ token
+
+
+ location
+ location
+ None
+
+
+
+
+Generates documentation based on the given parameters.
+
+This function initializes an API client using the provided API URL and
+token. It then generates documentation by analyzing the specified
+location, which can be a folder, a file, or the current working
+directory if no location is provided. The function handles different
+types of analysis based on the input location and reports any errors
+encountered during the process.
+
+Args:
+ api_url (str): The URL of the API to connect to for documentation generation.
+ token (str): The authentication token for accessing the API.
+ location (str?): The path to a specific file or folder to analyze. If not provided, the
+ current working directory is used.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+ tests.test_doc_commands.test_generate_doc_error_handling
+ tests.test_doc_commands.test_generate_doc_file_location
+ tests.test_doc_commands.test_generate_doc_folder_location
+ tests.test_doc_commands.test_generate_doc_no_location
+ tests.test_doc_commands.test_generate_doc_with_file_exception
+ tests.test_doc_commands.test_generate_doc_with_folder_exception
+
+
+ def
+ def penify_hook.commands.doc_commands.setup_docgen_parser
+ (parser)
+ setup_docgen_parser
+ penify_hook.commands.doc_commands.setup_docgen_parser
+
+ parser
+ parser
+
+
+
+
+Set up and configure a parser for documentation generation using Git
+commands.
+
+This function configures a parser with various subcommands and arguments
+necessary for generating documentation for Git diffs, files, or folders.
+It also installs and uninstalls commit hooks to automate documentation
+generation on commits.
+
+Args:
+ parser (argparse.ArgumentParser): The parser to configure.
+
+
+
+
+
+ penify_hook.main.main
+ tests.test_doc_commands.test_setup_docgen_parser
+
+
+ def
+ def penify_hook.commands.doc_commands.handle_docgen
+ (args)
+ handle_docgen
+ penify_hook.commands.doc_commands.handle_docgen
+
+ args
+ args
+
+
+
+
+Handle various subcommands related to document generation and hook
+management.
+
+This function processes different subcommands such as installing or
+uninstalling git hooks, and directly generating documentation based on
+provided arguments.
+
+Args:
+ args (Namespace): Parsed command-line arguments containing the subcommand and location
+ details.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+ penify_hook.commands.config_commands.get_token
+ penify_hook.commands.hook_commands.install_git_hook
+ penify_hook.commands.hook_commands.uninstall_git_hook
+ penify_hook.main.main
+ tests.test_doc_commands.test_handle_docgen_generate
+ tests.test_doc_commands.test_handle_docgen_install_hook
+ tests.test_doc_commands.test_handle_docgen_no_token
+ tests.test_doc_commands.test_handle_docgen_uninstall_hook
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commands_1_1hook__commands.xml b/docs343/xml/namespacepenify__hook_1_1commands_1_1hook__commands.xml
new file mode 100644
index 0000000..753b073
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commands_1_1hook__commands.xml
@@ -0,0 +1,111 @@
+
+
+
+ penify_hook::commands::hook_commands
+
+
+ string
+ string penify_hook::commands::hook_commands.HOOK_FILENAME
+
+ HOOK_FILENAME
+ penify_hook.commands.hook_commands.HOOK_FILENAME
+ = "post-commit"
+
+
+
+
+
+
+
+
+
+ string
+ string penify_hook::commands::hook_commands.HOOK_TEMPLATE
+
+ HOOK_TEMPLATE
+ penify_hook.commands.hook_commands.HOOK_TEMPLATE
+ = """#!/bin/sh
+# This is a post-commit hook generated by penify.
+# Automatically generates documentation for changed files after each commit.
+
+penify docgen -gf {git_folder_path} -t {token}
+"""
+
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.commands.hook_commands.install_git_hook
+ (location, token)
+ install_git_hook
+ penify_hook.commands.hook_commands.install_git_hook
+
+ location
+ location
+
+
+ token
+ token
+
+
+
+
+Install a post-commit hook in the specified location that generates
+documentation
+for changed files after each commit.
+
+Args:
+ location (str): The path to the Git repository where the hook should be installed.
+ token (str): The authentication token required to access the documentation generation
+ service.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+
+
+ def
+ def penify_hook.commands.hook_commands.uninstall_git_hook
+ (location)
+ uninstall_git_hook
+ penify_hook.commands.hook_commands.uninstall_git_hook
+
+ location
+ location
+
+
+
+
+Uninstalls the post-commit hook from the specified location.
+
+This function attempts to remove a post-commit git hook located at the
+given path. It constructs the path to the hook and checks if it exists.
+If the hook is found, it is deleted, and a confirmation message is
+printed. If no hook is found, a message indicating this is also printed.
+
+Args:
+ location (Path): The base directory where the .git/hooks directory is located.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1commit__analyzer.xml b/docs343/xml/namespacepenify__hook_1_1commit__analyzer.xml
new file mode 100644
index 0000000..34e3580
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1commit__analyzer.xml
@@ -0,0 +1,12 @@
+
+
+
+ penify_hook::commit_analyzer
+ penify_hook::commit_analyzer::CommitDocGenHook
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1config__command.xml b/docs343/xml/namespacepenify__hook_1_1config__command.xml
new file mode 100644
index 0000000..b54b356
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1config__command.xml
@@ -0,0 +1,78 @@
+
+
+
+ penify_hook::config_command
+
+
+ def
+ def penify_hook.config_command.setup_config_parser
+ (parent_parser)
+ setup_config_parser
+ penify_hook.config_command.setup_config_parser
+
+ parent_parser
+ parent_parser
+
+
+
+
+Set up a configuration parser with subparsers for different types of
+configurations.
+
+This function configures and adds subcommands to the parent parser. Each
+subcommand corresponds to a specific type of configuration, such as LLM
+(Language Model) or JIRA. It allows users to configure settings for
+these systems through command-line arguments.
+
+Args:
+ parent_parser (argparse.ArgumentParser): The parent parser to which the config subparsers will be added.
+
+
+
+
+
+ penify_hook.main.main
+
+
+ def
+ def penify_hook.config_command.handle_config
+ (args)
+ handle_config
+ penify_hook.config_command.handle_config
+
+ args
+ args
+
+
+
+
+Handle configuration settings based on the specified config type.
+
+This function processes different types of configurations such as LLM
+(Language Model) and JIRA. It saves configurations, sets up web-based
+configurations, and verifies JIRA connections.
+
+Args:
+ args (argparse.Namespace): Command-line arguments containing the type of configuration to handle.
+
+Returns:
+ int: Exit code indicating success or failure.
+
+
+
+
+
+ penify_hook.commands.config_commands.config_jira_web
+ penify_hook.commands.config_commands.config_llm_web
+ penify_hook.commands.config_commands.save_jira_config
+ penify_hook.commands.config_commands.save_llm_config
+ penify_hook.main.main
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1constants.xml b/docs343/xml/namespacepenify__hook_1_1constants.xml
new file mode 100644
index 0000000..1aafdc4
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1constants.xml
@@ -0,0 +1,43 @@
+
+
+
+ penify_hook::constants
+
+
+ string
+ string penify_hook::constants.API_URL
+
+ API_URL
+ penify_hook.constants.API_URL
+ = 'http://localhost:8000/api'
+
+
+
+
+
+
+
+
+
+ string
+ string penify_hook::constants.DASHBOARD_URL
+
+ DASHBOARD_URL
+ penify_hook.constants.DASHBOARD_URL
+ = "https://dashboard.penify.dev/auth/localhost/login"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1file__analyzer.xml b/docs343/xml/namespacepenify__hook_1_1file__analyzer.xml
new file mode 100644
index 0000000..1588f44
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1file__analyzer.xml
@@ -0,0 +1,29 @@
+
+
+
+ penify_hook::file_analyzer
+ penify_hook::file_analyzer::FileAnalyzerGenHook
+
+
+
+ penify_hook::file_analyzer.logger
+
+ logger
+ penify_hook.file_analyzer.logger
+ = logging.getLogger(__name__)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1folder__analyzer.xml b/docs343/xml/namespacepenify__hook_1_1folder__analyzer.xml
new file mode 100644
index 0000000..f75cafb
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1folder__analyzer.xml
@@ -0,0 +1,12 @@
+
+
+
+ penify_hook::folder_analyzer
+ penify_hook::folder_analyzer::FolderAnalyzerGenHook
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1git__analyzer.xml b/docs343/xml/namespacepenify__hook_1_1git__analyzer.xml
new file mode 100644
index 0000000..9b156cc
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1git__analyzer.xml
@@ -0,0 +1,29 @@
+
+
+
+ penify_hook::git_analyzer
+ penify_hook::git_analyzer::GitDocGenHook
+
+
+
+ penify_hook::git_analyzer.logger
+
+ logger
+ penify_hook.git_analyzer.logger
+ = logging.getLogger(__name__)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1jira__client.xml b/docs343/xml/namespacepenify__hook_1_1jira__client.xml
new file mode 100644
index 0000000..dbbe0fc
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1jira__client.xml
@@ -0,0 +1,29 @@
+
+
+
+ penify_hook::jira_client
+ penify_hook::jira_client::JiraClient
+
+
+ bool
+ bool penify_hook::jira_client::JIRA_AVAILABLE
+
+ JIRA_AVAILABLE
+ penify_hook.jira_client.JIRA_AVAILABLE
+ = True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1llm__client.xml b/docs343/xml/namespacepenify__hook_1_1llm__client.xml
new file mode 100644
index 0000000..5748cf6
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1llm__client.xml
@@ -0,0 +1,12 @@
+
+
+
+ penify_hook::llm_client
+ penify_hook::llm_client::LLMClient
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1login__command.xml b/docs343/xml/namespacepenify__hook_1_1login__command.xml
new file mode 100644
index 0000000..30045f3
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1login__command.xml
@@ -0,0 +1,65 @@
+
+
+
+ penify_hook::login_command
+
+
+ def
+ def penify_hook.login_command.setup_login_parser
+ (parser)
+ setup_login_parser
+ penify_hook.login_command.setup_login_parser
+
+ parser
+ parser
+
+
+
+
+
+
+
+
+ penify_hook.main.main
+
+
+ def
+ def penify_hook.login_command.handle_login
+ (args)
+ handle_login
+ penify_hook.login_command.handle_login
+
+ args
+ args
+
+
+
+
+Handle the login command.
+
+Initiates a user login process by calling the `login` function from the
+`penify_hook.commands.auth_commands` module using predefined constants
+`API_URL` and `DASHBOARD_URL` from the `penify_hook.constants` module.
+
+Args:
+ args (argparse.Namespace): Parsed arguments containing necessary parameters for the login command.
+
+Returns:
+ None: This function does not return any value; it is expected to handle the
+ login process internally.
+
+
+
+
+
+ penify_hook.commands.auth_commands.login
+ penify_hook.main.main
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1main.xml b/docs343/xml/namespacepenify__hook_1_1main.xml
new file mode 100644
index 0000000..786eb40
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1main.xml
@@ -0,0 +1,50 @@
+
+
+
+ penify_hook::main
+
+
+ def
+ def penify_hook.main.main
+ ()
+ main
+ penify_hook.main.main
+
+
+
+Main function to handle command-line interface (CLI) interactions with
+Penify services.
+
+This tool provides a command-line interface for generating smart commit
+messages, configuring local-LLM and JIRA, and generating code
+documentation. It supports basic commands that do not require login and
+advanced commands that require user authentication. The `--version` flag
+can be used to display the version information.
+
+Returns:
+ int: Exit status of the program (0 for success, 1 for error).
+
+
+
+
+
+ penify_hook.commands.commit_commands.handle_commit
+ penify_hook.config_command.handle_config
+ penify_hook.commands.doc_commands.handle_docgen
+ penify_hook.login_command.handle_login
+ penify_hook.main.main
+ penify_hook.ui_utils.print_info
+ penify_hook.commands.commit_commands.setup_commit_parser
+ penify_hook.config_command.setup_config_parser
+ penify_hook.commands.doc_commands.setup_docgen_parser
+ penify_hook.login_command.setup_login_parser
+ penify_hook.main.main
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1ui__utils.xml b/docs343/xml/namespacepenify__hook_1_1ui__utils.xml
new file mode 100644
index 0000000..194d4f6
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1ui__utils.xml
@@ -0,0 +1,667 @@
+
+
+
+ penify_hook::ui_utils
+
+
+
+ penify_hook::ui_utils.autoreset
+
+ autoreset
+ penify_hook.ui_utils.autoreset
+
+
+
+
+
+
+
+
+
+
+ penify_hook::ui_utils.INFO_COLOR
+
+ INFO_COLOR
+ penify_hook.ui_utils.INFO_COLOR
+ = Fore.CYAN
+
+
+
+
+
+
+
+
+
+
+ penify_hook::ui_utils.SUCCESS_COLOR
+
+ SUCCESS_COLOR
+ penify_hook.ui_utils.SUCCESS_COLOR
+ = Fore.GREEN
+
+
+
+
+
+
+
+
+
+
+ penify_hook::ui_utils.WARNING_COLOR
+
+ WARNING_COLOR
+ penify_hook.ui_utils.WARNING_COLOR
+ = Fore.YELLOW
+
+
+
+
+
+
+
+
+
+
+ penify_hook::ui_utils.ERROR_COLOR
+
+ ERROR_COLOR
+ penify_hook.ui_utils.ERROR_COLOR
+ = Fore.RED
+
+
+
+
+
+
+
+
+
+
+ penify_hook::ui_utils.HIGHLIGHT_COLOR
+
+ HIGHLIGHT_COLOR
+ penify_hook.ui_utils.HIGHLIGHT_COLOR
+ = Fore.BLUE
+
+
+
+
+
+
+
+
+
+
+ penify_hook::ui_utils.NEUTRAL_COLOR
+
+ NEUTRAL_COLOR
+ penify_hook.ui_utils.NEUTRAL_COLOR
+ = Fore.WHITE
+
+
+
+
+
+
+
+
+
+ string
+ string penify_hook::ui_utils.SUCCESS_SYMBOL
+
+ SUCCESS_SYMBOL
+ penify_hook.ui_utils.SUCCESS_SYMBOL
+ = "✓"
+
+
+
+
+
+
+
+
+
+ string
+ string penify_hook::ui_utils.WARNING_SYMBOL
+
+ WARNING_SYMBOL
+ penify_hook.ui_utils.WARNING_SYMBOL
+ = "â—‹"
+
+
+
+
+
+
+
+
+
+ string
+ string penify_hook::ui_utils.ERROR_SYMBOL
+
+ ERROR_SYMBOL
+ penify_hook.ui_utils.ERROR_SYMBOL
+ = "✗"
+
+
+
+
+
+
+
+
+
+ string
+ string penify_hook::ui_utils.PROCESSING_SYMBOL
+
+ PROCESSING_SYMBOL
+ penify_hook.ui_utils.PROCESSING_SYMBOL
+ = "⟳"
+
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.ui_utils.format_info
+ (message)
+ format_info
+ penify_hook.ui_utils.format_info
+
+ message
+ message
+
+
+
+
+Format an informational message with appropriate color.
+
+Args:
+ message (str): The text of the informational message to be formatted.
+
+Returns:
+ str: The formatted informational message with the specified color.
+
+
+
+
+
+ penify_hook.ui_utils.create_progress_bar
+ penify_hook.ui_utils.create_stage_progress_bar
+ penify_hook.ui_utils.print_info
+
+
+ def
+ def penify_hook.ui_utils.format_success
+ (message)
+ format_success
+ penify_hook.ui_utils.format_success
+
+ message
+ message
+
+
+
+
+Format a success message with appropriate color.
+
+This function takes a message as input and wraps it in ANSI escape codes
+to display it in green, indicating a successful operation. The
+Style.RESET_ALL is applied at the end to ensure that any subsequent text
+is displayed in the default style.
+
+Args:
+ message (str): The message to be formatted as a success message.
+
+Returns:
+ str: The formatted success message with green color and reset style.
+
+
+
+
+
+ penify_hook.ui_utils.print_success
+
+
+ def
+ def penify_hook.ui_utils.format_warning
+ (message)
+ format_warning
+ penify_hook.ui_utils.format_warning
+
+ message
+ message
+
+
+
+
+Format a warning message with appropriate color.
+
+Args:
+ message (str): The warning message to be formatted.
+
+Returns:
+ str: The formatted warning message with the specified color.
+
+
+
+
+
+ penify_hook.ui_utils.print_warning
+
+
+ def
+ def penify_hook.ui_utils.format_error
+ (message)
+ format_error
+ penify_hook.ui_utils.format_error
+
+ message
+ message
+
+
+
+
+Format an error message with appropriate color.
+
+This function takes a plain error message and wraps it in ANSI escape
+codes to apply the specified error color, ensuring that the error
+message is visually distinct when output. The function supports various
+error colors defined by constants like `ERROR_COLOR`.
+
+Args:
+ message (str): The plain text error message to be formatted.
+
+Returns:
+ str: The formatted error message with the error color applied.
+
+
+
+
+
+ penify_hook.ui_utils.print_error
+
+
+ def
+ def penify_hook.ui_utils.format_highlight
+ (message)
+ format_highlight
+ penify_hook.ui_utils.format_highlight
+
+ message
+ message
+
+
+
+
+Format a highlighted message with appropriate color.
+
+Args:
+ message (str): The message to be formatted and highlighted.
+
+Returns:
+ str: The formatted message with applied highlight style.
+
+
+
+
+
+
+
+ def
+ def penify_hook.ui_utils.format_file_path
+ (file_path)
+ format_file_path
+ penify_hook.ui_utils.format_file_path
+
+ file_path
+ file_path
+
+
+
+
+Format a file path with appropriate color.
+
+This function takes a file path as input and wraps it in ANSI escape
+codes to apply a warning color. The original file path is then reset to
+default style using Style.RESET_ALL.
+
+Args:
+ file_path (str): The file path to be formatted.
+
+Returns:
+ str: The formatted file path with the warning color applied.
+
+
+
+
+
+ penify_hook.ui_utils.print_processing
+ penify_hook.file_analyzer.FileAnalyzerGenHook.print_processing
+
+
+ def
+ def penify_hook.ui_utils.print_info
+ (message)
+ print_info
+ penify_hook.ui_utils.print_info
+
+ message
+ message
+
+
+
+
+Print an informational message with appropriate formatting.
+
+This function takes a string message as input and prints it in a
+formatted manner. It utilizes the `format_info` function to apply any
+necessary formatting before printing.
+
+Args:
+ message (str): The message to be printed.
+
+
+
+
+
+ penify_hook.ui_utils.format_info
+ penify_hook.commands.commit_commands.commit_code
+ penify_hook.jira_client.JiraClient.extract_issue_keys_from_branch
+ penify_hook.commit_analyzer.CommitDocGenHook.get_summary
+ penify_hook.commands.commit_commands.handle_commit
+ penify_hook.main.main
+ penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+ penify_hook.git_analyzer.GitDocGenHook.run
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+
+ def
+ def penify_hook.ui_utils.print_success
+ (message)
+ print_success
+ penify_hook.ui_utils.print_success
+
+ message
+ message
+
+
+
+
+Print a formatted success message.
+
+This function takes a string `message` and prints it as a formatted
+success message. The formatting includes adding a prefix "Success: " to
+the message and enclosing it within asterisks for emphasis.
+
+Args:
+ message (str): The message to be printed as a success message.
+
+
+
+
+
+ penify_hook.ui_utils.format_success
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+ penify_hook.git_analyzer.GitDocGenHook.run
+ penify_hook.commit_analyzer.CommitDocGenHook.run
+
+
+ def
+ def penify_hook.ui_utils.print_warning
+ (message)
+ print_warning
+ penify_hook.ui_utils.print_warning
+
+ message
+ message
+
+
+
+
+Print a warning message with appropriate formatting.
+
+This function takes a warning message as input and prints it with
+formatted output. The formatting may include color, timestamp, or other
+styles to emphasize that it is a warning.
+
+Args:
+ message (str): The warning message to be printed.
+
+
+
+
+
+ penify_hook.ui_utils.format_warning
+ penify_hook.commands.commit_commands.commit_code
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+ penify_hook.commit_analyzer.CommitDocGenHook.process_jira_integration
+
+
+ def
+ def penify_hook.ui_utils.print_error
+ (message)
+ print_error
+ penify_hook.ui_utils.print_error
+
+ message
+ message
+
+
+
+
+Print an error message with appropriate formatting.
+
+This function takes a string message, formats it as an error message,
+and then prints it. The formatting typically includes prefixing the
+message with "Error: " to clearly indicate that it is an error.
+
+Args:
+ message (str): The error message to be printed.
+
+
+
+
+
+ penify_hook.ui_utils.format_error
+ penify_hook.commands.commit_commands.commit_code
+
+
+ def
+ def penify_hook.ui_utils.print_processing
+ (file_path)
+ print_processing
+ penify_hook.ui_utils.print_processing
+
+ file_path
+ file_path
+
+
+
+
+Print a processing message for a specified file.
+
+This function takes a file path, formats it using `format_file_path`,
+and then prints a formatted message indicating that the file is being
+processed. The formatted path is highlighted using `format_highlight`.
+
+Args:
+ file_path (str): The path of the file to be processed.
+
+
+
+
+
+ penify_hook.ui_utils.format_file_path
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+
+ def
+ def penify_hook.ui_utils.print_status
+ (status, message)
+ print_status
+ penify_hook.ui_utils.print_status
+
+ status
+ status
+
+
+ message
+ message
+
+
+
+
+Print a status message with an appropriate symbol.
+
+This function takes a status and a message, then prints them with a
+colored symbol that corresponds to the given status. The available
+statuses are 'success', 'warning', 'error', and any other value will
+default to a processing indicator.
+
+Args:
+ status (str): The status type ('success', 'warning', 'error') or another string.
+ message (str): The message to be displayed along with the symbol.
+
+
+
+
+
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+
+ def
+ def penify_hook.ui_utils.create_progress_bar
+ (total, desc="Processing", unit="item")
+ create_progress_bar
+ penify_hook.ui_utils.create_progress_bar
+
+ total
+ total
+
+
+ desc
+ desc
+ "Processing"
+
+
+ unit
+ unit
+ "item"
+
+
+
+
+Create a tqdm progress bar with consistent styling.
+
+Args:
+ total (int): Total number of items to process.
+ desc (str): Description for the progress bar. Defaults to "Processing".
+ unit (str): Unit label for the progress items. Defaults to "item".
+
+Returns:
+ tqdm: A configured tqdm progress bar instance.
+
+
+
+
+
+ penify_hook.ui_utils.format_info
+ penify_hook.git_analyzer.GitDocGenHook.run
+
+
+ def
+ def penify_hook.ui_utils.create_stage_progress_bar
+ (stages, desc="Processing")
+ create_stage_progress_bar
+ penify_hook.ui_utils.create_stage_progress_bar
+
+ stages
+ stages
+
+
+ desc
+ desc
+ "Processing"
+
+
+
+
+Create a tqdm progress bar for processing stages with consistent
+styling.
+
+This function initializes and returns a tqdm progress bar object for
+tracking the progress through a series of stages. It also provides a
+description for the progress bar to enhance its usability.
+
+Args:
+ stages (list): A list of strings representing individual stages in the process.
+ desc (str?): A description for the progress bar. Defaults to "Processing".
+
+Returns:
+ tuple: A tuple containing the tqdm progress bar object and the list of stages.
+
+
+
+
+
+ penify_hook.ui_utils.format_info
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+
+
+ def
+ def penify_hook.ui_utils.update_stage
+ (pbar, stage_name)
+ update_stage
+ penify_hook.ui_utils.update_stage
+
+ pbar
+ pbar
+
+
+ stage_name
+ stage_name
+
+
+
+
+Update the progress bar with a new stage name.
+
+This function updates the provided tqdm progress bar to reflect the
+current stage of a process. It clears any existing postfix and sets a
+new description based on the provided stage name. The display is then
+refreshed to ensure that the update is visible immediately.
+
+Args:
+ pbar (tqdm): The progress bar object to be updated.
+ stage_name (str): A string representing the current stage of the process.
+
+
+
+
+
+ penify_hook.file_analyzer.FileAnalyzerGenHook.process_file
+ penify_hook.file_analyzer.FileAnalyzerGenHook.run
+
+
+
+
+
+UI utilities for Penify CLI.
+
+This module provides utility functions for consistent UI formatting,
+colored output, and progress indicators across the Penify CLI application.
+
+
+
+
+
diff --git a/docs343/xml/namespacepenify__hook_1_1utils.xml b/docs343/xml/namespacepenify__hook_1_1utils.xml
new file mode 100644
index 0000000..fea6e7d
--- /dev/null
+++ b/docs343/xml/namespacepenify__hook_1_1utils.xml
@@ -0,0 +1,96 @@
+
+
+
+ penify_hook::utils
+ penify_hook::utils::GitRepoNotFoundError
+
+
+
+ penify_hook::utils.logger
+
+ logger
+ penify_hook.utils.logger
+ = logging.getLogger(__name__)
+
+
+
+
+
+
+
+
+
+
+
+ def
+ def penify_hook.utils.get_repo_details
+ (Repo repo)
+ get_repo_details
+ penify_hook.utils.get_repo_details
+
+ Repo
+ repo
+
+
+
+
+Determine the details of a repository including its remote URL, hosting service, organization name, and repository name.
+
+
+
+
+
+
+ def
+ def penify_hook.utils.recursive_search_git_folder
+ (folder_path)
+ recursive_search_git_folder
+ penify_hook.utils.recursive_search_git_folder
+
+ folder_path
+ folder_path
+
+
+
+
+Recursively searches for a .git folder starting from the given directory.
+
+
+
+
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.commit_commands.commit_code
+ penify_hook.commands.config_commands.get_penify_config
+ penify_hook.commands.config_commands.load_env_files
+ penify_hook.utils.recursive_search_git_folder
+ penify_hook.commands.auth_commands.save_credentials
+ penify_hook.commands.config_commands.save_jira_config
+ penify_hook.commands.config_commands.save_llm_config
+
+
+ def
+ def penify_hook.utils.find_git_parent
+ (path)
+ find_git_parent
+ penify_hook.utils.find_git_parent
+
+ path
+ path
+
+
+
+
+Traverse up from the given path to find the nearest directory containing a .git subdirectory.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacesetup.xml b/docs343/xml/namespacesetup.xml
new file mode 100644
index 0000000..9527ed9
--- /dev/null
+++ b/docs343/xml/namespacesetup.xml
@@ -0,0 +1,195 @@
+
+
+
+ setup
+
+
+
+ setup.name
+
+ name
+ setup.name
+
+
+
+
+
+
+
+
+
+
+ setup.version
+
+ version
+ setup.version
+
+
+
+
+
+
+
+
+
+
+ setup.packages
+
+ packages
+ setup.packages
+
+
+
+
+
+
+
+
+
+
+ setup.install_requires
+
+ install_requires
+ setup.install_requires
+
+
+
+
+
+
+
+
+
+
+ setup.entry_points
+
+ entry_points
+ setup.entry_points
+
+
+
+
+
+
+
+
+
+
+ setup.author
+
+ author
+ setup.author
+
+
+
+
+
+
+
+
+
+
+ setup.author_email
+
+ author_email
+ setup.author_email
+
+
+
+
+
+
+
+
+
+
+ setup.description
+
+ description
+ setup.description
+
+
+
+
+
+
+
+
+
+
+ setup.long_description
+
+ long_description
+ setup.long_description
+
+
+
+
+
+
+
+
+
+
+ setup.long_description_content_type
+
+ long_description_content_type
+ setup.long_description_content_type
+
+
+
+
+
+
+
+
+
+
+ setup.url
+
+ url
+ setup.url
+
+
+
+
+
+
+
+
+
+
+ setup.classifiers
+
+ classifiers
+ setup.classifiers
+
+
+
+
+
+
+
+
+
+
+ setup.python_requires
+
+ python_requires
+ setup.python_requires
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacestd.xml b/docs343/xml/namespacestd.xml
new file mode 100644
index 0000000..0f0343b
--- /dev/null
+++ b/docs343/xml/namespacestd.xml
@@ -0,0 +1,110 @@
+
+
+
+ std
+ std::allocator
+ std::array
+ std::atomic
+ std::atomic_ref
+ std::auto_ptr
+ std::bad_alloc
+ std::bad_cast
+ std::bad_exception
+ std::bad_typeid
+ std::basic_fstream
+ std::basic_ifstream
+ std::basic_ios
+ std::basic_iostream
+ std::basic_istream
+ std::basic_istringstream
+ std::basic_ofstream
+ std::basic_ostream
+ std::basic_ostringstream
+ std::basic_string
+ std::basic_string_view
+ std::basic_stringstream
+ std::bitset
+ std::complex
+ std::deque
+ std::domain_error
+ std::error_category
+ std::error_code
+ std::error_condition
+ std::exception
+ std::forward_list
+ std::fstream
+ std::ifstream
+ std::invalid_argument
+ std::ios
+ std::ios_base
+ std::istream
+ std::istringstream
+ std::jthread
+ std::length_error
+ std::list
+ std::lock_guard
+ std::logic_error
+ std::map
+ std::multimap
+ std::multiset
+ std::mutex
+ std::ofstream
+ std::ostream
+ std::ostringstream
+ std::out_of_range
+ std::overflow_error
+ std::priority_queue
+ std::queue
+ std::range_error
+ std::recursive_mutex
+ std::recursive_timed_mutex
+ std::runtime_error
+ std::set
+ std::shared_lock
+ std::shared_mutex
+ std::shared_ptr
+ std::shared_timed_mutex
+ std::smart_ptr
+ std::span
+ std::stack
+ std::string
+ std::string_view
+ std::stringstream
+ std::system_error
+ std::thread
+ std::timed_mutex
+ std::u16string
+ std::u16string_view
+ std::u32string
+ std::u32string_view
+ std::u8string
+ std::u8string_view
+ std::underflow_error
+ std::unique_lock
+ std::unique_ptr
+ std::unordered_map
+ std::unordered_multimap
+ std::unordered_multiset
+ std::unordered_set
+ std::valarray
+ std::vector
+ std::weak_ptr
+ std::wfstream
+ std::wifstream
+ std::wios
+ std::wistream
+ std::wistringstream
+ std::wofstream
+ std::wostream
+ std::wostringstream
+ std::wstring
+ std::wstring_view
+ std::wstringstream
+
+STL namespace.
+
+
+
+
+
+
diff --git a/docs343/xml/namespacetests.xml b/docs343/xml/namespacetests.xml
new file mode 100644
index 0000000..3b5005f
--- /dev/null
+++ b/docs343/xml/namespacetests.xml
@@ -0,0 +1,16 @@
+
+
+
+ tests
+ tests::conftest
+ tests::test_commit_commands
+ tests::test_config_commands
+ tests::test_doc_commands
+ tests::test_web_config
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacetests_1_1conftest.xml b/docs343/xml/namespacetests_1_1conftest.xml
new file mode 100644
index 0000000..9d124cb
--- /dev/null
+++ b/docs343/xml/namespacetests_1_1conftest.xml
@@ -0,0 +1,11 @@
+
+
+
+ tests::conftest
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacetests_1_1test__commit__commands.xml b/docs343/xml/namespacetests_1_1test__commit__commands.xml
new file mode 100644
index 0000000..b7c5e1f
--- /dev/null
+++ b/docs343/xml/namespacetests_1_1test__commit__commands.xml
@@ -0,0 +1,12 @@
+
+
+
+ tests::test_commit_commands
+ tests::test_commit_commands::TestCommitCommands
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacetests_1_1test__config__commands.xml b/docs343/xml/namespacetests_1_1test__config__commands.xml
new file mode 100644
index 0000000..9443c08
--- /dev/null
+++ b/docs343/xml/namespacetests_1_1test__config__commands.xml
@@ -0,0 +1,12 @@
+
+
+
+ tests::test_config_commands
+ tests::test_config_commands::TestConfigCommands
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacetests_1_1test__doc__commands.xml b/docs343/xml/namespacetests_1_1test__doc__commands.xml
new file mode 100644
index 0000000..50d67cf
--- /dev/null
+++ b/docs343/xml/namespacetests_1_1test__doc__commands.xml
@@ -0,0 +1,461 @@
+
+
+
+ tests::test_doc_commands
+
+
+ def
+ def tests.test_doc_commands.test_generate_doc_no_location
+ (mock_getcwd, mock_api_client, mock_folder_analyzer, mock_file_analyzer, mock_git_analyzer)
+ test_generate_doc_no_location
+ tests.test_doc_commands.test_generate_doc_no_location
+
+ mock_getcwd
+ mock_getcwd
+
+
+ mock_api_client
+ mock_api_client
+
+
+ mock_folder_analyzer
+ mock_folder_analyzer
+
+
+ mock_file_analyzer
+ mock_file_analyzer
+
+
+ mock_git_analyzer
+ mock_git_analyzer
+
+
+
+
+Test function to generate documentation without location information.
+
+This function sets up mocks for the API client, current working
+directory, and Git analyzer. It then calls the `generate_doc` function
+with a fake API URL and token. The function is expected to initialize
+the API client, configure the Git analyzer, and run it without any
+location information.
+
+Args:
+ mock_getcwd (MagicMock): Mock for os.getcwd().
+ mock_api_client (MagicMock): Mock for creating an API client.
+ mock_folder_analyzer (MagicMock): Mock for folder analysis.
+ mock_file_analyzer (MagicMock): Mock for file analysis.
+ mock_git_analyzer (MagicMock): Mock for Git analyzer setup.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+
+
+ def
+ def tests.test_doc_commands.test_generate_doc_file_location
+ (mock_api_client, mock_folder_analyzer, mock_file_analyzer, mock_git_analyzer)
+ test_generate_doc_file_location
+ tests.test_doc_commands.test_generate_doc_file_location
+
+ mock_api_client
+ mock_api_client
+
+
+ mock_folder_analyzer
+ mock_folder_analyzer
+
+
+ mock_file_analyzer
+ mock_file_analyzer
+
+
+ mock_git_analyzer
+ mock_git_analyzer
+
+
+
+
+Test generating a documentation file location.
+
+This function tests the process of generating a documentation file
+location using mock objects for API client, folder analyzer, file
+analyzer, and Git analyzer. It sets up the necessary mocks, calls the
+`generate_doc` function with specified parameters, and asserts that the
+appropriate methods on the mock objects are called as expected.
+
+Args:
+ mock_api_client (MagicMock): Mock object for the API client.
+ mock_folder_analyzer (MagicMock): Mock object for the folder analyzer.
+ mock_file_analyzer (MagicMock): Mock object for the file analyzer.
+ mock_git_analyzer (MagicMock): Mock object for the Git analyzer.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+
+
+ def
+ def tests.test_doc_commands.test_generate_doc_folder_location
+ (mock_api_client, mock_folder_analyzer, mock_file_analyzer, mock_git_analyzer)
+ test_generate_doc_folder_location
+ tests.test_doc_commands.test_generate_doc_folder_location
+
+ mock_api_client
+ mock_api_client
+
+
+ mock_folder_analyzer
+ mock_folder_analyzer
+
+
+ mock_file_analyzer
+ mock_file_analyzer
+
+
+ mock_git_analyzer
+ mock_git_analyzer
+
+
+
+
+Test the function to generate documentation for a folder location.
+
+It sets up mock objects for API client, folder analyzer, file analyzer,
+and Git analyzer, then calls the `generate_doc` function with specified
+parameters. Finally, it asserts that the correct methods on the mock
+objects were called as expected.
+
+Args:
+ mock_api_client (MagicMock): Mock object for the API client.
+ mock_folder_analyzer (MagicMock): Mock object for the folder analyzer.
+ mock_file_analyzer (MagicMock): Mock object for the file analyzer.
+ mock_git_analyzer (MagicMock): Mock object for the Git analyzer.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+
+
+ def
+ def tests.test_doc_commands.test_generate_doc_error_handling
+ (mock_api_client, mock_git_analyzer, mock_exit)
+ test_generate_doc_error_handling
+ tests.test_doc_commands.test_generate_doc_error_handling
+
+ mock_api_client
+ mock_api_client
+
+
+ mock_git_analyzer
+ mock_git_analyzer
+
+
+ mock_exit
+ mock_exit
+
+
+
+
+Generate a documentation string for the provided code snippet using
+Google Docstring style.
+
+Short one line description: Test function to ensure proper error
+handling during API calls with GitAnalyzer. Multiline long description:
+This test function is designed to verify that the generate_doc function
+handles exceptions correctly when an error occurs during API interaction
+with GitAnalyzer. It sets up a mock API client and a mock Git analyzer,
+causing the analyzer to raise an exception to simulate a failure
+condition. The function then asserts that the exit code is set to 1 when
+the error handling mechanism is invoked.
+
+Args:
+ mock_api_client (MagicMock): A mock object simulating the API client.
+ mock_git_analyzer (MagicMock): A mock object simulating the Git analyzer, configured to raise an
+ exception.
+ mock_exit (MagicMock): A mock object representing the exit function, which should be called
+ with an error code.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+
+
+ def
+ def tests.test_doc_commands.test_setup_docgen_parser
+ ()
+ test_setup_docgen_parser
+ tests.test_doc_commands.test_setup_docgen_parser
+
+
+
+Test the setup_docgen_parser function to ensure it properly configures
+the ArgumentParser for docgen options.
+
+It verifies that the parser correctly sets up docgen options and handles
+different subcommands like 'install-hook' and 'uninstall-hook'.
+
+
+
+
+
+ penify_hook.commands.doc_commands.setup_docgen_parser
+
+
+ def
+ def tests.test_doc_commands.test_handle_docgen_install_hook
+ (mock_exit, mock_get_token, mock_generate_doc, mock_uninstall_hook, mock_install_hook)
+ test_handle_docgen_install_hook
+ tests.test_doc_commands.test_handle_docgen_install_hook
+
+ mock_exit
+ mock_exit
+
+
+ mock_get_token
+ mock_get_token
+
+
+ mock_generate_doc
+ mock_generate_doc
+
+
+ mock_uninstall_hook
+ mock_uninstall_hook
+
+
+ mock_install_hook
+ mock_install_hook
+
+
+
+
+Test the handling of the 'install-hook' subcommand.
+
+This function sets up a mock environment where it simulates the
+execution of the 'install-hook' subcommand. It verifies that the
+`mock_install_hook` is called with the correct arguments, while
+`mock_generate_doc` and `mock_uninstall_hook` are not called.
+
+Args:
+ mock_exit (MagicMock): Mock object for sys.exit.
+ mock_get_token (MagicMock): Mock object to simulate fetching a token.
+ mock_generate_doc (MagicMock): Mock object to simulate generating documentation.
+ mock_uninstall_hook (MagicMock): Mock object to simulate uninstalling a hook.
+ mock_install_hook (MagicMock): Mock object to simulate installing a hook.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+
+
+ def
+ def tests.test_doc_commands.test_handle_docgen_uninstall_hook
+ (mock_exit, mock_get_token, mock_generate_doc, mock_uninstall_hook, mock_install_hook)
+ test_handle_docgen_uninstall_hook
+ tests.test_doc_commands.test_handle_docgen_uninstall_hook
+
+ mock_exit
+ mock_exit
+
+
+ mock_get_token
+ mock_get_token
+
+
+ mock_generate_doc
+ mock_generate_doc
+
+
+ mock_uninstall_hook
+ mock_uninstall_hook
+
+
+ mock_install_hook
+ mock_install_hook
+
+
+
+
+Test the uninstall-hook subcommand of the handle_docgen function.
+This test case sets up a mock environment and verifies that the
+uninstall-hook is called with the correct location, while generate_doc
+and install_hook are not called.
+
+Args:
+ mock_exit (MagicMock): A mock for the exit function.
+ mock_get_token (MagicMock): A mock for the get_token function.
+ mock_generate_doc (MagicMock): A mock for the generate_doc function.
+ mock_uninstall_hook (MagicMock): A mock for the uninstall_hook function.
+ mock_install_hook (MagicMock): A mock for the install_hook function.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+
+
+ def
+ def tests.test_doc_commands.test_handle_docgen_generate
+ (mock_get_token, mock_generate_doc, mock_uninstall_hook, mock_install_hook)
+ test_handle_docgen_generate
+ tests.test_doc_commands.test_handle_docgen_generate
+
+ mock_get_token
+ mock_get_token
+
+
+ mock_generate_doc
+ mock_generate_doc
+
+
+ mock_uninstall_hook
+ mock_uninstall_hook
+
+
+ mock_install_hook
+ mock_install_hook
+
+
+
+
+Test the direct documentation generation functionality.
+
+This function tests the `handle_docgen` function when no subcommand is
+provided. It verifies that the document generation hook is called and
+the uninstall and install hooks are not called.
+
+Args:
+ mock_get_token (MagicMock): Mocked function to get authentication token.
+ mock_generate_doc (MagicMock): Mocked function for generating documentation.
+ mock_uninstall_hook (MagicMock): Mocked function for uninstalling the document generation hook.
+ mock_install_hook (MagicMock): Mocked function for installing the document generation hook.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+
+
+ def
+ def tests.test_doc_commands.test_handle_docgen_no_token
+ (mock_exit, mock_get_token)
+ test_handle_docgen_no_token
+ tests.test_doc_commands.test_handle_docgen_no_token
+
+ mock_exit
+ mock_exit
+
+
+ mock_get_token
+ mock_get_token
+
+
+
+
+Test the behavior of the `handle_docgen` function when no token is
+provided.
+
+This function asserts that if no token is returned by `mock_get_token`,
+the `handle_docgen` function will call `mock_exit` with a status code of
+1.
+
+Args:
+ mock_exit (MagicMock): A MagicMock object simulating the `exit` function.
+ mock_get_token (MagicMock): A MagicMock object simulating the `get_token` function.
+
+
+
+
+
+ penify_hook.commands.doc_commands.handle_docgen
+
+
+ def
+ def tests.test_doc_commands.test_generate_doc_with_file_exception
+ (mock_api_client, mock_getcwd)
+ test_generate_doc_with_file_exception
+ tests.test_doc_commands.test_generate_doc_with_file_exception
+
+ mock_api_client
+ mock_api_client
+
+
+ mock_getcwd
+ mock_getcwd
+
+
+
+
+Generate documentation from a Python source file.
+
+This function reads a Python file and generates a docstring based on its
+content. It uses mock objects to simulate API calls and directory
+operations during testing.
+
+Args:
+ mock_api_client (unittest.mock.MagicMock): A mock object for simulating API client behavior.
+ mock_getcwd (unittest.mock.MagicMock): A mock object for simulating the current working directory function.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+
+
+ def
+ def tests.test_doc_commands.test_generate_doc_with_folder_exception
+ (mock_api_client, mock_getcwd)
+ test_generate_doc_with_folder_exception
+ tests.test_doc_commands.test_generate_doc_with_folder_exception
+
+ mock_api_client
+ mock_api_client
+
+
+ mock_getcwd
+ mock_getcwd
+
+
+
+
+Generate documentation from a given API endpoint and save it to a
+folder.
+
+This function fetches data from the specified API endpoint, processes
+it, and saves the generated documentation in the provided folder. If an
+error occurs during the fetching process, a SystemExit exception is
+raised with an appropriate message.
+
+Args:
+ api_url (str): The URL of the API endpoint from which data will be fetched.
+ token (str): The authentication token required to access the API.
+ folder_path (str): The path to the folder where the documentation will be saved.
+
+
+
+
+
+ penify_hook.commands.doc_commands.generate_doc
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/namespacetests_1_1test__web__config.xml b/docs343/xml/namespacetests_1_1test__web__config.xml
new file mode 100644
index 0000000..d68b4d9
--- /dev/null
+++ b/docs343/xml/namespacetests_1_1test__web__config.xml
@@ -0,0 +1,12 @@
+
+
+
+ tests::test_web_config
+ tests::test_web_config::TestWebConfig
+
+
+
+
+
+
+
diff --git a/docs343/xml/penify-cli-documentation_8md.xml b/docs343/xml/penify-cli-documentation_8md.xml
new file mode 100644
index 0000000..83e4922
--- /dev/null
+++ b/docs343/xml/penify-cli-documentation_8md.xml
@@ -0,0 +1,220 @@
+
+
+
+ penify-cli-documentation.md
+
+
+
+
+
+---
+layout:doc
+title:StreamlineGitCommitsandCodeDocumentationwithPenify-CLI'sAutomatedGeneration
+description:DiscoverhowPenify-CLIautomatesbothGitcommitmessagesandcodedocumentation,withJiraintegrationandflexibleoptions.Savetime,improverepositoryclarity,andboostproductivitywiththisdetailedguidetousageandbestpractices.
+keywords:Penify-CLI,Gitcommitmessages,codedocumentation,Jiraintegration,automateddocumentation,versioncontrol,repositorymanagement,developerproductivity
+author:SumanSauarbh
+---
+#PenifyCLIDocumentation
+
+PenifyCLIisapowerfultoolforenhancingyourdevelopmentworkflowwithAI-poweredfeatureslikecommitmessagegeneration,codedocumentation,andJIRAintegration.
+
+##Installation
+
+```bash
+pipinstallpenify
+```
+
+##GettingStarted
+
+Afterinstallation,youcanchecktheversionofPenifyCLI:
+
+```bash
+penify--version
+```
+
+##CommandsOverview
+
+-`commit`:Generatesmartcommitmessagesusinglocal-LLM
+-`config`:Configurelocal-LLMandJIRAsettings
+-`login`:LogintoPenifytouseadvancedfeatures
+-`docgen`:GeneratecodedocumentationforGitdiffs,files,orfolders
+
+##DetailedCommandDocumentation
+
+###CommitCommand
+
+The`commit`commandgeneratesintelligentcommitmessagesusinglocalLLMmodelsorPenifyservices.
+
+####Usage:
+
+```bash
+penifycommit[options]
+```
+
+####Options:
+
+-`-m,--messageTEXT`:Providecontextforthecommitmessagegeneration
+-`-e,--terminal`:Openaneditortomodifythegeneratedcommitmessagebeforeapplyingit
+-`-d,--description`:Generateadetailedcommitmessagewithbothtitleanddescription
+
+####Examples:
+
+**Basicusage:**
+```bash
+penifycommit
+```
+
+**Providecontextforbetterresults:**
+```bash
+penifycommit-m"Fixedtheloginbutton"
+```
+
+**Generateadetailedcommitmessageandopeneditor:**
+```bash
+penifycommit-e-d
+```
+
+####Requirements:
+
+-EitheralocalLLMconfiguration(via`penifyconfigllm`)orPenifylogin
+-ForJIRAintegration,configureJIRAsettings(via`penifyconfigjira`)
+
+---
+
+###ConfigCommand
+
+The`config`commandhelpsyouconfigurelocalLLMsettingsandJIRAintegrationforenhancedcommitmessages.
+
+####Usage:
+
+```bash
+penifyconfig[subcommand]
+```
+
+####Subcommands:
+
+-`llm`:ConfigurelocalLargeLanguageModelsettings
+-`jira`:ConfigureJIRAintegrationsettings
+
+####Examples:
+
+**ConfigurelocalLLM:**
+```bash
+penifyconfigllm
+```
+Thisopensawebinterfacetoconfigure:
+-Modelname(e.g.,gpt-3.5-turbo,llama2)
+-APIbaseURL(e.g.,https://api.openai.com/v1)
+-APIkey
+
+**ConfigureJIRAintegration:**
+```bash
+penifyconfigjira
+```
+Thisopensawebinterfacetoconfigure:
+-JIRAURL(e.g.,https://your-domain.atlassian.net)
+-Username(typicallyyouremail)
+-APItoken
+
+---
+
+###LoginCommand
+
+The`login`commandauthenticatesyouwithPenifyforadvancedfeatureslikecodedocumentationgeneration.
+
+####Usage:
+
+```bash
+penifylogin
+```
+
+####Whathappens:
+1.AbrowserwindowopenstothePenifyloginpage
+2.Aftersuccessfullogin,yourAPIkeyisautomaticallysaved
+3.ThetoolisnowauthorizedtousePenify'sadvancedfeatures
+
+####Example:
+
+```bash
+penifylogin
+```
+
+---
+
+###DocgenCommand
+
+The`docgen`commandgeneratesdocumentationforyourcodeusingPenify'sAIservices.
+
+####Usage:
+
+```bash
+penifydocgen[options][subcommand]
+```
+
+####Options:
+
+-`-l,--locationPATH`:Pathtoaspecificfileorfoldertodocument(default:currentworkingdirectory)
+
+####Subcommands:
+
+-`install-hook`:InstallaGitpost-commithooktoautomaticallygeneratedocumentation
+-`uninstall-hook`:RemovetheGitpost-commithook
+
+####Examples:
+
+**DocumentcurrentGitdiff:**
+```bash
+penifydocgen
+```
+
+**Documentaspecificfile:**
+```bash
+penifydocgen-lsrc/main.py
+```
+
+**Documentanentirefolder:**
+```bash
+penifydocgen-lsrc/components
+```
+
+**InstalltheGithookforautomaticdocumentation:**
+```bash
+penifydocgeninstall-hook
+```
+
+**UninstalltheGithook:**
+```bash
+penifydocgenuninstall-hook
+```
+
+####Requirements:
+
+-RequireslogintoPenify(`penifylogin`)
+
+##ConfigurationFiles
+
+PenifyCLIstoresconfigurationinthefollowinglocations:
+
+-Globalconfiguration:`~/.penify`
+-Project-specificconfiguration:`.penify`inyourGitrepositoryroot
+
+##EnvironmentVariables
+
+-`PENIFY_API_TOKEN`:CanbeusedtoprovidetheAPItokeninsteadofloggingin
+
+##Troubleshooting
+
+Ifyouencounterissues:
+
+1.Checkyourconfigurationwith`cat~/.penify`
+2.VerifynetworkconnectivitytoAPIendpoints
+3.EnsureyourAPIkeysandtokensarevalid
+4.ForJIRAintegrationissues,verifyyourJIRAcredentials
+
+##AdditionalResources
+
+Formoreinformation,visitthe[PenifyDocumentation](https://docs.penify.dev/).
+
+
+
+
diff --git a/docs343/xml/penify__hook_2____init_____8py.xml b/docs343/xml/penify__hook_2____init_____8py.xml
new file mode 100644
index 0000000..d3d0335
--- /dev/null
+++ b/docs343/xml/penify__hook_2____init_____8py.xml
@@ -0,0 +1,13 @@
+
+
+
+ __init__.py
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/penify__hook_2commands_2____init_____8py.xml b/docs343/xml/penify__hook_2commands_2____init_____8py.xml
new file mode 100644
index 0000000..141dfec
--- /dev/null
+++ b/docs343/xml/penify__hook_2commands_2____init_____8py.xml
@@ -0,0 +1,16 @@
+
+
+
+ __init__.py
+ penify_hook
+ penify_hook::commands
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/setup_8py.xml b/docs343/xml/setup_8py.xml
new file mode 100644
index 0000000..b732c20
--- /dev/null
+++ b/docs343/xml/setup_8py.xml
@@ -0,0 +1,46 @@
+
+
+
+ setup.py
+ setup
+
+
+
+
+
+fromsetuptoolsimportsetup,find_packages
+
+[setup](
+name="penify",
+version="0.3.0",
+packages=['penify_hook'],
+install_requires=[
+"requests",
+"tqdm",
+"GitPython",
+"colorama",
+"litellm",
+"jira"
+],
+entry_points={
+"console_scripts":[
+"penify=penify_hook.main:main",
+],
+},
+author="SumanSaurabh",
+author_email="ss.sumansaurabh92@gmail.com",
+description="ApenifyclitooltogenerateDocumentation,Commit-summary.",
+long_description=open("README.md").read(),
+long_description_content_type="text/markdown",
+url="https://github.com/SingularityX-ai/penify",
+classifiers=[
+"ProgrammingLanguage::Python::3",
+"License::OSIApproved::MITLicense",
+"OperatingSystem::OSIndependent",
+],
+python_requires='>=3.6',
+)
+
+
+
+
diff --git a/docs343/xml/test__commit__commands_8py.xml b/docs343/xml/test__commit__commands_8py.xml
new file mode 100644
index 0000000..210ffd1
--- /dev/null
+++ b/docs343/xml/test__commit__commands_8py.xml
@@ -0,0 +1,450 @@
+
+
+
+ test_commit_commands.py
+ tests::test_commit_commands::TestCommitCommands
+ tests
+ tests::test_commit_commands
+
+
+
+
+
+importos
+importsys
+importpytest
+fromunittest.mockimportpatch,MagicMock,call
+
+from[penify_hook.commands.commit_commands]importcommit_code,setup_commit_parser,handle_commit
+
+class[TestCommitCommands]:
+
+@pytest.fixture
+def[mock_api_client](self):
+"""MocksaninstanceofAPIClientusingunittest.mock.
+
+ThisfunctioncreatesamockobjectforAPIClientandyieldsitalong
+withthemockedinstance.Itisusefulfortestingpurposeswherereal
+APIcallsshouldbeavoided.
+
+Yields:
+tuple:AtuplecontainingthemockofAPIClientandthemockedinstanceof
+APIClient.
+"""
+
+withpatch('penify_hook.api_client.APIClient',create=True)asmock:
+api_client_instance=MagicMock()
+mock.return_value=api_client_instance
+yieldmock,api_client_instance
+
+@pytest.fixture
+def[mock_llm_client](self):
+"""MockaninstanceofLLMClientfortestingpurposes.
+
+Thisfunctionyieldsamockobjectrepresentinganinstanceof
+LLMClient,whichcanbeusedtosimulateinteractionswithalanguage
+modelduringtesting.Themockispatchedtoreplacetheactual
+LLMClientclassfromthe[penify_hook]module.
+
+Yields:
+tuple:Atuplecontainingtwoelements:
+-mock(MagicMock):ThemockobjectforLLMClient.
+-llm_client_instance(MagicMock):AninstanceofthemockedLLMClient.
+"""
+
+withpatch('penify_hook.llm_client.LLMClient',create=True)asmock:
+llm_client_instance=MagicMock()
+mock.return_value=llm_client_instance
+yieldmock,llm_client_instance
+
+@pytest.fixture
+def[mock_jira_client](self):
+"""CreateamockJIRAclientfortestingpurposes.
+
+ThisfunctionyieldsatuplecontainingamockJIRAclientinstanceand
+its`is_connected`method.Themockclientisconfiguredtosimulatean
+activeconnection.Thisisusefulforunitteststhatrequire
+interactionwithaJIRAclientwithoutmakingactualnetworkcalls.
+
+Yields:
+tuple:AtuplecontainingthemockedJIRAclientinstanceandits
+`is_connected`method.
+"""
+
+withpatch('penify_hook.jira_client.JiraClient',create=True)asmock:
+jira_instance=MagicMock()
+jira_instance.is_connected.return_value=True
+mock.return_value=jira_instance
+yieldmock,jira_instance
+
+@pytest.fixture
+def[mock_commit_doc_gen](self):
+"""MockstheCommitDocGenHookclassandreturnsaMagicMockinstance.
+
+Thisfunctionusesthe`patch`decoratorfromthe`unittest.mock`module
+tocreateamockofthe`CommitDocGenHook`class.Itthensetsupthis
+mocktoreturnanew`MagicMock`instancewheninvoked.Thefunction
+yieldsboththemockobjectandthemockedinstance,allowingforeasy
+testingoffunctionsthatrelyon`CommitDocGenHook`.
+
+Returns:
+tuple:Atuplecontainingtwoelements:
+-mock(patch):Thepatchobjectusedtomockthe`CommitDocGenHook`
+class.
+-doc_gen_instance(MagicMock):Themockedinstanceof
+`CommitDocGenHook`.
+"""
+
+withpatch('penify_hook.commit_analyzer.CommitDocGenHook',create=True)asmock:
+doc_gen_instance=MagicMock()
+mock.return_value=doc_gen_instance
+yieldmock,doc_gen_instance
+
+@pytest.fixture
+def[mock_git_folder_search](self):
+"""Mockthe`recursive_search_git_folder`functiontoreturnapredefined
+gitfolderpath.
+
+Thisfunctionusesthe`patch`decoratorfromthe`unittest.mock`module
+tointerceptcallsto`penify_hook.utils.recursive_search_git_folder`.
+Whencalled,itwillreturn'/mock/git/folder'insteadofperformingan
+actualsearch.Thisisusefulfortestingpurposeswhereyouneeda
+consistentresponsewithoutinteractingwiththefilesystem.
+
+Yields:
+MagicMock:Amockobjectthatsimulatesthe`recursive_search_git_folder`function.
+"""
+
+withpatch('penify_hook.utils.recursive_search_git_folder',create=True)asmock:
+mock.return_value='/mock/git/folder'
+yieldmock
+
+@pytest.fixture
+def[mock_print_functions](self):
+"""Mockstheprintfunctionsfrom`penify_hook.ui_utils`fortesting
+purposes.
+
+ThisfunctionusesPython's`unittest.mock.patch`toreplacetheactual
+printfunctions(`print`,`print_warning`,and`print_error`)withmock
+objects.Thesemockobjectscanbeusedinteststocapturecallsmade
+totheseprintfunctionswithoutactuallyprintinganything.
+
+Yields:
+tuple:Atuplecontainingthreemockobjectscorrespondingto`print_info`,
+`print_warning`,
+and`print_error`.
+"""
+
+withpatch('penify_hook.ui_utils.print_info',create=True)asmock_info,\
+patch('penify_hook.ui_utils.print_warning',create=True)asmock_warning,\
+patch('penify_hook.ui_utils.print_error',create=True)asmock_error:
+yieldmock_info,mock_warning,mock_error
+
+@patch('penify_hook.api_client.APIClient',create=True)
+@patch('penify_hook.llm_client.LLMClient',create=True)
+@patch('penify_hook.commit_analyzer.CommitDocGenHook',create=True)
+@patch('penify_hook.utils.recursive_search_git_folder',create=True)
+@patch('penify_hook.ui_utils.print_info',create=True)
+@patch('penify_hook.ui_utils.print_warning',create=True)
+@patch('penify_hook.ui_utils.print_error',create=True)
+def[test_commit_code_with_llm_client](self,mock_error,mock_warning,mock_info,
+mock_git_folder_search,mock_doc_gen,
+mock_llm_client,mock_api_client):
+"""TestcommittingcodeusinganLLMclient.
+
+Thisfunctionsetsupmockobjectsforvariouscomponentsandthencalls
+the`commit_code`functionwithspecifiedparameters.Itverifiesthat
+thecorrectmocksarecreatedandcalledwiththeappropriatearguments.
+
+Args:
+mock_error(MagicMock):Mockobjectforerrorhandling.
+mock_warning(MagicMock):Mockobjectforwarninglogging.
+mock_info(MagicMock):Mockobjectforinfologging.
+mock_git_folder_search(MagicMock):Mockobjecttosimulategitfoldersearch.
+mock_doc_gen(MagicMock):Mockobjectfordocumentgeneration.
+mock_llm_client(MagicMock):MockobjectforLLMclientinteraction.
+mock_api_client(MagicMock):MockobjectforAPIclientinteraction.
+"""
+
+
+api_instance=MagicMock()
+mock_api_client.return_value=api_instance
+
+llm_instance=MagicMock()
+mock_llm_client.return_value=llm_instance
+
+doc_gen_instance=MagicMock()
+mock_doc_gen.return_value=doc_gen_instance
+
+mock_git_folder_search.return_value='/mock/git/folder'
+
+
+[commit_code](
+api_url="http://api.example.com",
+token="api-token",
+message="testcommit",
+open_terminal=False,
+generate_description=True,
+llm_model="gpt-4",
+llm_api_base="http://llm-api.example.com",
+llm_api_key="llm-api-key"
+)
+
+
+mock_api_client.assert_called_once_with("http://api.example.com","api-token")
+mock_llm_client.assert_called_once_with(
+model="gpt-4",
+api_base="http://llm-api.example.com",
+api_key="llm-api-key"
+)
+mock_doc_gen.assert_called_once_with('/mock/git/folder',api_instance,llm_instance,None)
+doc_gen_instance.run.assert_called_once_with("testcommit",False,True)
+
+@patch('penify_hook.api_client.APIClient',create=True)
+@patch('penify_hook.llm_client.LLMClient',create=True)
+@patch('penify_hook.jira_client.JiraClient',create=True)
+@patch('penify_hook.commit_analyzer.CommitDocGenHook',create=True)
+@patch('penify_hook.utils.recursive_search_git_folder',create=True)
+@patch('penify_hook.ui_utils.print_info',create=True)
+@patch('penify_hook.ui_utils.print_warning',create=True)
+@patch('penify_hook.ui_utils.print_error',create=True)
+def[test_commit_code_with_jira_client](self,mock_error,mock_warning,mock_info,
+mock_git_folder_search,mock_doc_gen,
+mock_jira_client,mock_llm_client,mock_api_client):
+"""TestcommittingcodeusingaJIRAclient.
+
+Thisfunctionteststhecommit_codefunctionwithvariousparameters,
+includingAPIandJIRAcredentials.Itsetsupmockobjectsfor
+dependenciessuchastheJIRAclient,LLMclient,anddocgeneratorto
+simulatethebehavioroftherealclasses.Thefunctionthencalls
+commit_codeandverifiesthattheJIRAclientanddocgeneratorare
+calledwiththecorrectparameters.
+
+Args:
+mock_error(MagicMock):AMagicMockobjectforsimulatingerrorlogging.
+mock_warning(MagicMock):AMagicMockobjectforsimulatingwarninglogging.
+mock_info(MagicMock):AMagicMockobjectforsimulatinginfologging.
+mock_git_folder_search(MagicMock):AMagicMockobjectforsimulatingthegitfoldersearchfunction.
+mock_doc_gen(MagicMock):AMagicMockobjectforsimulatingthedocgeneratorfunction.
+mock_jira_client(MagicMock):AMagicMockobjectforsimulatingtheJIRAclientclass.
+mock_llm_client(MagicMock):AMagicMockobjectforsimulatingtheLLMclientclass.
+mock_api_client(MagicMock):AMagicMockobjectforsimulatingtheAPIclientclass.
+"""
+
+
+api_instance=MagicMock()
+mock_api_client.return_value=api_instance
+
+llm_instance=MagicMock()
+mock_llm_client.return_value=llm_instance
+
+jira_instance=MagicMock()
+jira_instance.is_connected.return_value=True
+mock_jira_client.return_value=jira_instance
+
+doc_gen_instance=MagicMock()
+mock_doc_gen.return_value=doc_gen_instance
+
+mock_git_folder_search.return_value='/mock/git/folder'
+
+
+[commit_code](
+api_url="http://api.example.com",
+token="api-token",
+message="testcommit",
+open_terminal=False,
+generate_description=True,
+llm_model="gpt-4",
+llm_api_base="http://llm-api.example.com",
+llm_api_key="llm-api-key",
+jira_url="https://jira.example.com",
+jira_user="jira-user",
+jira_api_token="jira-token"
+)
+
+
+mock_jira_client.assert_called_once_with(
+jira_url="https://jira.example.com",
+jira_user="jira-user",
+jira_api_token="jira-token"
+)
+mock_doc_gen.assert_called_once_with('/mock/git/folder',api_instance,llm_instance,jira_instance)
+
+@patch('penify_hook.api_client.APIClient',create=True)
+@patch('penify_hook.jira_client.JiraClient',create=True)
+@patch('penify_hook.commit_analyzer.CommitDocGenHook',create=True)
+@patch('penify_hook.utils.recursive_search_git_folder',create=True)
+@patch('penify_hook.ui_utils.print_info',create=True)
+@patch('penify_hook.ui_utils.print_warning',create=True)
+@patch('penify_hook.ui_utils.print_error',create=True)
+def[test_commit_code_with_jira_connection_failure](self,mock_error,mock_warning,mock_info,
+mock_git_folder_search,mock_doc_gen,
+mock_jira_client,mock_api_client):
+"""Testthecommit_codefunctionwhenJIRAconnectionfails.
+
+ThisfunctionteststhescenariowheretheJIRAconnectionfailsduring
+acodecommit.Itsetsupvariousmockstosimulatedifferentcomponents
+ofthesystemandthencallsthe`commit_code`functionwithspecific
+parameters.ThefunctionisexpectedtohandletheJIRAconnection
+failuregracefullybylogginganappropriatewarning.
+
+Args:
+mock_error(MagicMock):Mockforerrorlogging.
+mock_warning(MagicMock):Mockforwarninglogging.
+mock_info(MagicMock):Mockforinfologging.
+mock_git_folder_search(MagicMock):MockforsearchingtheGitfolder.
+mock_doc_gen(MagicMock):Mockforgeneratingdocumentation.
+mock_jira_client(MagicMock):MockforcreatingaJIRAclient.
+mock_api_client(MagicMock):MockforcreatinganAPIclient.
+"""
+
+
+api_instance=MagicMock()
+mock_api_client.return_value=api_instance
+
+jira_instance=MagicMock()
+jira_instance.is_connected.return_value=False
+mock_jira_client.return_value=jira_instance
+
+doc_gen_instance=MagicMock()
+mock_doc_gen.return_value=doc_gen_instance
+
+mock_git_folder_search.return_value='/mock/git/folder'
+
+
+[commit_code](
+api_url="http://api.example.com",
+token="api-token",
+message="testcommit",
+open_terminal=False,
+generate_description=True,
+llm_model=None,
+jira_url="https://jira.example.com",
+jira_user="jira-user",
+jira_api_token="jira-token"
+)
+
+
+mock_doc_gen.assert_called_once_with('/mock/git/folder',api_instance,None,None)
+
+@patch('penify_hook.api_client.APIClient',create=True)
+@patch('penify_hook.commit_analyzer.CommitDocGenHook',create=True)
+@patch('penify_hook.utils.recursive_search_git_folder',create=True)
+@patch('sys.exit')
+@patch('builtins.print')
+def[test_commit_code_error_handling](self,mock_print,mock_exit,
+mock_git_folder_search,mock_doc_gen,mock_api_client):
+"""Testtheerrorhandlinginthetest_commit_codefunction.
+
+Thisfunctionsetsupmockstosimulateexceptionsandtesttheerror
+handlingofthecommit_codefunction.Itverifiesthatthefunction
+correctlyprintsanerrormessageandexitswithastatuscodeof1when
+anexceptionoccursduringdocumentationgeneration.
+
+Args:
+mock_print(MagicMock):Mockfortheprintfunction,usedtoverifyerrormessageoutput.
+mock_exit(MagicMock):Mockforthesys.exitfunction,usedtoverifyexitbehavior.
+mock_git_folder_search(MagicMock):Mockforthegit_folder_searchfunction,returningamockGitfolder
+path.
+mock_doc_gen(MagicMock):Mockforthedoc_genfunction,simulatinganexceptionduring
+documentationgeneration.
+mock_api_client(MagicMock):MockfortheAPIclientclass,notdirectlyusedbutreferencedinthe
+functionsignature.
+"""
+
+
+mock_doc_gen.side_effect=[Exception]("Testerror")
+mock_git_folder_search.return_value='/mock/git/folder'
+
+
+[commit_code](
+api_url="http://api.example.com",
+token="api-token",
+message="testcommit",
+open_terminal=False,
+generate_description=True
+)
+
+mock_print.assert_called_once_with("Error:Testerror")
+mock_exit.assert_called_once_with(1)
+
+def[test_setup_commit_parser](self):
+"""Setuptheargumentparserforthecommitcommand.
+
+Thisfunctionconfiguresanargumentparsertohandlevariousoptions
+forcommittingchanges.Itaddsthreearguments:-'-m'or'--message':
+Anoptionalargumenttospecifyacontextualcommitmessagewitha
+defaultvalueof"N/A".-'-e'or'--terminal':Abooleanflagtoopen
+aneditterminalbeforecommitting.-'-d'or'--description':Aboolean
+flagthat,whensettoFalse,indicatesthegenerationofacommit
+messagewithtitleanddescription.
+
+Args:
+parser(MagicMock):Theargumentparsertobeconfigured.
+"""
+
+parser=MagicMock()
+[setup_commit_parser](parser)
+
+
+assertparser.add_argument.call_count==3
+parser.add_argument.assert_any_call("-m","--message",required=False,help="Commitwithcontextualcommitmessage.",default="N/A")
+parser.add_argument.assert_any_call("-e","--terminal",action="store_true",help="Openeditterminalbeforecommitting.")
+parser.add_argument.assert_any_call("-d","--description",action="store_false",help="Itwillgeneratecommitmessagewithtitleanddescription.",default=False)
+
+@patch('penify_hook.commands.commit_commands.get_token')
+@patch('penify_hook.commands.commit_commands.get_jira_config')
+@patch('penify_hook.commands.commit_commands.get_llm_config')
+@patch('penify_hook.commands.commit_commands.commit_code')
+@patch('penify_hook.commands.commit_commands.print_info')
+@patch('penify_hook.constants.API_URL',"http://api.example.com")
+def[test_handle_commit](self,mock_print_info,mock_commit_code,mock_get_token,
+mock_get_llm_config,mock_get_jira_config):
+"""Testthehandle_commitfunctionwithvariousmockobjects.
+
+ThisfunctionsetsupmocksforretrievingLLMconfiguration,JIRA
+configuration,andcommitcode.Itthencreatesanargumentobjectand
+callsthehandle_commitfunction.Finally,itverifiesthatthemock
+functionswerecalledwiththeexpectedarguments.
+
+Args:
+mock_print_info(MagicMock):Mockobjectforprintinginformation.
+mock_commit_code(MagicMock):Mockobjectforcommittingcode.
+mock_get_token(MagicMock):MockobjectforretrievingAPItoken.
+mock_get_llm_config(MagicMock):MockobjectforretrievingLLMconfiguration.
+mock_get_jira_config(MagicMock):MockobjectforretrievingJIRAconfiguration.
+"""
+
+
+mock_get_llm_config.return_value={
+'model':'test-model',
+'api_base':'http://llm-api.example.com',
+'api_key':'llm-key'
+}
+mock_get_token.return_value='api-token'
+mock_get_jira_config.return_value={
+'url':'https://jira.example.com',
+'username':'jira-user',
+'api_token':'jira-token'
+}
+
+
+args=MagicMock()
+args.message="testcommit"
+args.terminal=True
+args.description=True
+
+
+[handle_commit](args)
+
+
+mock_print_info.assert_called_with("GenerateCommitDescription:True")
+mock_commit_code.assert_called_once_with(
+"http://api.example.com",'api-token',"testcommit",True,True,
+'test-model','http://llm-api.example.com','llm-key',
+'https://jira.example.com','jira-user','jira-token'
+)
+
+
+
+
diff --git a/docs343/xml/test__config__commands_8py.xml b/docs343/xml/test__config__commands_8py.xml
new file mode 100644
index 0000000..cd7b938
--- /dev/null
+++ b/docs343/xml/test__config__commands_8py.xml
@@ -0,0 +1,465 @@
+
+
+
+ test_config_commands.py
+ tests::test_config_commands::TestConfigCommands
+ tests
+ tests::test_config_commands
+
+
+
+
+
+importos
+importjson
+importpytest
+fromunittest.mockimportpatch,mock_open,MagicMock
+frompathlibimportPath
+
+from[penify_hook.commands.config_commands]import(
+get_penify_config,
+get_llm_config,
+get_jira_config,
+save_llm_config,
+save_jira_config,
+get_token
+)
+
+class[TestConfigCommands]:
+
+@patch('penify_hook.commands.config_commands.recursive_search_git_folder')
+@patch('penify_hook.commands.config_commands.Path')
+@patch('os.makedirs')
+@patch('builtins.open',new_callable=mock_open)
+def[test_get_penify_config_existing_dir](self,mock_file_open,mock_makedirs,mock_path,mock_git_folder):
+"""Testtheget_penify_configfunctionwhenthe.penifyconfigdirectory
+exists.
+
+Itshouldnotcreateanewdirectoryandassertthatallmocked
+functionswerecalledcorrectly.
+
+Args:
+mock_file_open(MagicMock):AMagicMockobjectsimulatingtheopen()function.
+mock_makedirs(MagicMock):AMagicMockobjectsimulatingtheos.makedirs()function.
+mock_path(MagicMock):AMagicMockobjectsimulatingthePathclassfrompathlibmodule.
+mock_git_folder(MagicMock):AMagicMockobjectsimulatingthegit_folder_search()function.
+"""
+
+
+mock_git_folder.return_value='/mock/git/folder'
+
+
+mock_path_instance=MagicMock()
+mock_path.return_value=mock_path_instance
+mock_path_instance.__truediv__.return_value=mock_path_instance
+
+
+mock_path_instance.exists.return_value=True
+
+
+result=[get_penify_config]()
+
+
+mock_git_folder.assert_called_once_with(os.getcwd())
+mock_path.assert_called_once_with('/mock/git/folder')
+mock_path_instance.__truediv__.assert_called_with('.penify')
+assertmock_makedirs.call_count==0
+
+@patch('penify_hook.utils.recursive_search_git_folder')
+@patch('penify_hook.commands.config_commands.Path')
+@patch('os.makedirs')
+@patch('builtins.open',new_callable=mock_open)
+def[test_get_penify_config_new_dir](self,mock_file_open,mock_makedirs,mock_path,mock_git_folder):
+"""Testthebehaviorofget_penify_configwhenthe.penifydirectorydoes
+notexist.
+
+Thisfunctionmocksvarioussystemcallstosimulateascenariowhere
+the.penifydirectoryisnotpresent.Itthenassertsthatthe
+appropriateactionsaretakentocreatethedirectoryandwriteanempty
+JSONfile.
+
+Args:
+mock_file_open(MagicMock):AMagicMockobjectsimulatingthe`open`function.
+mock_makedirs(MagicMock):AMagicMockobjectsimulatingthe`os.makedirs`function.
+mock_path(MagicMock):AMagicMockobjectsimulatingthe`Path`classfrom`pathlib`.
+mock_git_folder(MagicMock):AMagicMockobjectsimulatingagitfoldersearchfunction.
+"""
+
+
+mock_git_folder.return_value='/mock/git/folder'
+
+
+mock_path_instance=MagicMock()
+mock_path.return_value=mock_path_instance
+mock_path_instance.__truediv__.return_value=mock_path_instance
+
+
+mock_path_instance.exists.side_effect=[False,False]
+
+
+result=[get_penify_config]()
+
+
+mock_makedirs.assert_called_with(mock_path_instance,exist_ok=True)
+mock_file_open.assert_called_once()
+mock_file_open().write.assert_called_once_with('{}')
+
+@patch('penify_hook.commands.config_commands.get_penify_config')
+@patch('builtins.open',new_callable=mock_open,read_data='{"llm":{"model":"gpt-4","api_base":"https://api.openai.com","api_key":"test-key"}}')
+def[test_get_llm_config_exists](self,mock_file_open,mock_get_config):
+"""Testtheget_llm_configfunctionwhentheconfigurationfileexists.
+
+Thisfunctionsetsupamockconfigurationfilethatexistsandreturns
+itwhencalled.Itthencallstheget_llm_configfunctionandasserts
+thatitreturnsthecorrectconfigurationdictionary.Additionally,it
+checksthatthemock_file_openfunctionwascalledwiththecorrect
+arguments.
+
+Args:
+mock_file_open(MagicMock):Amockfortheopen()function.
+mock_get_config(MagicMock):Amockfortheget_config()function.
+"""
+
+
+mock_config_file=MagicMock()
+mock_config_file.exists.return_value=True
+mock_get_config.return_value=mock_config_file
+
+
+result=[get_llm_config]()
+
+
+assertresult=={
+'model':'gpt-4',
+'api_base':'https://api.openai.com',
+'api_key':'test-key'
+}
+mock_file_open.assert_called_once_with(mock_config_file,'r')
+
+@patch('penify_hook.commands.config_commands.get_penify_config')
+@patch('builtins.open',new_callable=mock_open,read_data='{}')
+def[test_get_llm_config_empty](self,mock_file_open,mock_get_config):
+"""Testthebehaviorofget_llm_configwhencalledwithanempty
+configurationfile.
+
+Thisfunctionsetsupamockconfigurationfilethatexistsbutreturns
+nocontent.Itthencallsthe`get_llm_config`functionandassertsthat
+itreturnsanemptydictionaryandthatthefileopenmethodwascalled
+exactlyoncewiththecorrectarguments.
+
+Args:
+mock_file_open(MagicMock):AMagicMockobjectsimulatingthebuilt-inopenfunction.
+mock_get_config(MagicMock):AMagicMockobjectsimulatingtheget_configfunction.
+"""
+
+
+mock_config_file=MagicMock()
+mock_config_file.exists.return_value=True
+mock_get_config.return_value=mock_config_file
+
+
+result=[get_llm_config]()
+
+
+assertresult=={}
+mock_file_open.assert_called_once_with(mock_config_file,'r')
+
+@patch('penify_hook.commands.config_commands.get_penify_config')
+@patch('builtins.open',new_callable=mock_open,read_data='invalidjson')
+@patch('builtins.print')
+def[test_get_llm_config_invalid_json](self,mock_print,mock_file_open,mock_get_config):
+"""Testfunctiontoverifythebehaviorofget_llm_configwhenreadingan
+invalidJSONfile.
+
+Itsetsupamockconfigurationfilethatexistsbutcontainsinvalid
+JSON.Thefunctionisexpectedtohandlethisgracefullybyprintingan
+errormessageandreturninganemptydictionary.
+
+Args:
+mock_print(MagicMock):Mockfortheprintfunction.
+mock_file_open(MagicMock):Mockfortheopenfunction.
+mock_get_config(MagicMock):Mockfortheget_configfunction,whichreturnsthemockconfiguration
+file.
+"""
+
+
+mock_config_file=MagicMock()
+mock_config_file.exists.return_value=True
+mock_get_config.return_value=mock_config_file
+
+
+result=[get_llm_config]()
+
+
+assertresult=={}
+mock_print.assert_called_once()
+assert'Errorreading.penifyconfigfile'inmock_print.call_args[0][0]
+
+@patch('penify_hook.commands.config_commands.get_penify_config')
+@patch('builtins.open',new_callable=mock_open,read_data='{"jira":{"url":"https://jira.example.com","username":"user","api_token":"token"}}')
+def[test_get_jira_config_exists](self,mock_file_open,mock_get_config):
+"""Testthatget_jira_configreturnsthecorrectJIRAconfigurationwhen
+theconfigurationfileexists.
+
+Itsetsupamockfortheconfigurationfiletosimulateitsexistence
+andverifiesthatthefunctionreadsfromthecorrectfileandreturns
+theexpectedJIRAconfigurationdictionary.Additionally,itchecksthat
+themockfileopeniscalledwiththeappropriatearguments.
+
+Args:
+mock_file_open(MagicMock):Amockforthe`open`function.
+mock_get_config(MagicMock):Amockforthe`get_config`function,whichisexpectedtoreturnamock
+configurationfileobject.
+
+Returns:
+None:Thistestfunctiondoesnotexplicitlyreturnanything.Itsassertions
+serveastheverificationofitscorrectness.
+"""
+
+
+mock_config_file=MagicMock()
+mock_config_file.exists.return_value=True
+mock_get_config.return_value=mock_config_file
+
+
+result=[get_jira_config]()
+
+
+assertresult=={
+'url':'https://jira.example.com',
+'username':'user',
+'api_token':'token'
+}
+mock_file_open.assert_called_once_with(mock_config_file,'r')
+
+@patch('penify_hook.commands.config_commands.get_penify_config')
+@patch('builtins.open',new_callable=mock_open)
+@patch('json.dump')
+@patch('builtins.print')
+def[test_save_llm_config_success](self,mock_print,mock_json_dump,mock_file_open,mock_get_config):
+"""Testthesave_llm_configfunctionsuccessfully.
+
+Thisfunctionteststhatthesave_llm_configfunctioncorrectlysavesan
+LLMconfigurationandhandlesvariousmockobjectsandsideeffects.It
+ensuresthatthefunctionreturnsTrueuponsuccessfulexecution,writes
+theexpectedconfigurationtoafile,andprintsaconfirmationmessage.
+
+Args:
+mock_print(MagicMock):Amockobjectfortheprintfunction.
+mock_json_dump(MagicMock):Amockobjectforjson.dump.
+mock_file_open(MagicMock):Amockobjectforfileopening.
+mock_get_config(MagicMock):Amockobjecttoreturnaconfigurationfilemock.
+"""
+
+
+mock_config_file=MagicMock()
+mock_get_config.return_value=mock_config_file
+mock_file_open.return_value.__enter__.return_value=mock_file_open
+
+
+withpatch('json.load',return_value={}):
+
+result=[save_llm_config]("gpt-4","https://api.openai.com","test-key")
+
+
+assertresult==True
+mock_json_dump.assert_called_once()
+expected_config={
+'llm':{
+'model':'gpt-4',
+'api_base':'https://api.openai.com',
+'api_key':'test-key'
+}
+}
+assertmock_json_dump.call_args[0][0]==expected_config
+mock_print.assert_called_once()
+assert'configurationsaved'inmock_print.call_args[0][0]
+
+@patch('penify_hook.commands.config_commands.get_penify_config')
+@patch('builtins.open',side_effect=IOError("Permissiondenied"))
+@patch('builtins.print')
+def[test_save_llm_config_failure](self,mock_print,mock_file_open,mock_get_config):
+"""Testfunctiontoverifythatthesave_llm_configfunctionreturnsFalse
+andprintsanerrormessagewhenitfailstosavetheLLMconfiguration
+duetoapermissionerror.
+
+Itsetsupamockconfigurationfilethatexistsandcallsthe
+save_llm_configfunctionwithvalidparameters.Thefunctionisexpected
+toreturnFalseandprint"ErrorsavingLLMconfiguration:Permission
+denied"incaseofafailure.
+
+Args:
+self(TestLLMConfig):Aninstanceofthetestclass.
+mock_print(MagicMock):AMagicMockobjectrepresentingtheprintfunction,whichwillbeused
+toassertthatitwascalledwiththeexpectederrormessage.
+mock_file_open(MagicMock):AMagicMockobjectrepresentingtheopenfunction,whichisnotusedin
+thistestbutisincludedasaparameterforcompleteness.
+mock_get_config(MagicMock):AMagicMockobjectrepresentingtheget_configfunction,whichwillbe
+usedtoreturnthemockconfigurationfile.
+"""
+
+
+mock_config_file=MagicMock()
+mock_config_file.exists.return_value=True
+mock_get_config.return_value=mock_config_file
+
+
+result=[save_llm_config]("gpt-4","https://api.openai.com","test-key")
+
+
+assertresultisFalse
+mock_print.assert_called_with("ErrorsavingLLMconfiguration:Permissiondenied")
+
+@patch('penify_hook.commands.config_commands.Path')
+@patch('builtins.open',new_callable=mock_open)
+@patch('json.dump')
+@patch('builtins.print')
+def[test_save_jira_config_success](self,mock_print,mock_json_dump,mock_file_open,mock_path):
+"""Testthesave_jira_configfunctiontoensureitsavesJIRAconfiguration
+successfully.
+
+Thisfunctionsetsupmocksforvariousdependenciesandteststhe
+functionalityofsavingaJIRAconfiguration.Itassertsthatthe
+functionreturns`True`,theJSONdumpiscalledwiththecorrect
+configuration,andtheprintstatementcontainstheexpectedmessage.
+
+Args:
+mock_print(MagicMock):Mockfortheprintfunction.
+mock_json_dump(MagicMock):Mockforthejson.dumpfunction.
+mock_file_open(MagicMock):Mockfortheopenfunction.
+mock_path(MagicMock):Mockforthepathmodule.
+"""
+
+
+mock_home_dir=MagicMock()
+mock_path.home.return_value=mock_home_dir
+mock_home_dir.__truediv__.return_value=mock_home_dir
+mock_home_dir.exists.return_value=True
+
+
+withpatch('json.load',return_value={}):
+
+result=[save_jira_config]("https://jira.example.com","user","token")
+
+
+assertresult==True
+mock_json_dump.assert_called_once()
+expected_config={
+'jira':{
+'url':'https://jira.example.com',
+'username':'user',
+'api_token':'token'
+}
+}
+assertmock_json_dump.call_args[0][0]==expected_config
+mock_print.assert_called_once()
+assert'configurationsaved'inmock_print.call_args[0][0]
+
+@patch('os.getenv')
+@patch('penify_hook.commands.config_commands.Path')
+@patch('builtins.open',new_callable=mock_open,read_data='{"api_keys":"config-token"}')
+def[test_get_token_from_env](self,mock_file_open,mock_path,mock_getenv):
+"""Testretrievingatokenfromtheenvironmentvariable.
+
+Thisfunctionteststhebehaviorof`get_token`whenanenvironment
+variableisset.Itverifiesthatifthe'PENIFY_API_TOKEN'environment
+variableexists,thefunctionreturnsitsvaluewithoutattemptingto
+readafile.
+
+Args:
+mock_file_open(MagicMock):AMagicMockobjectforsimulatingfileoperations.
+mock_path(MagicMock):AMagicMockobjectforsimulatingpathoperations.
+mock_getenv(MagicMock):AMagicMockobjectforsimulatingenvironmentvariableretrieval.
+"""
+
+
+mock_getenv.return_value="env-token"
+
+
+result=[get_token]()
+
+
+assertresult=="env-token"
+mock_getenv.assert_called_once_with('PENIFY_API_TOKEN')
+
+assertmock_file_open.call_count==0
+
+@patch('os.getenv')
+@patch('penify_hook.commands.config_commands.Path')
+@patch('builtins.open',new_callable=mock_open,read_data='{"api_keys":"config-token"}')
+def[test_get_token_from_config](self,mock_file_open,mock_path,mock_getenv):
+"""Testretrievingatokenfromtheconfiguration.
+
+Thisfunctionsetsupmocksforenvironmentvariablesandconfiguration
+files,callsthe`get_token`function,andassertsitsbehavior.It
+verifiesthatwhentheenvironmentvariableisnotfound,thefunction
+readsatokenfromaconfigurationfilelocatedintheuser'shome
+directory.
+
+Args:
+mock_file_open(MagicMock):Amockforthe`open`function.
+mock_path(MagicMock):Amockforthe`pathlib.Path`class.
+mock_getenv(MagicMock):Amockforthe`os.getenv`function.
+"""
+
+
+mock_getenv.return_value=None
+
+
+mock_home_dir=MagicMock()
+mock_path.home.return_value=mock_home_dir
+mock_home_dir.__truediv__.return_value=mock_home_dir
+mock_home_dir.exists.return_value=True
+
+
+result=[get_token]()
+
+
+assertresult=="config-token"
+mock_getenv.assert_called_once_with('PENIFY_API_TOKEN')
+mock_file_open.assert_called_once_with(mock_home_dir,'r')
+
+@patch('os.getenv')
+@patch('penify_hook.commands.config_commands.Path')
+@patch('builtins.open',new_callable=mock_open,read_data='{"other_key":"value"}')
+def[test_get_token_not_found](self,mock_file_open,mock_path,mock_getenv):
+"""Testtheget_tokenfunctionwhentheAPItokenenvironmentvariableis
+notfound.
+
+Thisfunctionteststhescenariowherethe`PENIFY_API_TOKEN`
+environmentvariableisnotset.Itmockstheenvironmentvariableto
+return`None`,andverifiesthatthefunctionreturns`None`.Thetest
+alsochecksthattheenvironmentvariableisaccessedonceandthata
+fileopenoperationisattemptedonaconfigurationfilelocatedinthe
+user'shomedirectory.
+
+Args:
+mock_file_open(MagicMock):Mockforthebuilt-in`open`function.
+mock_path(MagicMock):Mockforthe`pathlib.Path`module.
+mock_getenv(MagicMock):Mockforthe`os.getenv`function.
+
+Returns:
+None:Thefunctiondoesnotreturnanything;itassertsconditionstoverify
+correctness.
+"""
+
+
+mock_getenv.return_value=None
+
+
+mock_home_dir=MagicMock()
+mock_path.home.return_value=mock_home_dir
+mock_home_dir.__truediv__.return_value=mock_home_dir
+mock_home_dir.exists.return_value=True
+
+
+result=[get_token]()
+
+
+assertresultisNone
+mock_getenv.assert_called_once_with('PENIFY_API_TOKEN')
+mock_file_open.assert_called_once_with(mock_home_dir,'r')
+
+
+
+
diff --git a/docs343/xml/test__doc__commands_8py.xml b/docs343/xml/test__doc__commands_8py.xml
new file mode 100644
index 0000000..46e88a8
--- /dev/null
+++ b/docs343/xml/test__doc__commands_8py.xml
@@ -0,0 +1,372 @@
+
+
+
+ test_doc_commands.py
+ tests
+ tests::test_doc_commands
+
+
+
+
+
+importpytest
+importsys
+importos
+fromargparseimportArgumentParser
+fromunittest.mockimportpatch,MagicMock
+
+sys.path.insert(0,os.path.abspath(os.path.join(os.path.dirname(__file__),'..')))
+
+from[penify_hook.commands.doc_commands]import(
+generate_doc,
+setup_docgen_parser,
+handle_docgen
+)
+
+
+@patch('penify_hook.file_analyzer.FileAnalyzerGenHook')
+@patch('penify_hook.git_analyzer.GitDocGenHook')
+@patch('penify_hook.folder_analyzer.FolderAnalyzerGenHook')
+@patch('penify_hook.api_client.APIClient')
+@patch('penify_hook.commands.doc_commands.os.getcwd')
+def[test_generate_doc_no_location](mock_getcwd,mock_api_client,
+mock_folder_analyzer,mock_file_analyzer,
+mock_git_analyzer):
+"""Testfunctiontogeneratedocumentationwithoutlocationinformation.
+
+ThisfunctionsetsupmocksfortheAPIclient,currentworking
+directory,andGitanalyzer.Itthencallsthe`generate_doc`function
+withafakeAPIURLandtoken.Thefunctionisexpectedtoinitialize
+theAPIclient,configuretheGitanalyzer,andrunitwithoutany
+locationinformation.
+
+Args:
+mock_getcwd(MagicMock):Mockforos.getcwd().
+mock_api_client(MagicMock):MockforcreatinganAPIclient.
+mock_folder_analyzer(MagicMock):Mockforfolderanalysis.
+mock_file_analyzer(MagicMock):Mockforfileanalysis.
+mock_git_analyzer(MagicMock):MockforGitanalyzersetup.
+"""
+
+
+mock_api_instance=MagicMock()
+mock_api_client.return_value=mock_api_instance
+mock_getcwd.return_value='/fake/current/dir'
+mock_git_instance=MagicMock()
+mock_git_analyzer.return_value=mock_git_instance
+
+
+[generate_doc]('http://api.example.com','fake-token',None)
+
+
+mock_api_client.assert_called_once_with('http://api.example.com','fake-token')
+mock_git_analyzer.assert_called_once_with('/fake/current/dir',mock_api_instance)
+mock_git_instance.run.assert_called_once()
+
+
+
+
+@patch('penify_hook.git_analyzer.GitDocGenHook')
+@patch('penify_hook.folder_analyzer.FolderAnalyzerGenHook')
+@patch('penify_hook.api_client.APIClient')
+@patch('penify_hook.api_client.APIClient')
+def[test_generate_doc_file_location](mock_api_client,mock_folder_analyzer,
+mock_file_analyzer,mock_git_analyzer):
+"""Testgeneratingadocumentationfilelocation.
+
+Thisfunctionteststheprocessofgeneratingadocumentationfile
+locationusingmockobjectsforAPIclient,folderanalyzer,file
+analyzer,andGitanalyzer.Itsetsupthenecessarymocks,callsthe
+`generate_doc`functionwithspecifiedparameters,andassertsthatthe
+appropriatemethodsonthemockobjectsarecalledasexpected.
+
+Args:
+mock_api_client(MagicMock):MockobjectfortheAPIclient.
+mock_folder_analyzer(MagicMock):Mockobjectforthefolderanalyzer.
+mock_file_analyzer(MagicMock):Mockobjectforthefileanalyzer.
+mock_git_analyzer(MagicMock):MockobjectfortheGitanalyzer.
+"""
+
+
+mock_api_instance=MagicMock()
+mock_api_client.return_value=mock_api_instance
+mock_file_instance=MagicMock()
+mock_file_analyzer.return_value=mock_file_instance
+
+
+[generate_doc]('http://api.example.com','fake-token','example.py')
+
+
+mock_api_client.assert_called_once_with('http://api.example.com','fake-token')
+mock_file_analyzer.assert_called_once_with('example.py',mock_api_instance)
+mock_file_instance.run.assert_called_once()
+mock_git_analyzer.assert_not_called()
+mock_folder_analyzer.assert_not_called()
+
+
+@patch('penify_hook.commands.doc_commands.GitDocGenHook')
+@patch('penify_hook.commands.doc_commands.FileAnalyzerGenHook')
+@patch('penify_hook.commands.doc_commands.FolderAnalyzerGenHook')
+@patch('penify_hook.api_client.APIClient')
+def[test_generate_doc_folder_location](mock_api_client,mock_folder_analyzer,
+mock_file_analyzer,mock_git_analyzer):
+"""Testthefunctiontogeneratedocumentationforafolderlocation.
+
+ItsetsupmockobjectsforAPIclient,folderanalyzer,fileanalyzer,
+andGitanalyzer,thencallsthe`generate_doc`functionwithspecified
+parameters.Finally,itassertsthatthecorrectmethodsonthemock
+objectswerecalledasexpected.
+
+Args:
+mock_api_client(MagicMock):MockobjectfortheAPIclient.
+mock_folder_analyzer(MagicMock):Mockobjectforthefolderanalyzer.
+mock_file_analyzer(MagicMock):Mockobjectforthefileanalyzer.
+mock_git_analyzer(MagicMock):MockobjectfortheGitanalyzer.
+"""
+
+
+mock_api_instance=MagicMock()
+mock_api_client.return_value=mock_api_instance
+mock_folder_instance=MagicMock()
+mock_folder_analyzer.return_value=mock_folder_instance
+
+
+[generate_doc]('http://api.example.com','fake-token','src')
+
+
+mock_api_client.assert_called_once_with('http://api.example.com','fake-token')
+mock_folder_analyzer.assert_called_once_with('src',mock_api_instance)
+mock_folder_instance.run.assert_called_once()
+mock_git_analyzer.assert_not_called()
+mock_file_analyzer.assert_not_called()
+
+
+@patch('sys.exit')
+@patch('penify_hook.commands.doc_commands.GitDocGenHook')
+@patch('penify_hook.api_client.APIClient')
+def[test_generate_doc_error_handling](mock_api_client,mock_git_analyzer,mock_exit):
+"""Generateadocumentationstringfortheprovidedcodesnippetusing
+GoogleDocstringstyle.
+
+Shortonelinedescription:Testfunctiontoensurepropererror
+handlingduringAPIcallswithGitAnalyzer.Multilinelongdescription:
+Thistestfunctionisdesignedtoverifythatthegenerate_docfunction
+handlesexceptionscorrectlywhenanerroroccursduringAPIinteraction
+withGitAnalyzer.ItsetsupamockAPIclientandamockGitanalyzer,
+causingtheanalyzertoraiseanexceptiontosimulateafailure
+condition.Thefunctionthenassertsthattheexitcodeissetto1when
+theerrorhandlingmechanismisinvoked.
+
+Args:
+mock_api_client(MagicMock):AmockobjectsimulatingtheAPIclient.
+mock_git_analyzer(MagicMock):AmockobjectsimulatingtheGitanalyzer,configuredtoraisean
+exception.
+mock_exit(MagicMock):Amockobjectrepresentingtheexitfunction,whichshouldbecalled
+withanerrorcode.
+"""
+
+
+mock_api_instance=MagicMock()
+mock_api_client.return_value=mock_api_instance
+mock_git_analyzer.side_effect=[Exception]("Testerror")
+
+
+[generate_doc]('http://api.example.com','fake-token',None)
+
+
+mock_exit.assert_called_once_with(1)
+
+
+def[test_setup_docgen_parser]():
+"""Testthesetup_docgen_parserfunctiontoensureitproperlyconfigures
+theArgumentParserfordocgenoptions.
+
+Itverifiesthattheparsercorrectlysetsupdocgenoptionsandhandles
+differentsubcommandslike'install-hook'and'uninstall-hook'.
+"""
+
+parser=ArgumentParser()
+[setup_docgen_parser](parser)
+
+
+args=parser.parse_args(['-l','test_location'])
+assertargs.location=='test_location'
+
+
+args=parser.parse_args(['install-hook','-l','hook_location'])
+assertargs.docgen_subcommand=='install-hook'
+assertargs.location=='hook_location'
+
+
+args=parser.parse_args(['uninstall-hook','-l','hook_location'])
+assertargs.docgen_subcommand=='uninstall-hook'
+assertargs.location=='hook_location'
+
+
+@patch('penify_hook.commands.doc_commands.install_git_hook')
+@patch('penify_hook.commands.doc_commands.uninstall_git_hook')
+@patch('penify_hook.commands.doc_commands.generate_doc')
+@patch('penify_hook.commands.doc_commands.get_token')
+@patch('sys.exit')
+def[test_handle_docgen_install_hook](mock_exit,mock_get_token,mock_generate_doc,
+mock_uninstall_hook,mock_install_hook):
+"""Testthehandlingofthe'install-hook'subcommand.
+
+Thisfunctionsetsupamockenvironmentwhereitsimulatesthe
+executionofthe'install-hook'subcommand.Itverifiesthatthe
+`mock_install_hook`iscalledwiththecorrectarguments,while
+`mock_generate_doc`and`mock_uninstall_hook`arenotcalled.
+
+Args:
+mock_exit(MagicMock):Mockobjectforsys.exit.
+mock_get_token(MagicMock):Mockobjecttosimulatefetchingatoken.
+mock_generate_doc(MagicMock):Mockobjecttosimulategeneratingdocumentation.
+mock_uninstall_hook(MagicMock):Mockobjecttosimulateuninstallingahook.
+mock_install_hook(MagicMock):Mockobjecttosimulateinstallingahook.
+"""
+
+
+mock_get_token.return_value='fake-token'
+
+
+args=MagicMock(docgen_subcommand='install-hook',location='hook_location')
+[handle_docgen](args)
+mock_install_hook.assert_called_once_with('hook_location','fake-token')
+mock_generate_doc.assert_not_called()
+mock_uninstall_hook.assert_not_called()
+
+
+@patch('penify_hook.commands.doc_commands.install_git_hook')
+@patch('penify_hook.commands.doc_commands.uninstall_git_hook')
+@patch('penify_hook.commands.doc_commands.generate_doc')
+@patch('penify_hook.commands.doc_commands.get_token')
+@patch('sys.exit')
+def[test_handle_docgen_uninstall_hook](mock_exit,mock_get_token,mock_generate_doc,
+mock_uninstall_hook,mock_install_hook):
+"""Testtheuninstall-hooksubcommandofthehandle_docgenfunction.
+Thistestcasesetsupamockenvironmentandverifiesthatthe
+uninstall-hookiscalledwiththecorrectlocation,whilegenerate_doc
+andinstall_hookarenotcalled.
+
+Args:
+mock_exit(MagicMock):Amockfortheexitfunction.
+mock_get_token(MagicMock):Amockfortheget_tokenfunction.
+mock_generate_doc(MagicMock):Amockforthegenerate_docfunction.
+mock_uninstall_hook(MagicMock):Amockfortheuninstall_hookfunction.
+mock_install_hook(MagicMock):Amockfortheinstall_hookfunction.
+"""
+
+
+mock_get_token.return_value='fake-token'
+
+
+args=MagicMock(docgen_subcommand='uninstall-hook',location='hook_location')
+[handle_docgen](args)
+mock_uninstall_hook.assert_called_once_with('hook_location')
+mock_generate_doc.assert_not_called()
+mock_install_hook.assert_not_called()
+
+
+@patch('penify_hook.commands.doc_commands.install_git_hook')
+@patch('penify_hook.commands.doc_commands.uninstall_git_hook')
+@patch('penify_hook.commands.doc_commands.generate_doc')
+@patch('penify_hook.commands.doc_commands.get_token')
+def[test_handle_docgen_generate](mock_get_token,mock_generate_doc,
+mock_uninstall_hook,mock_install_hook):
+"""Testthedirectdocumentationgenerationfunctionality.
+
+Thisfunctionteststhe`handle_docgen`functionwhennosubcommandis
+provided.Itverifiesthatthedocumentgenerationhookiscalledand
+theuninstallandinstallhooksarenotcalled.
+
+Args:
+mock_get_token(MagicMock):Mockedfunctiontogetauthenticationtoken.
+mock_generate_doc(MagicMock):Mockedfunctionforgeneratingdocumentation.
+mock_uninstall_hook(MagicMock):Mockedfunctionforuninstallingthedocumentgenerationhook.
+mock_install_hook(MagicMock):Mockedfunctionforinstallingthedocumentgenerationhook.
+"""
+
+
+mock_get_token.return_value='fake-token'
+
+
+args=MagicMock(docgen_subcommand=None,location='doc_location')
+[handle_docgen](args)
+mock_generate_doc.assert_called_once()
+mock_install_hook.assert_not_called()
+mock_uninstall_hook.assert_not_called()
+
+
+@patch('penify_hook.commands.doc_commands.get_token')
+@patch('sys.exit')
+def[test_handle_docgen_no_token](mock_exit,mock_get_token):
+"""Testthebehaviorofthe`handle_docgen`functionwhennotokenis
+provided.
+
+Thisfunctionassertsthatifnotokenisreturnedby`mock_get_token`,
+the`handle_docgen`functionwillcall`mock_exit`withastatuscodeof
+1.
+
+Args:
+mock_exit(MagicMock):AMagicMockobjectsimulatingthe`exit`function.
+mock_get_token(MagicMock):AMagicMockobjectsimulatingthe`get_token`function.
+"""
+
+
+mock_get_token.return_value=None
+args=MagicMock(docgen_subcommand=None,location='doc_location')
+[handle_docgen](args)
+mock_exit.assert_called_once_with(1)
+
+
+@patch('penify_hook.commands.doc_commands.os.getcwd')
+@patch('penify_hook.api_client.APIClient')
+def[test_generate_doc_with_file_exception](mock_api_client,mock_getcwd):
+"""GeneratedocumentationfromaPythonsourcefile.
+
+ThisfunctionreadsaPythonfileandgeneratesadocstringbasedonits
+content.ItusesmockobjectstosimulateAPIcallsanddirectory
+operationsduringtesting.
+
+Args:
+mock_api_client(unittest.mock.MagicMock):AmockobjectforsimulatingAPIclientbehavior.
+mock_getcwd(unittest.mock.MagicMock):Amockobjectforsimulatingthecurrentworkingdirectoryfunction.
+"""
+
+
+mock_api_client.side_effect=[Exception]("APIerror")
+mock_getcwd.return_value='/fake/current/dir'
+
+
+withpytest.raises(SystemExit):
+[generate_doc]('http://api.example.com','fake-token','example.py')
+
+
+@patch('penify_hook.commands.doc_commands.os.getcwd')
+@patch('penify_hook.api_client.APIClient')
+def[test_generate_doc_with_folder_exception](mock_api_client,mock_getcwd):
+"""GeneratedocumentationfromagivenAPIendpointandsaveittoa
+folder.
+
+ThisfunctionfetchesdatafromthespecifiedAPIendpoint,processes
+it,andsavesthegenerateddocumentationintheprovidedfolder.Ifan
+erroroccursduringthefetchingprocess,aSystemExitexceptionis
+raisedwithanappropriatemessage.
+
+Args:
+api_url(str):TheURLoftheAPIendpointfromwhichdatawillbefetched.
+token(str):TheauthenticationtokenrequiredtoaccesstheAPI.
+folder_path(str):Thepathtothefolderwherethedocumentationwillbesaved.
+"""
+
+
+mock_api_client.side_effect=[Exception]("APIerror")
+mock_getcwd.return_value='/fake/current/dir'
+
+
+withpytest.raises(SystemExit):
+[generate_doc]('http://api.example.com','fake-token','src_folder')
+
+
+
+
diff --git a/docs343/xml/test__web__config_8py.xml b/docs343/xml/test__web__config_8py.xml
new file mode 100644
index 0000000..9482cac
--- /dev/null
+++ b/docs343/xml/test__web__config_8py.xml
@@ -0,0 +1,110 @@
+
+
+
+ test_web_config.py
+ tests::test_web_config::TestWebConfig
+ tests
+ tests::test_web_config
+
+
+
+
+
+importpytest
+importjson
+importhttp.server
+importthreading
+importsocketserver
+importtime
+fromunittest.mockimportpatch,MagicMock,mock_open
+importwebbrowser
+
+from[penify_hook.commands.config_commands]importconfig_llm_web,config_jira_web
+
+
+class[TestWebConfig]:
+
+@patch('webbrowser.open')
+@patch('socketserver.TCPServer')
+@patch('pkg_resources.resource_filename')
+def[test_config_llm_web_server_setup](self,mock_resource_filename,mock_server,mock_webbrowser):
+"""SetupandtestthewebserverconfigurationforanLLM(LargeLanguage
+Model)webinterface.
+
+Thisfunctionconfiguresamockwebserverfortestingpurposes,
+includingsettingupresourcefilenames,mockingserverbehavior,and
+verifyingthatthewebbrowserisopenedandtheserverstarts
+correctly.Thefunctionusesvariousmockstosimulateexternal
+dependenciessuchas`resource_filename`and`server`.
+
+Args:
+mock_resource_filename(MagicMock):AMagicMockobjectsimulatingthe`resource_filename`function.
+mock_server(MagicMock):AMagicMockobjectsimulatingthecontextmanagerforthewebserver.
+mock_webbrowser(MagicMock):AMagicMockobjectsimulatingthe`webbrowser`module.
+"""
+
+
+mock_resource_filename.return_value='mock/template/path'
+mock_server_instance=MagicMock()
+mock_server.return_value.__enter__.return_value=mock_server_instance
+
+
+defstop_server_after_call():
+mock_server_instance.shutdown()
+mock_server_instance.serve_forever.side_effect=stop_server_after_call
+
+
+withpatch('builtins.print'):
+[config_llm_web]()
+
+
+mock_webbrowser.assert_called_once()
+assertmock_webbrowser.call_args[0][0].startswith('http://localhost:')
+
+
+mock_server.assert_called_once()
+mock_server_instance.serve_forever.assert_called_once()
+
+@patch('webbrowser.open')
+@patch('socketserver.TCPServer')
+@patch('pkg_resources.resource_filename')
+def[test_config_jira_web_server_setup](self,mock_resource_filename,mock_server,mock_webbrowser):
+"""TesttheconfigurationandsetupofaJIRAwebserver.
+
+ThisfunctionteststheentireprocessofsettingupaJIRAwebserver,
+includingmockingnecessaryresources,configuringtheservertoshut
+downafterhandlingonerequest,andverifyingthatthewebbrowseris
+openedwiththecorrectURL.Thefunctionusesseveralmockstosimulate
+externaldependenciessuchasresourcefiles,servers,andwebbrowsers.
+
+Args:
+mock_resource_filename(MagicMock):AMagicMockobjectforsimulatingthe`resource_filename`function.
+mock_server(MagicMock):AMagicMockobjectforsimulatingtheserversetup.
+mock_webbrowser(MagicMock):AMagicMockobjectforsimulatingthewebbrowseropening.
+"""
+
+
+mock_resource_filename.return_value='mock/template/path'
+mock_server_instance=MagicMock()
+mock_server.return_value.__enter__.return_value=mock_server_instance
+
+
+defstop_server_after_call():
+mock_server_instance.shutdown()
+mock_server_instance.serve_forever.side_effect=stop_server_after_call
+
+
+withpatch('builtins.print'):
+[config_jira_web]()
+
+
+mock_webbrowser.assert_called_once()
+assertmock_webbrowser.call_args[0][0].startswith('http://localhost:')
+
+
+mock_server.assert_called_once()
+mock_server_instance.serve_forever.assert_called_once()
+
+
+
+
diff --git a/docs343/xml/tests_2____init_____8py.xml b/docs343/xml/tests_2____init_____8py.xml
new file mode 100644
index 0000000..b5fdf08
--- /dev/null
+++ b/docs343/xml/tests_2____init_____8py.xml
@@ -0,0 +1,15 @@
+
+
+
+ __init__.py
+ tests
+
+
+
+
+
+
+
+
+
+
diff --git a/docs343/xml/ui__utils_8py.xml b/docs343/xml/ui__utils_8py.xml
new file mode 100644
index 0000000..52bf215
--- /dev/null
+++ b/docs343/xml/ui__utils_8py.xml
@@ -0,0 +1,263 @@
+
+
+
+ ui_utils.py
+ penify_hook
+ penify_hook::ui_utils
+
+
+
+
+
+"""
+UIutilitiesforPenifyCLI.
+
+ThismoduleprovidesutilityfunctionsforconsistentUIformatting,
+coloredoutput,andprogressindicatorsacrossthePenifyCLIapplication.
+"""
+importos
+fromcoloramaimportFore,Style,init
+fromtqdmimporttqdm
+
+
+init(autoreset=True)
+
+
+INFO_COLOR=Fore.CYAN
+SUCCESS_COLOR=Fore.GREEN
+WARNING_COLOR=Fore.YELLOW
+ERROR_COLOR=Fore.RED
+HIGHLIGHT_COLOR=Fore.BLUE
+NEUTRAL_COLOR=Fore.WHITE
+
+
+SUCCESS_SYMBOL="✓"
+WARNING_SYMBOL="â—‹"
+ERROR_SYMBOL="✗"
+PROCESSING_SYMBOL="⟳"
+
+def[format_info](message):
+"""Formataninformationalmessagewithappropriatecolor.
+
+Args:
+message(str):Thetextoftheinformationalmessagetobeformatted.
+
+Returns:
+str:Theformattedinformationalmessagewiththespecifiedcolor.
+"""
+returnf"{INFO_COLOR}{message}{Style.RESET_ALL}"
+
+def[format_success](message):
+"""Formatasuccessmessagewithappropriatecolor.
+
+ThisfunctiontakesamessageasinputandwrapsitinANSIescapecodes
+todisplayitingreen,indicatingasuccessfuloperation.The
+Style.RESET_ALLisappliedattheendtoensurethatanysubsequenttext
+isdisplayedinthedefaultstyle.
+
+Args:
+message(str):Themessagetobeformattedasasuccessmessage.
+
+Returns:
+str:Theformattedsuccessmessagewithgreencolorandresetstyle.
+"""
+returnf"{SUCCESS_COLOR}{message}{Style.RESET_ALL}"
+
+def[format_warning](message):
+"""Formatawarningmessagewithappropriatecolor.
+
+Args:
+message(str):Thewarningmessagetobeformatted.
+
+Returns:
+str:Theformattedwarningmessagewiththespecifiedcolor.
+"""
+returnf"{WARNING_COLOR}{message}{Style.RESET_ALL}"
+
+def[format_error](message):
+"""Formatanerrormessagewithappropriatecolor.
+
+ThisfunctiontakesaplainerrormessageandwrapsitinANSIescape
+codestoapplythespecifiederrorcolor,ensuringthattheerror
+messageisvisuallydistinctwhenoutput.Thefunctionsupportsvarious
+errorcolorsdefinedbyconstantslike`ERROR_COLOR`.
+
+Args:
+message(str):Theplaintexterrormessagetobeformatted.
+
+Returns:
+str:Theformattederrormessagewiththeerrorcolorapplied.
+"""
+returnf"{ERROR_COLOR}{message}{Style.RESET_ALL}"
+
+def[format_highlight](message):
+"""Formatahighlightedmessagewithappropriatecolor.
+
+Args:
+message(str):Themessagetobeformattedandhighlighted.
+
+Returns:
+str:Theformattedmessagewithappliedhighlightstyle.
+"""
+returnf"{HIGHLIGHT_COLOR}{message}{Style.RESET_ALL}"
+
+def[format_file_path](file_path):
+"""Formatafilepathwithappropriatecolor.
+
+ThisfunctiontakesafilepathasinputandwrapsitinANSIescape
+codestoapplyawarningcolor.Theoriginalfilepathisthenresetto
+defaultstyleusingStyle.RESET_ALL.
+
+Args:
+file_path(str):Thefilepathtobeformatted.
+
+Returns:
+str:Theformattedfilepathwiththewarningcolorapplied.
+"""
+returnf"{WARNING_COLOR}{file_path}{Style.RESET_ALL}"
+
+def[print_info](message):
+"""Printaninformationalmessagewithappropriateformatting.
+
+Thisfunctiontakesastringmessageasinputandprintsitina
+formattedmanner.Itutilizesthe`format_info`functiontoapplyany
+necessaryformattingbeforeprinting.
+
+Args:
+message(str):Themessagetobeprinted.
+"""
+print([format_info](message))
+
+def[print_success](message):
+"""Printaformattedsuccessmessage.
+
+Thisfunctiontakesastring`message`andprintsitasaformatted
+successmessage.Theformattingincludesaddingaprefix"Success:"to
+themessageandenclosingitwithinasterisksforemphasis.
+
+Args:
+message(str):Themessagetobeprintedasasuccessmessage.
+"""
+print([format_success](message))
+
+def[print_warning](message):
+"""Printawarningmessagewithappropriateformatting.
+
+Thisfunctiontakesawarningmessageasinputandprintsitwith
+formattedoutput.Theformattingmayincludecolor,timestamp,orother
+stylestoemphasizethatitisawarning.
+
+Args:
+message(str):Thewarningmessagetobeprinted.
+"""
+print([format_warning](message))
+
+def[print_error](message):
+"""Printanerrormessagewithappropriateformatting.
+
+Thisfunctiontakesastringmessage,formatsitasanerrormessage,
+andthenprintsit.Theformattingtypicallyincludesprefixingthe
+messagewith"Error:"toclearlyindicatethatitisanerror.
+
+Args:
+message(str):Theerrormessagetobeprinted.
+"""
+print([format_error](message))
+
+def[print_processing](file_path):
+"""Printaprocessingmessageforaspecifiedfile.
+
+Thisfunctiontakesafilepath,formatsitusing`format_file_path`,
+andthenprintsaformattedmessageindicatingthatthefileisbeing
+processed.Theformattedpathishighlightedusing`format_highlight`.
+
+Args:
+file_path(str):Thepathofthefiletobeprocessed.
+"""
+formatted_path=[format_file_path](file_path)
+print(f"\n{format_highlight(f'Processingfile:{formatted_path}')}")
+
+def[print_status](status,message):
+"""Printastatusmessagewithanappropriatesymbol.
+
+Thisfunctiontakesastatusandamessage,thenprintsthemwitha
+coloredsymbolthatcorrespondstothegivenstatus.Theavailable
+statusesare'success','warning','error',andanyothervaluewill
+defaulttoaprocessingindicator.
+
+Args:
+status(str):Thestatustype('success','warning','error')oranotherstring.
+message(str):Themessagetobedisplayedalongwiththesymbol.
+"""
+ifstatus=='success':
+print(f"{SUCCESS_COLOR}{SUCCESS_SYMBOL}{message}{Style.RESET_ALL}")
+elifstatus=='warning':
+print(f"{NEUTRAL_COLOR}{WARNING_SYMBOL}{message}{Style.RESET_ALL}")
+elifstatus=='error':
+print(f"{ERROR_COLOR}{ERROR_SYMBOL}{message}{Style.RESET_ALL}")
+else:
+print(f"{PROCESSING_SYMBOL}{message}")
+
+def[create_progress_bar](total,desc="Processing",unit="item"):
+"""Createatqdmprogressbarwithconsistentstyling.
+
+Args:
+total(int):Totalnumberofitemstoprocess.
+desc(str):Descriptionfortheprogressbar.Defaultsto"Processing".
+unit(str):Unitlabelfortheprogressitems.Defaultsto"item".
+
+Returns:
+tqdm:Aconfiguredtqdmprogressbarinstance.
+"""
+returntqdm(
+total=total,
+desc=[format_info](desc),
+unit=unit,
+ncols=80,
+ascii=True
+)
+
+def[create_stage_progress_bar](stages,desc="Processing"):
+"""Createatqdmprogressbarforprocessingstageswithconsistent
+styling.
+
+Thisfunctioninitializesandreturnsatqdmprogressbarobjectfor
+trackingtheprogressthroughaseriesofstages.Italsoprovidesa
+descriptionfortheprogressbartoenhanceitsusability.
+
+Args:
+stages(list):Alistofstringsrepresentingindividualstagesintheprocess.
+desc(str?):Adescriptionfortheprogressbar.Defaultsto"Processing".
+
+Returns:
+tuple:Atuplecontainingthetqdmprogressbarobjectandthelistofstages.
+"""
+pbar=tqdm(
+total=len(stages),
+desc=[format_info](desc),
+unit="step",
+ncols=80,
+ascii=True
+)
+returnpbar,stages
+
+def[update_stage](pbar,stage_name):
+"""Updatetheprogressbarwithanewstagename.
+
+Thisfunctionupdatestheprovidedtqdmprogressbartoreflectthe
+currentstageofaprocess.Itclearsanyexistingpostfixandsetsa
+newdescriptionbasedontheprovidedstagename.Thedisplayisthen
+refreshedtoensurethattheupdateisvisibleimmediately.
+
+Args:
+pbar(tqdm):Theprogressbarobjecttobeupdated.
+stage_name(str):Astringrepresentingthecurrentstageoftheprocess.
+"""
+
+pbar.set_postfix_str("")
+pbar.set_description_str(f"{format_info(stage_name)}")
+pbar.refresh()
+
+
+
+
diff --git a/docs343/xml/utils_8py.xml b/docs343/xml/utils_8py.xml
new file mode 100644
index 0000000..ba7e019
--- /dev/null
+++ b/docs343/xml/utils_8py.xml
@@ -0,0 +1,99 @@
+
+
+
+ utils.py
+ penify_hook::utils::GitRepoNotFoundError
+ penify_hook
+ penify_hook::utils
+
+
+
+
+
+importlogging
+importos
+importre
+
+fromgitimportRepo
+logger=logging.getLogger(__name__)
+
+
+class[GitRepoNotFoundError]([Exception]):
+pass
+
+
+def[get_repo_details](repo:Repo):
+"""DeterminethedetailsofarepositoryincludingitsremoteURL,hostingservice,organizationname,andrepositoryname."""
+remote_url=None
+hosting_service="Unknown"
+org_name=None
+repo_name=None
+
+try:
+
+remote=repo.remotes.origin.url
+remote_url=remote
+
+
+if"github.com"inremote:
+hosting_service="GITHUB"
+match=re.match(r".*github\.com[:/](.*?)/(.*?)(\.git)?$",remote)
+elif"dev.azure.com"inremote:
+hosting_service="AZUREDEVOPS"
+match=re.match(r".*dev\.azure\.com/(.*?)/(.*?)/_git/(.*?)(\.git)?$",remote)
+elif"visualstudio.com"inremote:
+hosting_service="AZUREDEVOPS"
+match=re.match(r".*@(.*?)\.visualstudio\.com/(.*?)/_git/(.*?)(\.git)?$",remote)
+elif"bitbucket.org"inremote:
+hosting_service="BITBUCKET"
+match=re.match(r".*bitbucket\.org[:/](.*?)/(.*?)(\.git)?$",remote)
+elif"gitlab.com"inremote:
+hosting_service="GITLAB"
+match=re.match(r".*gitlab\.com[:/](.*?)/(.*?)(\.git)?$",remote)
+else:
+hosting_service="UnknownHostingService"
+match=None
+
+ifmatch:
+org_name=match.group(1)
+repo_name=match.group(2)
+
+
+ifhosting_service=="AZUREDEVOPS":
+repo_name=match.group(3)
+
+exceptExceptionase:
+logger.error(f"ErrordeterminingGITprovider:{e}")
+
+return{
+"organization_name":org_name,
+"repo_name":repo_name,
+"vendor":hosting_service
+}
+
+def[recursive_search_git_folder](folder_path):
+"""Recursivelysearchesfora.gitfolderstartingfromthegivendirectory."""
+ifos.path.isdir(folder_path):
+if'.git'inos.listdir(folder_path):
+returnfolder_path
+
+eliffolder_path==os.path.dirname(folder_path):
+returnNone
+else:
+return[recursive_search_git_folder](os.path.dirname(folder_path))
+
+def[find_git_parent](path):
+
+"""Traverseupfromthegivenpathtofindthenearestdirectorycontaininga.gitsubdirectory."""
+current_dir=os.path.abspath(path)
+
+whilecurrent_dir!=os.path.dirname(current_dir):
+ifos.path.isdir(os.path.join(current_dir,".git")):
+returncurrent_dir
+current_dir=os.path.dirname(current_dir)
+
+raise[GitRepoNotFoundError](f"NoGitrepositoryfoundinthepathoranyofitsparentdirectories:{path}")
+
+
+
+
diff --git a/docs343/xml/xml.xsd b/docs343/xml/xml.xsd
new file mode 100644
index 0000000..9f80fe1
--- /dev/null
+++ b/docs343/xml/xml.xsd
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+