From f306faab16db6e6c797dea11c19dbb2b1b24632e Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Mon, 21 Apr 2025 11:02:21 +0200 Subject: [PATCH] Check the current code quality --- aider_gitea/__init__.py | 111 ++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/aider_gitea/__init__.py b/aider_gitea/__init__.py index 2288fc2..210519c 100644 --- a/aider_gitea/__init__.py +++ b/aider_gitea/__init__.py @@ -151,7 +151,8 @@ AIDER_LINT = bash_cmd( LLM_MESSAGE_FORMAT = """/code {issue}""" -MODEL = 'ollama/gemma3:27b' +#MODEL = 'ollama/gemma3:27b' +MODEL = 'ollama/gemma3:4b' def create_aider_command(issue: str) -> list[str]: l = [ @@ -167,8 +168,6 @@ def create_aider_command(issue: str) -> list[str]: AIDER_LINT, '--auto-test', '--no-auto-lint', - '--read', - 'CONVENTIONS.md', '--message', LLM_MESSAGE_FORMAT.format(issue=issue), '--yes', @@ -177,6 +176,10 @@ def create_aider_command(issue: str) -> list[str]: for key in secrets.llm_api_keys(): l += ['--api-key', key] + if False: + l.append('--read') + l.append('CONVENTIONS.md') + if True: l.append('--cache-prompts') @@ -215,6 +218,18 @@ def get_commit_messages(cwd: Path, base_branch: str, current_branch: str) -> lis return [] +def get_diff(cwd: Path, base_branch: str, current_branch: str) -> str: + result = subprocess.run( + ['git', 'diff', f'{base_branch}..{current_branch}', '--pretty=format:%s'], + check=True, + cwd=cwd, + capture_output=True, + text=True, + ) + return result.stdout.strip() + + + def push_changes( repository_config: RepositoryConfig, cwd: Path, @@ -293,9 +308,68 @@ def run_cmd(cmd: list[str], cwd: Path | None = None, check=True) -> bool: result = subprocess.run(cmd, check=check, cwd=cwd) return result.returncode == 0 +def issue_solution_round(repository_path, issue_content): + # Primary Aider command + aider_did_not_crash = run_cmd( + create_aider_command(issue_content), + repository_path, + check=False, + ) + if not aider_did_not_crash: + return aider_did_not_crash -SKIP_AIDER = False + # Auto-fix standard code quality stuff after aider + run_cmd(['bash', '-c', RUFF_FORMAT_AND_AUTO_FIX], repository_path, check=False) + run_cmd(['git', 'add', '.'], repository_path) + run_cmd(['git', 'commit', '-m', 'Ruff after aider'], repository_path, check=False) + return True + +def run_ollama(cwd: Path, texts: list[str]) -> str: + cmd = ['ollama', 'run', MODEL.removeprefix('ollama/')] + print(cmd) + process = subprocess.Popen( + cmd, + cwd=cwd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + stdout, stderr = process.communicate('\n'.join(texts)) + return stdout + +def run_ollama_and_get_yes_or_no(cwd, initial_texts: list[str]) -> bool: + texts = list(initial_texts) + texts.append('Think through your answer, and end it with "yes" or "no".') + while True: + result = run_ollama(cwd, texts).lower().removesuffix('.').strip() + print(result) + if result.endswith('yes'): + return True + elif result.endswith('no'): + return False + else: + texts.append(result) + texts.append('Please answer either yes or no.') + +def verify_solution(repository_path: Path, issue_content: str) -> bool: + summary = run_ollama( + repository_path, + ['Concisely summarize following changeset', + get_diff(repository_path, 'HEAD', 'main') + ]) + + print(summary) + + return run_ollama_and_get_yes_or_no( + repository_path, + ['Does this changeset the task?', + '# Change set', + summary, + '# Issue', + issue_content, + ]) def solve_issue_in_repository( repository_config: RepositoryConfig, @@ -312,7 +386,7 @@ def solve_issue_in_repository( run_cmd(['git', 'clone', repository_config.repo_url(), repository_path]) run_cmd(['bash', '-c', AIDER_TEST], repository_path) run_cmd(['git', 'checkout', repository_config.base_branch], repository_path) - run_cmd(['git', 'checkout', branch_name], repository_path) + run_cmd(['git', 'checkout', '-b', branch_name], repository_path) # Run initial ruff pass before aider run_cmd(['bash', '-c', RUFF_FORMAT_AND_AUTO_FIX], repository_path, check=False) @@ -330,26 +404,19 @@ def solve_issue_in_repository( # Run aider issue_content = f'# {issue_title}\n{issue_description}' - if not SKIP_AIDER: - succeeded = run_cmd( - create_aider_command(issue_content), - repository_path, - check=False, - ) - else: - logger.warning('Skipping aider command (for testing)') - succeeded = True - if not succeeded: - logger.error('Aider invocation failed for issue #%s', issue_number) - return IssueResolution(False) - # Auto-fix standard code quality stuff after aider - run_cmd(['bash', '-c', RUFF_FORMAT_AND_AUTO_FIX], repository_path, check=False) - run_cmd(['git', 'add', '.'], repository_path) - run_cmd(['git', 'commit', '-m', 'Ruff after aider'], repository_path, check=False) + while True: + aider_did_not_crash = issue_solution_round(repository_path, issue_content) + if not aider_did_not_crash: + logger.error('Aider invocation failed for issue #%s', issue_number) + return IssueResolution(False) + + # Verify whether this is a satisfactory solution + if verify_solution(repository_path, issue_content): + break # Check if aider made any changes beyond the initial ruff pass - if not has_commits_on_branch(repository_path, repository_config.base_branch, branch_name) and not SKIP_AIDER: + if not has_commits_on_branch(repository_path, repository_config.base_branch, branch_name): logger.info( 'Aider did not make any changes beyond the initial ruff pass for issue #%s', issue_number,