This is an automated email from the ASF dual-hosted git repository.
rawkintrevo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git
The following commit(s) were added to refs/heads/main by this push:
new ac5c51347 MAHOUT-506: Add gofannon PR Review (#514)
ac5c51347 is described below
commit ac5c5134729be9aa27640585db800a73eb08cd54
Author: Trevor Grant <[email protected]>
AuthorDate: Tue Mar 11 21:15:11 2025 -0500
MAHOUT-506: Add gofannon PR Review (#514)
* Add gofannon PR Review
* Added ASF License Headers
---
.github/scripts/checks/__init__.py | 16 +++++
.github/scripts/checks/general_review.py | 119 +++++++++++++++++++++++++++++++
.github/scripts/review_pr.py | 46 ++++++++++++
.github/workflows/pr_review.yml | 47 ++++++++++++
4 files changed, 228 insertions(+)
diff --git a/.github/scripts/checks/__init__.py
b/.github/scripts/checks/__init__.py
new file mode 100644
index 000000000..cce3acad3
--- /dev/null
+++ b/.github/scripts/checks/__init__.py
@@ -0,0 +1,16 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
diff --git a/.github/scripts/checks/general_review.py
b/.github/scripts/checks/general_review.py
new file mode 100644
index 000000000..9215e5a1f
--- /dev/null
+++ b/.github/scripts/checks/general_review.py
@@ -0,0 +1,119 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import ast
+from github import Github
+
+class GeneralReviewCheck:
+ def __init__(self, client, model_name):
+ self.client = client
+ self.model_name = model_name
+
+ def process_pr_file(self, file, repo, pr):
+ comments = []
+ analyzed = False
+
+ if file.filename.endswith('.py'):
+ analyzed = True
+ content = repo.get_contents(file.filename,
ref=pr.head.sha).decoded_content.decode()
+
+ # Basic code analysis
+ try:
+ tree = ast.parse(content)
+ analysis = self.analyze_code_structure(tree)
+ if analysis:
+ comments.append({
+ "path": file.filename,
+ "body": analysis,
+ "line": 1
+ })
+ except SyntaxError as e:
+ comments.append({
+ "path": file.filename,
+ "body": f"⚠️ Syntax error found:\n{e}",
+ "line": 1
+ })
+
+ return comments, analyzed
+
+ def analyze_code_structure(self, tree):
+ analysis = []
+
+ # Check for large classes
+ for node in ast.walk(tree):
+ if isinstance(node, ast.ClassDef):
+ methods = [n for n in node.body if isinstance(n,
ast.FunctionDef)]
+ if len(methods) > 10:
+ analysis.append(f"- Class '{node.name}' has {len(methods)}
methods. Consider splitting into smaller classes.")
+
+ # Check for long functions
+ for node in ast.walk(tree):
+ if isinstance(node, ast.FunctionDef):
+ lines = node.end_lineno - node.lineno if node.end_lineno else 0
+ if lines > 50:
+ analysis.append(f"- Function '{node.name}' is {lines}
lines long. Consider breaking it into smaller functions.")
+
+ # Check for TODO comments
+ for node in ast.walk(tree):
+ if isinstance(node, ast.Expr) and isinstance(node.value,
ast.Constant):
+ if isinstance(node.value.value, str) and 'TODO' in
node.value.value.upper():
+ analysis.append(f"- TODO comment found:
{node.value.value}")
+
+ if analysis:
+ return "🔍 Code structure analysis:\n" + "\n".join(analysis)
+ return None
+
+ def generate_general_impression(self, pr):
+ prompt = f"""Provide a general impression of this pull request.
Consider:
+- Overall code quality
+- Code organization
+- Documentation
+- Potential improvements
+- Areas that need special attention
+
+Pull Request Details:
+Title: {pr.title}
+Description: {pr.body}
+Files Changed: {pr.changed_files}
+Additions: {pr.additions}
+Deletions: {pr.deletions}
+
+Provide your analysis in markdown format with these sections:
+1. Overall Impression
+2. Strengths
+3. Areas for Improvement
+4. Special Attention Needed"""
+
+ response = self.client.chat.completions.create(
+ model=self.model_name,
+ messages=[{
+ "role": "system",
+ "content": "You are an experienced code reviewer. Provide a
high-level analysis of pull requests."
+ }, {
+ "role": "user",
+ "content": prompt
+ }]
+ )
+
+ return response.choices[0].message.content
+
+ def process_pr(self, pr):
+ general_analysis = self.generate_general_impression(pr)
+ return [{
+ "path": "GENERAL",
+ "body": general_analysis,
+ "line": 0
+ }], True
diff --git a/.github/scripts/review_pr.py b/.github/scripts/review_pr.py
new file mode 100644
index 000000000..5b283433b
--- /dev/null
+++ b/.github/scripts/review_pr.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os
+import sys
+from github import Github
+from gofannon.github.pr_review_tool import PRReviewTool
+
+def check_env_vars():
+ required_vars = [
+ 'GITHUB_TOKEN', 'OPENAI_API_KEY', 'OPENAI_BASE_URL',
'OPENAI_MODEL_NAME', 'PR_NUMBER', 'REPO_NAME'
+ ]
+ for var in required_vars:
+ if not os.environ.get(var):
+ sys.exit(f"Error: Required environment variable '{var}' is
missing.")
+
+check_env_vars()
+
+def main():
+ pr_number = int(os.environ['PR_NUMBER'])
+ repo_name = os.environ['REPO_NAME']
+ pr_review_tool = PRReviewTool()
+ review_summary = pr_review_tool.fn(pr_number=pr_number,
repo_name=repo_name)
+
+ # Post the review comment to the pull request using PyGithub.
+ g = Github(os.environ['GITHUB_TOKEN'])
+ repo = g.get_repo(repo_name)
+ pr = repo.get_pull(pr_number)
+ pr.create_issue_comment(review_summary)
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/pr_review.yml b/.github/workflows/pr_review.yml
new file mode 100644
index 000000000..fafc1f446
--- /dev/null
+++ b/.github/workflows/pr_review.yml
@@ -0,0 +1,47 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+name: PR Tool Review
+on:
+ pull_request_target:
+ types: [labeled]
+
+jobs:
+ review:
+ if: github.event.label.name == 'run-tests'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out base repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.10'
+ - name: Install Gofannon
+ run: |
+ pip install gofannon
+ - name: Run PR Review Tool
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+ OPENAI_BASE_URL: "https://api.deepinfra.com/v1/openai"
+ OPENAI_MODEL_NAME: "meta-llama/Llama-3.3-70B-Instruct-Turbo"
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ REPO_NAME: ${{ github.repository }}
+ run: |
+ poetry run python .github/scripts/review_pr.py