|
7 | 7 | import os |
8 | 8 | import sys |
9 | 9 |
|
10 | | -import google.generativeai as genai |
| 10 | +import google.genai as genai |
11 | 11 | import requests |
12 | 12 | from github import Github, GithubException |
13 | 13 |
|
@@ -127,7 +127,7 @@ def get_pr_diff(self): |
127 | 127 | "body": pr.body or "", |
128 | 128 | "diff": diff_text, |
129 | 129 | } |
130 | | - except (GithubException, requests.RequestException) as e: |
| 130 | + except (GithubException, requests.RequestException, ValueError) as e: |
131 | 131 | print(f"Error getting PR diff: {e}") |
132 | 132 |
|
133 | 133 | return None |
@@ -164,38 +164,38 @@ def analyze_with_gemini(self, build_logs, pr_diff, workflow_yaml): |
164 | 164 | # Gemini prompt - ignore line length for readability |
165 | 165 | context = f""" |
166 | 166 | ### ROLE |
167 | | -You are the "Automated Maintainer Gatekeeper." Your goal is to analyze Pull Request (PR) build failures and provide direct, technically accurate, and no-nonsense feedback to contributors. |
| 167 | +You are the "Automated Maintainer Gatekeeper." Your goal is to analyze Pull Request (PR) build failures and provide direct, technically accurate, and no-nonsense feedback to contributors. # noqa: E501 |
168 | 168 |
|
169 | 169 | ### INPUT CONTEXT PROVIDED |
170 | 170 | 1. **Build Output/Logs:** {build_logs_json} |
171 | 171 | 2. **YAML Workflow:** {workflow_yaml or "Not available"} |
172 | 172 | 3. **PR Diff:** {pr_diff_json} |
173 | | -4. **Project Name:** {project_name} |
| 173 | +4. **Project Name:** {project_name} # noqa: E501 |
174 | 174 | 5. **Repository:** {repo_url} |
175 | | -6. **run-qa-checks:** {qa_checks_url} |
176 | | -7. **runtests:** {runtests_url} |
| 175 | +6. **run-qa-checks:** {qa_checks_url} # noqa: E501 |
| 176 | +7. **runtests:** {runtests_url} # noqa: E501 |
177 | 177 |
|
178 | 178 | ### TASK |
179 | | -Analyze the provided context to determine why the build failed. Categorize the failure and respond according to the "Tone Guidelines" below. |
| 179 | +Analyze the provided context to determine why the build failed. Categorize the failure and respond according to the "Tone Guidelines" below. # noqa: E501 |
180 | 180 |
|
181 | 181 | ### TONE GUIDELINES |
182 | 182 | - **Direct & Honest:** Do not use "fluff" or overly polite corporate language. |
183 | 183 | - **Firm Standards:** If a PR is low-effort, spammy, or fails to follow basic instructions, state that clearly. |
184 | | -- **Action-Oriented:** Provide the exact command or file change needed to fix the error, unless the PR is spammy, in which case we should just declare the PR as potential SPAM and ask maintainers to manually review it. |
| 184 | +- **Action-Oriented:** Provide the exact command or file change needed to fix the error, unless the PR is spammy, in which case we should just declare the PR as potential SPAM and ask maintainers to manually review it. # noqa: E501 |
185 | 185 |
|
186 | 186 | ### RESPONSE STRUCTURE |
187 | 187 | 1. **Status Summary:** A one-sentence blunt assessment of the failure. |
188 | 188 | 2. **Technical Diagnosis:** |
189 | 189 | - Identify the specific line/test that failed. |
190 | 190 | - Explain *why* it failed. |
191 | 191 | 3. **Required Action:** Provide a code block or specific steps the contributor must take. |
192 | | -4. **Quality Warning (If Applicable):** If the PR appears to be "spam" (e.g., trivial README changes, AI-generated nonsense, or repeated basic errors), include a firm statement that such contributions are a drain on project resources and ping the maintainers asking them for manual review. |
| 192 | +4. **Quality Warning (If Applicable):** If the PR appears to be "spam" (e.g., trivial README changes, AI-generated nonsense, or repeated basic errors), include a firm statement that such contributions are a drain on project resources and ping the maintainers asking them for manual review. # noqa: E501 |
193 | 193 |
|
194 | 194 | ### EXAMPLE RESPONSE STYLE |
195 | | -"The build failed because you neglected to update the test suite to match your logic changes. This project does not accept functional changes without corresponding test updates. Refer to the log at line 452. Update tests/logic_test.py before re-submitting. We prioritize high-quality, ready-to-merge code; please ensure you run local tests before pushing." |
| 195 | +"The build failed because you neglected to update the test suite to match your logic changes. This project does not accept functional changes without corresponding test updates. Refer to the log at line 452. Update tests/logic_test.py before re-submitting. We prioritize high-quality, ready-to-merge code; please ensure you run local tests before pushing." # noqa: E501 |
196 | 196 |
|
197 | 197 | Analyze the failure and provide your response: |
198 | | -""" # noqa: E501 |
| 198 | +""" |
199 | 199 |
|
200 | 200 | try: |
201 | 201 | response = self.model.generate_content(context) |
@@ -251,37 +251,56 @@ def post_comment(self, message): |
251 | 251 |
|
252 | 252 | def run(self): |
253 | 253 | """Main execution flow""" |
254 | | - print("CI Failure Bot starting - AI-powered analysis") |
255 | | - |
256 | | - # Double-check: Skip if this is a dependabot PR |
257 | 254 | try: |
258 | | - workflow_run = self.repo.get_workflow_run(self.workflow_run_id) |
259 | | - if workflow_run.actor and "dependabot" in workflow_run.actor.login.lower(): |
260 | | - print(f"Skipping dependabot PR from {workflow_run.actor.login}") |
| 255 | + print("CI Failure Bot starting - AI-powered analysis") |
| 256 | + |
| 257 | + # Double-check: Skip if this is a dependabot PR |
| 258 | + try: |
| 259 | + workflow_run = self.repo.get_workflow_run(self.workflow_run_id) |
| 260 | + if ( |
| 261 | + workflow_run.actor |
| 262 | + and "dependabot" in workflow_run.actor.login.lower() |
| 263 | + ): |
| 264 | + print(f"Skipping dependabot PR from {workflow_run.actor.login}") |
| 265 | + return |
| 266 | + except (GithubException, AttributeError) as e: |
| 267 | + print(f"Warning: Could not check actor: {e}") |
| 268 | + |
| 269 | + # Get all context |
| 270 | + build_logs = self.get_build_logs() |
| 271 | + pr_diff = self.get_pr_diff() |
| 272 | + workflow_yaml = self.get_workflow_yaml() |
| 273 | + |
| 274 | + if not build_logs: |
| 275 | + print("No build logs found") |
261 | 276 | return |
262 | | - except (GithubException, AttributeError) as e: |
263 | | - print(f"Warning: Could not check actor: {e}") |
264 | 277 |
|
265 | | - # Get all context |
266 | | - build_logs = self.get_build_logs() |
267 | | - pr_diff = self.get_pr_diff() |
268 | | - workflow_yaml = self.get_workflow_yaml() |
| 278 | + print("Analyzing failure with Gemini AI...") |
269 | 279 |
|
270 | | - if not build_logs: |
271 | | - print("No build logs found") |
272 | | - return |
| 280 | + # Get AI analysis |
| 281 | + ai_response = self.analyze_with_gemini(build_logs, pr_diff, workflow_yaml) |
273 | 282 |
|
274 | | - print("Analyzing failure with Gemini AI...") |
| 283 | + # Post intelligent comment |
| 284 | + self.post_comment(ai_response) |
275 | 285 |
|
276 | | - # Get AI analysis |
277 | | - ai_response = self.analyze_with_gemini(build_logs, pr_diff, workflow_yaml) |
| 286 | + print("CI Failure Bot completed successfully") |
278 | 287 |
|
279 | | - # Post intelligent comment |
280 | | - self.post_comment(ai_response) |
| 288 | + except Exception as e: |
| 289 | + print(f"CRITICAL ERROR in CI Failure Bot: {e}") |
| 290 | + print(f"Error type: {type(e).__name__}") |
| 291 | + import traceback |
281 | 292 |
|
282 | | - print("CI Failure Bot completed") |
| 293 | + traceback.print_exc() |
| 294 | + sys.exit(1) |
283 | 295 |
|
284 | 296 |
|
285 | 297 | if __name__ == "__main__": |
286 | | - bot = CIFailureBot() |
287 | | - bot.run() |
| 298 | + try: |
| 299 | + bot = CIFailureBot() |
| 300 | + bot.run() |
| 301 | + except Exception as e: |
| 302 | + print(f"FATAL: CI Failure Bot crashed: {e}") |
| 303 | + import traceback |
| 304 | + |
| 305 | + traceback.print_exc() |
| 306 | + sys.exit(1) |
0 commit comments