-
Notifications
You must be signed in to change notification settings - Fork 15
add : automated repo analysis and one-click PR creation for Watchflow rules #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add : automated repo analysis and one-click PR creation for Watchflow rules #31
Conversation
Summary of ChangesHello @naaa760, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a powerful new feature that automates the process of generating and deploying Watchflow rules. By analyzing a given GitHub repository's structure and history, the system can now recommend relevant rules and, with a single action, create a pull request to integrate these rules directly into the repository. This significantly reduces the manual effort required to set up and maintain code quality and process enforcement, making it easier for teams to adopt and benefit from Watchflow. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
Codecov Report❌ Patch coverage is ❌ Your patch status has failed because the patch coverage (51.4%) is below the target coverage (80.0%). You can increase the patch coverage or adjust the target coverage. @@ Coverage Diff @@
## main #31 +/- ##
=======================================
+ Coverage 32.0% 33.3% +1.2%
=======================================
Files 85 85
Lines 5001 5048 +47
=======================================
+ Hits 1604 1684 +80
+ Misses 3397 3364 -33 Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant new feature for automated repository analysis and one-click pull request creation for Watchflow rules. The changes are extensive, refactoring the RepositoryAnalysisAgent to a simpler procedural flow, enhancing data models with Pydantic for better validation, and extending the GitHub client to support the new functionality with both installation and user tokens. The new API endpoints are well-structured and include tests. I've provided a few suggestions to improve logging for better debuggability, simplify data models by removing redundant validators, and align more closely with the GitHub API documentation for status code checks. Overall, this is a solid contribution that adds valuable capabilities.
| except Exception as exc: # noqa: BLE001 | ||
| latency_ms = int((time.perf_counter() - started_at) * 1000) | ||
| return AgentResult( | ||
| success=False, | ||
| message=f"Repository analysis failed: {str(e)}", | ||
| message=f"Repository analysis failed: {exc}", | ||
| data={}, | ||
| metadata={ | ||
| "execution_time_ms": execution_time * 1000, | ||
| "error_type": type(e).__name__, | ||
| }, | ||
| metadata={"execution_time_ms": latency_ms}, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This except block catches a broad Exception, which can make debugging difficult. The noqa comment indicates this is intentional, but it's crucial to log the full traceback to diagnose issues. Currently, there's no logger instance in this file to do so. I recommend re-introducing the logger (e.g., import logging; logger = logging.getLogger(__name__) at the module level) and using logger.error with exc_info=True to capture the full context of the failure. This will significantly improve debuggability.
| @model_validator(mode="after") | ||
| def populate_full_name(self) -> "RepositoryAnalysisRequest": | ||
| if not self.repository_full_name and self.repository_url: | ||
| self.repository_full_name = parse_github_repo_identifier(self.repository_url) | ||
| return self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @model_validator(mode="after") | ||
| def populate_full_name(self) -> "ProceedWithPullRequestRequest": | ||
| if not self.repository_full_name and self.repository_url: | ||
| self.repository_full_name = parse_github_repo_identifier(self.repository_url) | ||
| return self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| async def analyze_repository_structure(state: RepositoryAnalysisState) -> None: | ||
| """Collect repository metadata and structure signals.""" | ||
| repo = state.repository_full_name | ||
| installation_id = state.installation_id | ||
|
|
||
| repo_data = await github_client.get_repository(repo, installation_id=installation_id) | ||
| workflows = await github_client.list_directory_any_auth( | ||
| repo_full_name=repo, path=".github/workflows", installation_id=installation_id | ||
| ) | ||
| contributors = await github_client.get_repository_contributors(repo, installation_id) if installation_id else [] | ||
|
|
||
| state.repository_features = RepositoryFeatures( | ||
| has_contributing=False, | ||
| has_codeowners=bool(await github_client.get_file_content(repo, ".github/CODEOWNERS", installation_id)), | ||
| has_workflows=bool(workflows), | ||
| workflow_count=len(workflows or []), | ||
| language=(repo_data or {}).get("language"), | ||
| contributor_count=len(contributors), | ||
| pr_count=0, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function and others in this file make external API calls but lack logging. The previous implementation had logging for each step, which is very useful for debugging and monitoring the agent's progress. I recommend adding structured logging back into these node functions to provide visibility into the analysis process, especially for successes, failures, and key findings (e.g., number of workflows found). This would greatly improve observability.
| payload = {"ref": f"refs/heads/{ref.lstrip('refs/heads/')}", "sha": sha} | ||
| session = await self._get_session() | ||
| async with session.post(url, headers=headers, json=payload) as response: | ||
| return response.status in (200, 201) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The success check response.status in (200, 201) includes 200 OK. However, the GitHub API documentation for creating a git ref (POST /repos/{owner}/{repo}/git/refs) only specifies 201 Created as a success status code. To align with the documentation and avoid ambiguity, it's best to only check for 201.
| return response.status in (200, 201) | |
| return response.status == 201 |
| payload = {"title": title, "head": head, "base": base, "body": body} | ||
| session = await self._get_session() | ||
| async with session.post(url, headers=headers, json=payload) as response: | ||
| if response.status in (200, 201): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The success check response.status in (200, 201) includes 200 OK. The GitHub API documentation for creating a pull request (POST /repos/{owner}/{repo}/pulls) specifies 201 Created as the success status. To align with the documentation, it would be clearer to only check for 201.
| if response.status in (200, 201): | |
| if response.status == 201: |
What’s included
How to test