4141NUMSTAT_PARTS = 3
4242NAME_STATUS_PARTS = 2
4343RENAME_STATUS_PARTS = 3
44- SECRET_LEVEL_WARNING = "warning"
45- SECRET_LEVEL_ERROR = "error"
44+ SENSITIVITY_LEVEL_WARNING = "warning"
45+ SENSITIVITY_LEVEL_ERROR = "error"
4646
4747
4848# Initialize commit types from settings
@@ -71,7 +71,7 @@ class TemplateParams:
7171class PotentialSecret (BaseModel ):
7272 file : str
7373 description : str
74- level : str = SECRET_LEVEL_ERROR
74+ level : str = SENSITIVITY_LEVEL_ERROR
7575
7676
7777class CommitData (BaseModel ):
@@ -219,14 +219,15 @@ def _generate_commit_with_ai(diff: str, specified_type: str | None, current_bran
219219 return chat_completion .output_parsed
220220
221221
222- def get_ai_command (specified_type : str | None = None ) -> str | None :
223- current_dir = Path .cwd ()
222+ def _get_repo_for_ai (current_dir : Path ) -> git .Repo | None :
224223 try :
225- repo = git .Repo (current_dir , search_parent_directories = True )
224+ return git .Repo (current_dir , search_parent_directories = True )
226225 except git .InvalidGitRepositoryError :
227226 print ("[yellow]Not a git repository[/yellow]" )
228227 return None
229228
229+
230+ def _build_diff_for_ai (repo : git .Repo ) -> str | None :
230231 files_to_include , lock_files = get_filtered_diff_files (repo )
231232 if not files_to_include and not lock_files :
232233 print ("[yellow]No files to commit, please add some files before using AI[/yellow]" )
@@ -237,12 +238,15 @@ def get_ai_command(specified_type: str | None = None) -> str | None:
237238 diff += f"[INFO] The following lock files were modified but are not included in the diff: { ', ' .join (lock_files )} \n "
238239 if files_to_include :
239240 diff += repo .git .diff ("--cached" , "-M" , "--" , * files_to_include )
240- current_branch = repo .active_branch .name
241241
242242 if not diff :
243243 print ("[yellow]No changes to commit, please add some changes before using AI[/yellow]" )
244244 return None
245245
246+ return diff
247+
248+
249+ def _get_ai_response (diff : str , specified_type : str | None , current_branch : str ) -> CommitData | None :
246250 try :
247251 resp = _generate_commit_with_ai (diff , specified_type , current_branch )
248252 if resp is None :
@@ -252,10 +256,18 @@ def get_ai_command(specified_type: str | None = None) -> str | None:
252256 print ("[red]Could not connect to AI provider[/red]" )
253257 print (e )
254258 return None
259+ return resp
255260
256- detected_secrets : list [PotentialSecret ] = resp .secrets if resp .secrets else []
257- warning_secrets = [secret for secret in detected_secrets if secret .level == SECRET_LEVEL_WARNING ]
258- error_secrets = [secret for secret in detected_secrets if secret .level != SECRET_LEVEL_WARNING ]
261+
262+ def _is_warning_level (level : str ) -> bool :
263+ return level .lower () == SENSITIVITY_LEVEL_WARNING
264+
265+
266+ def _confirm_detected_secrets (secrets : list [PotentialSecret ]) -> bool :
267+ if not secrets :
268+ return True
269+ warning_secrets = [secret for secret in secrets if _is_warning_level (secret .level )]
270+ error_secrets = [secret for secret in secrets if not _is_warning_level (secret .level )]
259271 if warning_secrets :
260272 print ("[yellow]Detected potential sensitive key names (no values):[/yellow]" )
261273 for secret in warning_secrets :
@@ -264,15 +276,30 @@ def get_ai_command(specified_type: str | None = None) -> str | None:
264276 print ("[red]Detected potential secrets in these files:[/red]" )
265277 for secret in error_secrets :
266278 print (f"[red]- { secret .file } : { secret .description } [/red]" )
267- proceed = click .confirm ("Detected potential secrets. Continue with commit?" , default = False )
268- if not proceed :
269- print ("[yellow]Commit aborted. Please review sensitive content.[/yellow]" )
270- return None
271- elif warning_secrets :
272- proceed = click .confirm ("Detected potential sensitive key names. Continue with commit?" , default = True )
273- if not proceed :
274- print ("[yellow]Commit aborted. Please review sensitive content.[/yellow]" )
275- return None
279+ return click .confirm ("Detected potential secrets. Continue with commit?" , default = False )
280+ if warning_secrets :
281+ return click .confirm ("Detected potential sensitive key names. Continue with commit?" , default = True )
282+ return True
283+
284+
285+ def get_ai_command (specified_type : str | None = None ) -> str | None :
286+ repo = _get_repo_for_ai (Path .cwd ())
287+ if repo is None :
288+ return None
289+
290+ diff = _build_diff_for_ai (repo )
291+ if diff is None :
292+ return None
293+
294+ current_branch = repo .active_branch .name
295+ resp = _get_ai_response (diff , specified_type , current_branch )
296+ if resp is None :
297+ return None
298+
299+ detected_secrets : list [PotentialSecret ] = resp .secrets if resp .secrets else []
300+ if not _confirm_detected_secrets (detected_secrets ):
301+ print ("[yellow]Commit aborted. Please review sensitive content.[/yellow]" )
302+ return None
276303
277304 # 如果用户指定了类型,则使用用户指定的类型,否则使用 AI 生成的类型
278305 commit_type = specified_type if specified_type is not None else resp .type
0 commit comments