Skip to content

Commit dd3ac63

Browse files
committed
🔨 refactor(ai): refactor ai commit generation flow
1 parent fd4d632 commit dd3ac63

File tree

1 file changed

+46
-19
lines changed

1 file changed

+46
-19
lines changed

tgit/commit.py

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
NUMSTAT_PARTS = 3
4242
NAME_STATUS_PARTS = 2
4343
RENAME_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:
7171
class PotentialSecret(BaseModel):
7272
file: str
7373
description: str
74-
level: str = SECRET_LEVEL_ERROR
74+
level: str = SENSITIVITY_LEVEL_ERROR
7575

7676

7777
class 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

Comments
 (0)