mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-10 07:40:39 +08:00
Compare commits
78 Commits
mrT23-patc
...
tr/static_
Author | SHA1 | Date | |
---|---|---|---|
685f001298 | |||
88c2b90860 | |||
c84d84ace2 | |||
af5a50ac6a | |||
bccc2844b9 | |||
d80103751e | |||
8ff8b1d48e | |||
da0bd84746 | |||
b42ded61f8 | |||
dfa4f22be2 | |||
7d55fc174b | |||
968fb71577 | |||
454365913f | |||
bbaba2dbda | |||
e4c6792866 | |||
183dd5d2fc | |||
2e79392a5f | |||
da4148f336 | |||
070ed21103 | |||
640bc1e28a | |||
6c4aa468a9 | |||
da20efd050 | |||
c25aaad176 | |||
b4c20d683c | |||
7bc20d6f16 | |||
f894e8831b | |||
25b7e1e777 | |||
6ba2fb212d | |||
4a60046f7c | |||
35b1f5e747 | |||
d77a819d92 | |||
f3fd439d47 | |||
6188afff48 | |||
57cfdcf274 | |||
1333ac47bc | |||
267e01409b | |||
8bdebcb99f | |||
a13400b9b8 | |||
89f9cf5adc | |||
6b653dbe48 | |||
109b965407 | |||
511c5a31db | |||
3dd8050004 | |||
4b7d01972c | |||
05ec944a8b | |||
4713ae74b7 | |||
c828cdde62 | |||
6f14f9c8e1 | |||
9f8cc75bd3 | |||
0668ccbb9e | |||
8a287f8ed6 | |||
d5625db3c8 | |||
d6b779eef8 | |||
804cb9ec1d | |||
47d32283ca | |||
397963257d | |||
a3fd15bb92 | |||
ded7d96649 | |||
bbf06e25ef | |||
7e5ddf7e37 | |||
0198c61cf7 | |||
20d8e76a7f | |||
be8052251a | |||
ba08b13446 | |||
835684b92a | |||
90295b6429 | |||
08d6bbc94c | |||
8229d98842 | |||
9e28aca919 | |||
3e780783cc | |||
5c7b65810c | |||
f2f82e8805 | |||
1e51acff22 | |||
81e847e477 | |||
a70fe27d94 | |||
1a5835a947 | |||
4b74506107 | |||
08319f8492 |
14
README.md
14
README.md
@ -25,11 +25,11 @@ CodiumAI PR-Agent aims to help efficiently review and handle pull requests, by p
|
||||
</div>
|
||||
|
||||
### [Documentation](https://pr-agent-docs.codium.ai/)
|
||||
- See the [Installation Guide](https://pr-agent-docs.codium.ai/installation/) for instructions on installing PR-Agent on different platforms.
|
||||
- See the [Installation Guide](https://qodo-merge-docs.qodo.ai/installation/) for instructions on installing PR-Agent on different platforms.
|
||||
|
||||
- See the [Usage Guide](https://pr-agent-docs.codium.ai/usage-guide/) for instructions on running PR-Agent tools via different interfaces, such as CLI, PR Comments, or by automatically triggering them when a new PR is opened.
|
||||
- See the [Usage Guide](https://qodo-merge-docs.qodo.ai/usage-guide/) for instructions on running PR-Agent tools via different interfaces, such as CLI, PR Comments, or by automatically triggering them when a new PR is opened.
|
||||
|
||||
- See the [Tools Guide](https://pr-agent-docs.codium.ai/tools/) for a detailed description of the different tools, and the available configurations for each tool.
|
||||
- See the [Tools Guide](https://qodo-merge-docs.qodo.ai/tools/) for a detailed description of the different tools, and the available configurations for each tool.
|
||||
|
||||
|
||||
## Table of Contents
|
||||
@ -43,6 +43,12 @@ CodiumAI PR-Agent aims to help efficiently review and handle pull requests, by p
|
||||
|
||||
## News and Updates
|
||||
|
||||
### September 21, 2024
|
||||
Need help with PR-Agent? New feature - simply comment `/help "your question"` in a pull request, and PR-Agent will provide you with the [relevant documentation](https://github.com/Codium-ai/pr-agent/pull/1241#issuecomment-2365259334).
|
||||
|
||||
<kbd><img src="https://www.codium.ai/images/pr_agent/pr_help_chat.png" width="768"></kbd>
|
||||
|
||||
|
||||
### September 12, 2024
|
||||
[Dynamic context](https://pr-agent-docs.codium.ai/core-abilities/dynamic_context/) is now the default option for context extension.
|
||||
This feature enables PR-Agent to dynamically adjusting the relevant context for each code hunk, while avoiding overflowing the model with too much information.
|
||||
@ -256,7 +262,7 @@ Note that when you set your own PR-Agent or use CodiumAI hosted PR-Agent, there
|
||||
2. **Improved privacy** - No data will be stored or used to train models. PR-Agent Pro will employ zero data retention, and will use an OpenAI account with zero data retention.
|
||||
3. **Improved support** - PR-Agent Pro users will receive priority support, and will be able to request new features and capabilities.
|
||||
4. **Extra features** -In addition to the benefits listed above, PR-Agent Pro will emphasize more customization, and the usage of static code analysis, in addition to LLM logic, to improve results.
|
||||
See [here](https://pr-agent-docs.codium.ai/#pr-agent-pro) for a list of features available in PR-Agent Pro.
|
||||
See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for a list of features available in PR-Agent Pro.
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
FROM python:3.12.3 AS base
|
||||
|
||||
WORKDIR /app
|
||||
ADD docs/chroma_db.zip /app/docs/chroma_db.zip
|
||||
ADD pyproject.toml .
|
||||
ADD requirements.txt .
|
||||
RUN pip install . && rm pyproject.toml requirements.txt
|
||||
|
@ -1 +1 @@
|
||||
# [Visit Our Docs Portal](https://pr-agent-docs.codium.ai/)
|
||||
# [Visit Our Docs Portal](https://qodo-merge-docs.qodo.ai/)
|
||||
|
BIN
docs/chroma_db.zip
Normal file
BIN
docs/chroma_db.zip
Normal file
Binary file not shown.
@ -1 +1 @@
|
||||
pr-agent-docs.codium.ai
|
||||
qodo-merge-docs.qodo.ai
|
||||
|
@ -1,5 +1,5 @@
|
||||
We take your code's security and privacy seriously:
|
||||
|
||||
- The Chrome extension will not send your code to any external servers.
|
||||
- For private repositories, we will first validate the user's identity and permissions. After authentication, we generate responses using the existing PR-Agent Pro integration.
|
||||
- For private repositories, we will first validate the user's identity and permissions. After authentication, we generate responses using the existing Qodo Merge Pro integration.
|
||||
|
||||
|
@ -4,22 +4,22 @@
|
||||
The PR-Chat feature allows to freely chat with your PR code, within your GitHub environment.
|
||||
It will seamlessly use the PR as context to your chat session, and provide AI-powered feedback.
|
||||
|
||||
To enable private chat, simply install the PR-Agent Chrome extension. After installation, each PR's file-changed tab will include a chat box, where you may ask questions about your code.
|
||||
To enable private chat, simply install the Qodo Merge Chrome extension. After installation, each PR's file-changed tab will include a chat box, where you may ask questions about your code.
|
||||
This chat session is **private**, and won't be visible to other users.
|
||||
|
||||
All open-source repositories are supported.
|
||||
For private repositories, you will also need to install PR-Agent Pro, After installation, make sure to open at least one new PR to fully register your organization. Once done, you can chat with both new and existing PRs across all installed repositories.
|
||||
For private repositories, you will also need to install Qodo Merge Pro, After installation, make sure to open at least one new PR to fully register your organization. Once done, you can chat with both new and existing PRs across all installed repositories.
|
||||
|
||||
#### Context-aware PR chat
|
||||
|
||||
PR-Agent constructs a comprehensive context for each pull request, incorporating the PR description, commit messages, and code changes with extended dynamic context. This contextual information, along with additional PR-related data, forms the foundation for an AI-powered chat session. The agent then leverages this rich context to provide intelligent, tailored responses to user inquiries about the pull request.
|
||||
Qodo Merge constructs a comprehensive context for each pull request, incorporating the PR description, commit messages, and code changes with extended dynamic context. This contextual information, along with additional PR-related data, forms the foundation for an AI-powered chat session. The agent then leverages this rich context to provide intelligent, tailored responses to user inquiries about the pull request.
|
||||
|
||||
<img src="https://codium.ai/images/pr_agent/pr_chat_1.png" width="768">
|
||||
<img src="https://codium.ai/images/pr_agent/pr_chat_2.png" width="768">
|
||||
|
||||
|
||||
### Toolbar extension
|
||||
With PR-Agent Chrome extension, it's [easier than ever](https://www.youtube.com/watch?v=gT5tli7X4H4) to interactively configure and experiment with the different tools and configuration options.
|
||||
With Qodo Merge Chrome extension, it's [easier than ever](https://www.youtube.com/watch?v=gT5tli7X4H4) to interactively configure and experiment with the different tools and configuration options.
|
||||
|
||||
For private repositories, after you found the setup that works for you, you can also easily export it as a persistent configuration file, and use it for automatic commands.
|
||||
|
||||
@ -27,11 +27,11 @@ For private repositories, after you found the setup that works for you, you can
|
||||
|
||||
<img src="https://codium.ai/images/pr_agent/toolbar2.png" width="512">
|
||||
|
||||
### PR-Agent filters
|
||||
### Qodo Merge filters
|
||||
|
||||
PR-Agent filters is a sidepanel option. that allows you to filter different message in the conversation tab.
|
||||
Qodo Merge filters is a sidepanel option. that allows you to filter different message in the conversation tab.
|
||||
|
||||
For example, you can choose to present only message from PR-Agent, or filter those messages, focusing only on user's comments.
|
||||
For example, you can choose to present only message from Qodo Merge, or filter those messages, focusing only on user's comments.
|
||||
|
||||
<img src="https://codium.ai/images/pr_agent/pr_agent_filters1.png" width="256">
|
||||
|
||||
@ -40,7 +40,7 @@ For example, you can choose to present only message from PR-Agent, or filter tho
|
||||
|
||||
### Enhanced code suggestions
|
||||
|
||||
PR-Agent Chrome extension adds the following capabilities to code suggestions tool's comments:
|
||||
Qodo Merge Chrome extension adds the following capabilities to code suggestions tool's comments:
|
||||
|
||||
- Auto-expand the table when you are viewing a code block, to avoid clipping.
|
||||
- Adding a "quote-and-reply" button, that enables to address and comment on a specific suggestion (for example, asking the author to fix the issue)
|
||||
|
@ -1,11 +1,11 @@
|
||||
[PR-Agent Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) is a collection of tools that integrates seamlessly with your GitHub environment, aiming to enhance your Git usage experience, and providing AI-powered capabilities to your PRs.
|
||||
[Qodo Merge Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) is a collection of tools that integrates seamlessly with your GitHub environment, aiming to enhance your Git usage experience, and providing AI-powered capabilities to your PRs.
|
||||
|
||||
With a single-click installation you will gain access to a context-aware chat on your pull requests code, a toolbar extension with multiple AI feedbacks, PR-Agent filters, and additional abilities.
|
||||
With a single-click installation you will gain access to a context-aware chat on your pull requests code, a toolbar extension with multiple AI feedbacks, Qodo Merge filters, and additional abilities.
|
||||
|
||||
The extension is powered by top code models like Claude 3.5 Sonnet and GPT4. All the extension's features are free to use on public repositories.
|
||||
|
||||
For private repositories, you will need to install [PR-Agent Pro](https://github.com/apps/codiumai-pr-agent-pro) in addition to the extension (Quick GitHub app setup with a 14-day free trial. No credit card needed).
|
||||
For a demonstration of how to install PR-Agent Pro and use it with the Chrome extension, please refer to the tutorial video at the provided [link](https://codium.ai/images/pr_agent/private_repos.mp4).
|
||||
For private repositories, you will need to install [Qodo Merge Pro](https://github.com/apps/codiumai-pr-agent-pro) in addition to the extension (Quick GitHub app setup with a 14-day free trial. No credit card needed).
|
||||
For a demonstration of how to install Qodo Merge Pro and use it with the Chrome extension, please refer to the tutorial video at the provided [link](https://codium.ai/images/pr_agent/private_repos.mp4).
|
||||
|
||||
<img src="https://codium.ai/images/pr_agent/PR-AgentChat.gif" width="768">
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
## TL;DR
|
||||
|
||||
PR-Agent uses an **asymmetric and dynamic context strategy** to improve AI analysis of code changes in pull requests.
|
||||
Qodo Merge uses an **asymmetric and dynamic context strategy** to improve AI analysis of code changes in pull requests.
|
||||
It provides more context before changes than after, and dynamically adjusts the context based on code structure (e.g., enclosing functions or classes).
|
||||
This approach balances providing sufficient context for accurate analysis, while avoiding needle-in-the-haystack information overload that could degrade AI performance or exceed token limits.
|
||||
|
||||
@ -43,14 +43,14 @@ Pull requests often encompass multiple changes across many files, potentially sp
|
||||
- Increased context expands the token count, increasing processing time and cost, and may prevent the model from processing the entire pull request in a single pass.
|
||||
|
||||
## Asymmetric and dynamic context
|
||||
To address these challenges, PR-Agent employs an **asymmetric** and **dynamic** context strategy, providing the model with more focused and relevant context information for each code change.
|
||||
To address these challenges, Qodo Merge employs an **asymmetric** and **dynamic** context strategy, providing the model with more focused and relevant context information for each code change.
|
||||
|
||||
**Asymmetric:**
|
||||
|
||||
We start by recognizing that the context preceding a code change is typically more crucial for understanding the modification than the context following it.
|
||||
Consequently, PR-Agent implements an asymmetric context policy, decoupling the context window into two distinct segments: one for the code before the change and another for the code after.
|
||||
Consequently, Qodo Merge implements an asymmetric context policy, decoupling the context window into two distinct segments: one for the code before the change and another for the code after.
|
||||
|
||||
By independently adjusting each context window, PR-Agent can supply the model with a more tailored and pertinent context for individual code changes.
|
||||
By independently adjusting each context window, Qodo Merge can supply the model with a more tailored and pertinent context for individual code changes.
|
||||
|
||||
**Dynamic:**
|
||||
|
||||
|
@ -1,43 +1,43 @@
|
||||
# Overview - Impact Evaluation 💎
|
||||
|
||||
Demonstrating the return on investment (ROI) of AI-powered initiatives is crucial for modern organizations.
|
||||
To address this need, PR-Agent has developed an AI impact measurement tools and metrics, providing advanced analytics to help businesses quantify the tangible benefits of AI adoption in their PR review process.
|
||||
To address this need, Qodo Merge has developed an AI impact measurement tools and metrics, providing advanced analytics to help businesses quantify the tangible benefits of AI adoption in their PR review process.
|
||||
|
||||
|
||||
## Auto Impact Validator - Real-Time Tracking of Implemented PR-Agent Suggestions
|
||||
## Auto Impact Validator - Real-Time Tracking of Implemented Qodo Merge Suggestions
|
||||
|
||||
### How It Works
|
||||
When a user pushes a new commit to the pull request, PR-Agent automatically compares the updated code against the previous suggestions, marking them as implemented if the changes address these recommendations, whether directly or indirectly:
|
||||
When a user pushes a new commit to the pull request, Qodo Merge automatically compares the updated code against the previous suggestions, marking them as implemented if the changes address these recommendations, whether directly or indirectly:
|
||||
|
||||
1. **Direct Implementation:** The user directly addresses the suggestion as-is in the PR, either by clicking on the "apply code suggestion" checkbox or by making the changes manually.
|
||||
2. **Indirect Implementation:** PR-Agent recognizes when a suggestion's intent is fulfilled, even if the exact code changes differ from the original recommendation. It marks these suggestions as implemented, acknowledging that users may achieve the same goal through alternative solutions.
|
||||
2. **Indirect Implementation:** Qodo Merge recognizes when a suggestion's intent is fulfilled, even if the exact code changes differ from the original recommendation. It marks these suggestions as implemented, acknowledging that users may achieve the same goal through alternative solutions.
|
||||
|
||||
### Real-Time Visual Feedback
|
||||
Upon confirming that a suggestion was implemented, PR-Agent automatically adds a ✅ (check mark) to the relevant suggestion, enabling transparent tracking of PR-Agent's impact analysis.
|
||||
PR-Agent will also add, inside the relevant suggestions, an explanation of how the new code was impacted by each suggestion.
|
||||
Upon confirming that a suggestion was implemented, Qodo Merge automatically adds a ✅ (check mark) to the relevant suggestion, enabling transparent tracking of Qodo Merge's impact analysis.
|
||||
Qodo Merge will also add, inside the relevant suggestions, an explanation of how the new code was impacted by each suggestion.
|
||||
|
||||
{width=512}
|
||||
|
||||
### Dashboard Metrics
|
||||
The dashboard provides macro-level insights into the overall impact of PR-Agent on the pull-request process with key productivity metrics.
|
||||
The dashboard provides macro-level insights into the overall impact of Qodo Merge on the pull-request process with key productivity metrics.
|
||||
|
||||
By offering clear, data-driven evidence of PR-Agent's impact, it empowers leadership teams to make informed decisions about the tool's effectiveness and ROI.
|
||||
By offering clear, data-driven evidence of Qodo Merge's impact, it empowers leadership teams to make informed decisions about the tool's effectiveness and ROI.
|
||||
|
||||
Here are key metrics that the dashboard tracks:
|
||||
|
||||
#### PR-Agent Impacts per 1K Lines
|
||||
#### Qodo Merge Impacts per 1K Lines
|
||||
{width=512}
|
||||
> Explanation: for every 1K lines of code (additions/edits), PR-Agent had on average ~X suggestions implemented.
|
||||
> Explanation: for every 1K lines of code (additions/edits), Qodo Merge had on average ~X suggestions implemented.
|
||||
|
||||
**Why This Metric Matters:**
|
||||
|
||||
1. **Standardized and Comparable Measurement:** By measuring impacts per 1K lines of code additions, you create a standardized metric that can be compared across different projects, teams, customers, and time periods. This standardization is crucial for meaningful analysis, benchmarking, and identifying where PR-Agent is most effective.
|
||||
1. **Standardized and Comparable Measurement:** By measuring impacts per 1K lines of code additions, you create a standardized metric that can be compared across different projects, teams, customers, and time periods. This standardization is crucial for meaningful analysis, benchmarking, and identifying where Qodo Merge is most effective.
|
||||
2. **Accounts for PR Variability and Incentivizes Quality:** This metric addresses the fact that "Not all PRs are created equal." By normalizing against lines of code rather than PR count, you account for the variability in PR sizes and focus on the quality and impact of suggestions rather than just the number of PRs affected.
|
||||
3. **Quantifies Value and ROI:** The metric directly correlates with the value PR-Agent is providing, showing how frequently it offers improvements relative to the amount of new code being written. This provides a clear, quantifiable way to demonstrate PR-Agent's return on investment to stakeholders.
|
||||
3. **Quantifies Value and ROI:** The metric directly correlates with the value Qodo Merge is providing, showing how frequently it offers improvements relative to the amount of new code being written. This provides a clear, quantifiable way to demonstrate Qodo Merge's return on investment to stakeholders.
|
||||
|
||||
#### Suggestion Effectiveness Across Categories
|
||||
{width=512}
|
||||
> Explanation: This chart illustrates the distribution of implemented suggestions across different categories, enabling teams to better understand PR-Agent's impact on various aspects of code quality and development practices.
|
||||
> Explanation: This chart illustrates the distribution of implemented suggestions across different categories, enabling teams to better understand Qodo Merge's impact on various aspects of code quality and development practices.
|
||||
|
||||
#### Suggestion Score Distribution
|
||||
{width=512}
|
||||
|
@ -1,12 +1,12 @@
|
||||
# Core Abilities
|
||||
PR-Agent utilizes a variety of core abilities to provide a comprehensive and efficient code review experience. These abilities include:
|
||||
Qodo Merge utilizes a variety of core abilities to provide a comprehensive and efficient code review experience. These abilities include:
|
||||
|
||||
- [Local and global metadata](https://pr-agent-docs.codium.ai/core-abilities/metadata/)
|
||||
- [Dynamic context](https://pr-agent-docs.codium.ai/core-abilities/dynamic_context/)
|
||||
- [Self-reflection](https://pr-agent-docs.codium.ai/core-abilities/self_reflection/)
|
||||
- [Impact evaluation](https://pr-agent-docs.codium.ai/core-abilities/impact_evaluation/)
|
||||
- [Interactivity](https://pr-agent-docs.codium.ai/core-abilities/interactivity/)
|
||||
- [Compression strategy](https://pr-agent-docs.codium.ai/core-abilities/compression_strategy/)
|
||||
- [Code-oriented YAML](https://pr-agent-docs.codium.ai/core-abilities/code_oriented_yaml/)
|
||||
- [Static code analysis](https://pr-agent-docs.codium.ai/core-abilities/static_code_analysis/)
|
||||
- [Code fine-tuning benchmark](https://pr-agent-docs.codium.ai/finetuning_benchmark/)
|
||||
- [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/)
|
||||
- [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/)
|
||||
- [Self-reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/)
|
||||
- [Impact evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/)
|
||||
- [Interactivity](https://qodo-merge-docs.qodo.ai/core-abilities/interactivity/)
|
||||
- [Compression strategy](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/)
|
||||
- [Code-oriented YAML](https://qodo-merge-docs.qodo.ai/core-abilities/code_oriented_yaml/)
|
||||
- [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/)
|
||||
- [Code fine-tuning benchmark](https://qodo-merge-docs.qodo.ai/finetuning_benchmark/)
|
@ -1,6 +1,6 @@
|
||||
## Local and global metadata injection with multi-stage analysis
|
||||
(1)
|
||||
PR-Agent initially retrieves for each PR the following data:
|
||||
Qodo Merge initially retrieves for each PR the following data:
|
||||
|
||||
- PR title and branch name
|
||||
- PR original description
|
||||
@ -9,10 +9,10 @@ PR-Agent initially retrieves for each PR the following data:
|
||||
- The entire content of the files that were modified in the PR
|
||||
|
||||
!!! tip "Tip: Organization-level metadata"
|
||||
In addition to the inputs above, PR-Agent can incorporate supplementary preferences provided by the user, like [`extra_instructions` and `organization best practices`](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices). This information can be used to enhance the PR analysis.
|
||||
In addition to the inputs above, Qodo Merge can incorporate supplementary preferences provided by the user, like [`extra_instructions` and `organization best practices`](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices). This information can be used to enhance the PR analysis.
|
||||
|
||||
(2)
|
||||
By default, the first command that PR-Agent executes is [`describe`](https://pr-agent-docs.codium.ai/tools/describe/), which generates three types of outputs:
|
||||
By default, the first command that Qodo Merge executes is [`describe`](https://qodo-merge-docs.qodo.ai/tools/describe/), which generates three types of outputs:
|
||||
|
||||
- PR Type (e.g. bug fix, feature, refactor, etc)
|
||||
- PR Description - a bullet point summary of the PR
|
||||
@ -21,7 +21,7 @@ By default, the first command that PR-Agent executes is [`describe`](https://pr-
|
||||
These AI-generated outputs are now considered as part of the PR metadata, and can be used in subsequent commands like `review` and `improve`.
|
||||
This effectively enables multi-stage chain-of-thought analysis, without doing any additional API calls which will cost time and money.
|
||||
|
||||
For example, when generating code suggestions for different files, PR-Agent can inject the AI-generated ["Changes walkthrough"](https://github.com/Codium-ai/pr-agent/pull/1202#issue-2511546839) file summary in the prompt:
|
||||
For example, when generating code suggestions for different files, Qodo Merge can inject the AI-generated ["Changes walkthrough"](https://github.com/Codium-ai/pr-agent/pull/1202#issue-2511546839) file summary in the prompt:
|
||||
|
||||
```
|
||||
## File: 'src/file1.py'
|
||||
@ -49,8 +49,8 @@ __old hunk__
|
||||
...
|
||||
```
|
||||
|
||||
(3) The entire PR files that were retrieved are also used to expand and enhance the PR context (see [Dynamic Context](https://pr-agent-docs.codium.ai/core-abilities/dynamic-context/)).
|
||||
(3) The entire PR files that were retrieved are also used to expand and enhance the PR context (see [Dynamic Context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic-context/)).
|
||||
|
||||
|
||||
(4) All the metadata described above represents several level of cumulative analysis - ranging from hunk level, to file level, to PR level, to organization level.
|
||||
This comprehensive approach enables PR-Agent AI models to generate more precise and contextually relevant suggestions and feedback.
|
||||
This comprehensive approach enables Qodo Merge AI models to generate more precise and contextually relevant suggestions and feedback.
|
@ -1,6 +1,6 @@
|
||||
## TL;DR
|
||||
|
||||
PR-Agent implements a **self-reflection** process where the AI model reflects, scores, and re-ranks its own suggestions, eliminating irrelevant or incorrect ones.
|
||||
Qodo Merge implements a **self-reflection** process where the AI model reflects, scores, and re-ranks its own suggestions, eliminating irrelevant or incorrect ones.
|
||||
This approach improves the quality and relevance of suggestions, saving users time and enhancing their experience.
|
||||
Configuration options allow users to set a score threshold for further filtering out suggestions.
|
||||
|
||||
@ -9,7 +9,7 @@ Configuration options allow users to set a score threshold for further filtering
|
||||
|
||||
Given that not all generated code suggestions will be relevant, it is crucial to enable users to review them in a fast and efficient way, allowing quick identification and filtering of non-applicable ones.
|
||||
|
||||
To achieve this goal, PR-Agent offers a dedicated hierarchical structure when presenting suggestions to users:
|
||||
To achieve this goal, Qodo Merge offers a dedicated hierarchical structure when presenting suggestions to users:
|
||||
|
||||
- A "category" section groups suggestions by their category, allowing users to quickly dismiss irrelevant suggestions.
|
||||
- Each suggestion is first described by a one-line summary, which can be expanded to a full description by clicking on a collapsible.
|
||||
@ -34,7 +34,7 @@ This process consists of the following steps:
|
||||
|
||||
Note that presenting all generated suggestions simultaneously provides the model with a comprehensive context, enabling it to make more informed decisions compared to evaluating each suggestion individually.
|
||||
|
||||
To conclude, the self-reflection process enables PR-Agent to prioritize suggestions based on their importance, eliminate inaccurate or irrelevant proposals, and optionally exclude suggestions that fall below a specified threshold of significance.
|
||||
To conclude, the self-reflection process enables Qodo Merge to prioritize suggestions based on their importance, eliminate inaccurate or irrelevant proposals, and optionally exclude suggestions that fall below a specified threshold of significance.
|
||||
This results in a more refined and valuable set of suggestions for the user, saving time and improving the overall experience.
|
||||
|
||||
## Example Results
|
||||
|
@ -1,6 +1,6 @@
|
||||
## Overview - Static Code Analysis 💎
|
||||
|
||||
By combining static code analysis with LLM capabilities, PR-Agent can provide a comprehensive analysis of the PR code changes on a component level.
|
||||
By combining static code analysis with LLM capabilities, Qodo Merge can provide a comprehensive analysis of the PR code changes on a component level.
|
||||
|
||||
It scans the PR code changes, finds all the code components (methods, functions, classes) that changed, and enables to interactively generate tests, docs, code suggestions and similar code search for each component.
|
||||
|
||||
@ -13,7 +13,7 @@ It scans the PR code changes, finds all the code components (methods, functions,
|
||||
### Analyze PR
|
||||
|
||||
|
||||
The [`analyze`](https://pr-agent-docs.codium.ai/tools/analyze/) tool enables to interactively generate tests, docs, code suggestions and similar code search for each component that changed in the PR.
|
||||
The [`analyze`](https://qodo-merge-docs.qodo.ai/tools/analyze/) tool enables to interactively generate tests, docs, code suggestions and similar code search for each component that changed in the PR.
|
||||
It can be invoked manually by commenting on any PR:
|
||||
```
|
||||
/analyze
|
||||
@ -27,7 +27,7 @@ Clicking on each checkbox will trigger the relevant tool for the selected compon
|
||||
|
||||
### Generate Tests
|
||||
|
||||
The [`test`](https://pr-agent-docs.codium.ai/tools/test/) tool generate tests for a selected component, based on the PR code changes.
|
||||
The [`test`](https://qodo-merge-docs.qodo.ai/tools/test/) tool generate tests for a selected component, based on the PR code changes.
|
||||
It can be invoked manually by commenting on any PR:
|
||||
```
|
||||
/test component_name
|
||||
@ -38,7 +38,7 @@ where 'component_name' is the name of a specific component in the PR, Or be tri
|
||||
|
||||
### Generate Docs for a Component
|
||||
|
||||
The [`add_docs`](https://pr-agent-docs.codium.ai/tools/documentation/) tool scans the PR code changes, and automatically generate docstrings for any code components that changed in the PR.
|
||||
The [`add_docs`](https://qodo-merge-docs.qodo.ai/tools/documentation/) tool scans the PR code changes, and automatically generate docstrings for any code components that changed in the PR.
|
||||
It can be invoked manually by commenting on any PR:
|
||||
```
|
||||
/add_docs component_name
|
||||
@ -49,7 +49,7 @@ Or be triggered interactively by using the `analyze` tool.
|
||||
{width=768}
|
||||
|
||||
### Generate Code Suggestions for a Component
|
||||
The [`improve_component`](https://pr-agent-docs.codium.ai/tools/improve_component/) tool generates code suggestions for a specific code component that changed in the PR.
|
||||
The [`improve_component`](https://qodo-merge-docs.qodo.ai/tools/improve_component/) tool generates code suggestions for a specific code component that changed in the PR.
|
||||
It can be invoked manually by commenting on any PR:
|
||||
```
|
||||
/improve_component component_name
|
||||
@ -61,7 +61,7 @@ Or be triggered interactively by using the `analyze` tool.
|
||||
|
||||
### Find Similar Code
|
||||
|
||||
The [`similar code`](https://pr-agent-docs.codium.ai/tools/similar_code/) tool retrieves the most similar code components from inside the organization's codebase, or from open-source code.
|
||||
The [`similar code`](https://qodo-merge-docs.qodo.ai/tools/similar_code/) tool retrieves the most similar code components from inside the organization's codebase, or from open-source code.
|
||||
|
||||
For example:
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
# FAQ
|
||||
|
||||
??? note "Question: Can PR-Agent serve as a substitute for a human reviewer?"
|
||||
??? note "Question: Can Qodo Merge serve as a substitute for a human reviewer?"
|
||||
#### Answer:<span style="display:none;">1</span>
|
||||
|
||||
PR-Agent is designed to assist, not replace, human reviewers.
|
||||
Qodo Merge is designed to assist, not replace, human reviewers.
|
||||
|
||||
Reviewing PRs is a tedious and time-consuming task often seen as a "chore". In addition, the longer the PR – the shorter the relative feedback, since long PRs can overwhelm reviewers, both in terms of technical difficulty, and the actual review time.
|
||||
PR-Agent aims to address these pain points, and to assist and empower both the PR author and reviewer.
|
||||
Qodo Merge aims to address these pain points, and to assist and empower both the PR author and reviewer.
|
||||
|
||||
However, PR-Agent has built-in safeguards to ensure the developer remains in the driver's seat. For example:
|
||||
However, Qodo Merge has built-in safeguards to ensure the developer remains in the driver's seat. For example:
|
||||
|
||||
1. Preserves user's original PR header
|
||||
2. Places user's description above the AI-generated PR description
|
||||
@ -35,33 +35,33 @@ ___
|
||||
- Only if the `Category` header is relevant, the user should move to the summarized suggestion description.
|
||||
- Only if the summarized suggestion description is relevant, the user should click on the collapsible, to read the full suggestion description with a code preview example.
|
||||
|
||||
- In addition, we recommend to use the [`extra_instructions`](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project.
|
||||
- The interactive [PR chat](https://pr-agent-docs.codium.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model.
|
||||
- In addition, we recommend to use the [`extra_instructions`](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project.
|
||||
- The interactive [PR chat](https://qodo-merge-docs.qodo.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model.
|
||||
|
||||
___
|
||||
|
||||
??? note "Question: How can I get more tailored suggestions?"
|
||||
#### Answer:<span style="display:none;">3</span>
|
||||
|
||||
See [here](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices) for more information on how to use the `extra_instructions` and `best_practices` configuration options, to guide the model to more tailored suggestions.
|
||||
See [here](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices) for more information on how to use the `extra_instructions` and `best_practices` configuration options, to guide the model to more tailored suggestions.
|
||||
|
||||
___
|
||||
|
||||
??? note "Question: Will you store my code ? Are you using my code to train models?"
|
||||
#### Answer:<span style="display:none;">4</span>
|
||||
|
||||
No. PR-Agent strict privacy policy ensures that your code is not stored or used for training purposes.
|
||||
No. Qodo Merge strict privacy policy ensures that your code is not stored or used for training purposes.
|
||||
|
||||
For a detailed overview of our data privacy policy, please refer to [this link](https://pr-agent-docs.codium.ai/overview/data_privacy/)
|
||||
For a detailed overview of our data privacy policy, please refer to [this link](https://qodo-merge-docs.qodo.ai/overview/data_privacy/)
|
||||
|
||||
___
|
||||
|
||||
??? note "Question: Can I use my own LLM keys with PR-Agent?"
|
||||
??? note "Question: Can I use my own LLM keys with Qodo Merge?"
|
||||
#### Answer:<span style="display:none;">5</span>
|
||||
|
||||
When you self-host, you use your own keys.
|
||||
|
||||
PR-Agent Pro with SaaS deployment is a hosted version of PR-Agent, where Codium AI manages the infrastructure and the keys.
|
||||
Qodo Merge Pro with SaaS deployment is a hosted version of Qodo Merge, where Qodo manages the infrastructure and the keys.
|
||||
For enterprise customers, on-prem deployment is also available. [Contact us](https://www.codium.ai/contact/#pricing) for more information.
|
||||
|
||||
___
|
@ -1,10 +1,10 @@
|
||||
# PR-Agent Code Fine-tuning Benchmark
|
||||
# Qodo Merge Code Fine-tuning Benchmark
|
||||
|
||||
On coding tasks, the gap between open-source models and top closed-source models such as GPT4 is significant.
|
||||
<br>
|
||||
In practice, open-source models are unsuitable for most real-world code tasks, and require further fine-tuning to produce acceptable results.
|
||||
|
||||
_PR-Agent fine-tuning benchmark_ aims to benchmark open-source models on their ability to be fine-tuned for a coding task.
|
||||
_Qodo Merge fine-tuning benchmark_ aims to benchmark open-source models on their ability to be fine-tuned for a coding task.
|
||||
Specifically, we chose to fine-tune open-source models on the task of analyzing a pull request, and providing useful feedback and code suggestions.
|
||||
|
||||
Here are the results:
|
||||
@ -53,8 +53,8 @@ Here are the results:
|
||||
|
||||
### Training dataset
|
||||
|
||||
Our training dataset comprises 25,000 pull requests, aggregated from permissive license repos. For each pull request, we generated responses for the three main tools of PR-Agent:
|
||||
[Describe](https://pr-agent-docs.codium.ai/tools/describe/), [Review](https://pr-agent-docs.codium.ai/tools/improve/) and [Improve](https://pr-agent-docs.codium.ai/tools/improve/).
|
||||
Our training dataset comprises 25,000 pull requests, aggregated from permissive license repos. For each pull request, we generated responses for the three main tools of Qodo Merge:
|
||||
[Describe](https://qodo-merge-docs.qodo.ai/tools/describe/), [Review](https://qodo-merge-docs.qodo.ai/tools/improve/) and [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/).
|
||||
|
||||
On the raw data collected, we employed various automatic and manual cleaning techniques to ensure the outputs were of the highest quality, and suitable for instruct-tuning.
|
||||
|
||||
|
@ -1,25 +1,38 @@
|
||||
# Overview
|
||||
|
||||
CodiumAI PR-Agent is an open-source tool to help efficiently review and handle pull requests.
|
||||
Qodo Merge is an open-source tool to help efficiently review and handle pull requests.
|
||||
|
||||
- See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms.
|
||||
|
||||
- See the [Usage Guide](./usage-guide/index.md) for instructions on running the PR-Agent commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened.
|
||||
- See the [Usage Guide](./usage-guide/index.md) for instructions on running the Qodo Merge commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened.
|
||||
|
||||
- See the [Tools Guide](./tools/index.md) for a detailed description of the different tools.
|
||||
|
||||
|
||||
## PR-Agent Features
|
||||
PR-Agent offers extensive pull request functionalities across various git providers.
|
||||
## Qodo Merge Docs Smart Search
|
||||
|
||||
To search the documentation site using natural language:
|
||||
|
||||
1) Comment `/help "your question"` in either:
|
||||
|
||||
- A pull request where Qodo Merge is installed
|
||||
- A [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat)
|
||||
|
||||
2) Qodo Merge will respond with an [answer](https://github.com/Codium-ai/pr-agent/pull/1241#issuecomment-2365259334) that includes relevant documentation links.
|
||||
|
||||
|
||||
## Qodo Merge Features
|
||||
|
||||
Qodo Merge offers extensive pull request functionalities across various git providers.
|
||||
|
||||
| | | GitHub | Gitlab | Bitbucket | Azure DevOps |
|
||||
|-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|
|
||||
| TOOLS | Review | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ Incremental | ✅ | | | |
|
||||
| | ⮑ [SOC2 Compliance](https://pr-agent-docs.codium.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
|
||||
| | ⮑ [SOC2 Compliance](https://qodo-merge-docs.qodo.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
|
||||
| | Ask | ✅ | ✅ | ✅ | ✅ |
|
||||
| | Describe | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ [Inline file summary](https://pr-agent-docs.codium.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | |
|
||||
| | ⮑ [Inline file summary](https://qodo-merge-docs.qodo.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | |
|
||||
| | Improve | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ Extended | ✅ | ✅ | ✅ | ✅ |
|
||||
| | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
|
||||
@ -42,7 +55,7 @@ PR-Agent offers extensive pull request functionalities across various git provid
|
||||
| | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
|
||||
| | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | |
|
||||
|
||||
💎 marks a feature available only in [PR-Agent Pro](https://www.codium.ai/pricing/){:target="_blank"}
|
||||
💎 marks a feature available only in [Qodo Merge Pro](https://www.codium.ai/pricing/){:target="_blank"}
|
||||
|
||||
|
||||
## Example Results
|
||||
@ -74,8 +87,8 @@ PR-Agent offers extensive pull request functionalities across various git provid
|
||||
|
||||
## How it Works
|
||||
|
||||
The following diagram illustrates PR-Agent tools and their flow:
|
||||
The following diagram illustrates Qodo Merge tools and their flow:
|
||||
|
||||

|
||||

|
||||
|
||||
Check out the [core abilities](core-abilities/index.md) page for a comprehensive overview of the variety of core abilities used by PR-Agent.
|
||||
Check out the [core abilities](core-abilities/index.md) page for a comprehensive overview of the variety of core abilities used by Qodo Merge.
|
||||
|
@ -1,5 +1,5 @@
|
||||
## Azure DevOps Pipeline
|
||||
You can use a pre-built Action Docker image to run PR-Agent as an Azure devops pipeline.
|
||||
You can use a pre-built Action Docker image to run Qodo Merge as an Azure devops pipeline.
|
||||
add the following file to your repository under `azure-pipelines.yml`:
|
||||
```yaml
|
||||
# Opt out of CI triggers
|
||||
@ -47,11 +47,11 @@ stages:
|
||||
env:
|
||||
azure_devops__pat: $(azure_devops_pat)
|
||||
openai__key: $(OPENAI_KEY)
|
||||
displayName: 'Run PR Agent'
|
||||
displayName: 'Run Qodo Merge'
|
||||
```
|
||||
This script will run PR-Agent on every new merge request, with the `improve`, `review`, and `describe` commands.
|
||||
This script will run Qodo Merge on every new merge request, with the `improve`, `review`, and `describe` commands.
|
||||
Note that you need to export the `azure_devops__pat` and `OPENAI_KEY` variables in the Azure DevOps pipeline settings (Pipelines -> Library -> + Variable group):
|
||||
{width=468}
|
||||
{width=468}
|
||||
|
||||
Make sure to give pipeline permissions to the `pr_agent` variable group.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
## Run as a Bitbucket Pipeline
|
||||
|
||||
|
||||
You can use the Bitbucket Pipeline system to run PR-Agent on every pull request open or update.
|
||||
You can use the Bitbucket Pipeline system to run Qodo Merge on every pull request open or update.
|
||||
|
||||
1. Add the following file in your repository bitbucket_pipelines.yml
|
||||
|
||||
@ -29,7 +29,7 @@ Note that comments on a PR are not supported in Bitbucket Pipeline.
|
||||
|
||||
## Run using CodiumAI-hosted Bitbucket app 💎
|
||||
|
||||
Please contact visit [PR-Agent pro](https://www.codium.ai/pricing/) if you're interested in a hosted BitBucket app solution that provides full functionality including PR reviews and comment handling. It's based on the [bitbucket_app.py](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/git_providers/bitbucket_provider.py) implementation.
|
||||
Please contact visit [Qodo Merge Pro](https://www.codium.ai/pricing/) if you're interested in a hosted BitBucket app solution that provides full functionality including PR reviews and comment handling. It's based on the [bitbucket_app.py](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/git_providers/bitbucket_provider.py) implementation.
|
||||
|
||||
|
||||
## Bitbucket Server and Data Center
|
||||
@ -58,7 +58,7 @@ python cli.py --pr_url https://git.onpreminstanceofbitbucket.com/projects/PROJEC
|
||||
|
||||
### Run it as service
|
||||
|
||||
To run pr-agent as webhook, build the docker image:
|
||||
To run Qodo Merge as webhook, build the docker image:
|
||||
```
|
||||
docker build . -t codiumai/pr-agent:bitbucket_server_webhook --target bitbucket_server_webhook -f docker/Dockerfile
|
||||
docker push codiumai/pr-agent:bitbucket_server_webhook # Push to your Docker repository
|
||||
|
@ -1,6 +1,6 @@
|
||||
## Run as a GitHub Action
|
||||
|
||||
You can use our pre-built Github Action Docker image to run PR-Agent as a Github Action.
|
||||
You can use our pre-built Github Action Docker image to run Qodo Merge as a Github Action.
|
||||
|
||||
1) Add the following file to your repository under `.github/workflows/pr_agent.yml`:
|
||||
|
||||
@ -60,7 +60,7 @@ The GITHUB_TOKEN secret is automatically created by GitHub.
|
||||
3) Merge this change to your main branch.
|
||||
When you open your next PR, you should see a comment from `github-actions` bot with a review of your PR, and instructions on how to use the rest of the tools.
|
||||
|
||||
4) You may configure PR-Agent by adding environment variables under the env section corresponding to any configurable property in the [configuration](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) file. Some examples:
|
||||
4) You may configure Qodo Merge by adding environment variables under the env section corresponding to any configurable property in the [configuration](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) file. Some examples:
|
||||
```yaml
|
||||
env:
|
||||
# ... previous environment values
|
||||
@ -68,7 +68,7 @@ When you open your next PR, you should see a comment from `github-actions` bot w
|
||||
PR_REVIEWER.REQUIRE_TESTS_REVIEW: "false" # Disable tests review
|
||||
PR_CODE_SUGGESTIONS.NUM_CODE_SUGGESTIONS: 6 # Increase number of code suggestions
|
||||
```
|
||||
See detailed usage instructions in the [USAGE GUIDE](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-action)
|
||||
See detailed usage instructions in the [USAGE GUIDE](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-action)
|
||||
|
||||
---
|
||||
|
||||
@ -155,7 +155,7 @@ cp pr_agent/settings/.secrets_template.toml pr_agent/settings/.secrets.toml
|
||||
|
||||
9. Install the app by navigating to the "Install App" tab and selecting your desired repositories.
|
||||
|
||||
> **Note:** When running PR-Agent from GitHub App, the default configuration file (configuration.toml) will be loaded.
|
||||
> **Note:** When running Qodo Merge from GitHub app, the default configuration file (configuration.toml) will be loaded.
|
||||
> However, you can override the default tool parameters by uploading a local configuration file `.pr_agent.toml`
|
||||
> For more information please check out the [USAGE GUIDE](../usage-guide/automations_and_usage.md#github-app)
|
||||
---
|
||||
@ -185,7 +185,7 @@ For example: `GITHUB.WEBHOOK_SECRET` --> `GITHUB__WEBHOOK_SECRET`
|
||||
|
||||
## AWS CodeCommit Setup
|
||||
|
||||
Not all features have been added to CodeCommit yet. As of right now, CodeCommit has been implemented to run the pr-agent CLI on the command line, using AWS credentials stored in environment variables. (More features will be added in the future.) The following is a set of instructions to have pr-agent do a review of your CodeCommit pull request from the command line:
|
||||
Not all features have been added to CodeCommit yet. As of right now, CodeCommit has been implemented to run the Qodo Merge CLI on the command line, using AWS credentials stored in environment variables. (More features will be added in the future.) The following is a set of instructions to have Qodo Merge do a review of your CodeCommit pull request from the command line:
|
||||
|
||||
1. Create an IAM user that you will use to read CodeCommit pull requests and post comments
|
||||
* Note: That user should have CLI access only, not Console access
|
||||
|
@ -1,5 +1,5 @@
|
||||
## Run as a GitLab Pipeline
|
||||
You can use a pre-built Action Docker image to run PR-Agent as a GitLab pipeline. This is a simple way to get started with PR-Agent without setting up your own server.
|
||||
You can use a pre-built Action Docker image to run Qodo Merge as a GitLab pipeline. This is a simple way to get started with Qodo Merge without setting up your own server.
|
||||
|
||||
(1) Add the following file to your repository under `.gitlab-ci.yml`:
|
||||
```yaml
|
||||
@ -8,7 +8,7 @@ stages:
|
||||
|
||||
pr_agent_job:
|
||||
stage: pr_agent
|
||||
image:
|
||||
image:
|
||||
name: codiumai/pr-agent:latest
|
||||
entrypoint: [""]
|
||||
script:
|
||||
@ -16,7 +16,8 @@ pr_agent_job:
|
||||
- echo "Running PR Agent action step"
|
||||
- export MR_URL="$CI_MERGE_REQUEST_PROJECT_URL/merge_requests/$CI_MERGE_REQUEST_IID"
|
||||
- echo "MR_URL=$MR_URL"
|
||||
- export gitlab__PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN
|
||||
- export gitlab__url=$CI_SERVER_PROTOCOL://$CI_SERVER_FQDN
|
||||
- export gitlab__PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN
|
||||
- export config__git_provider="gitlab"
|
||||
- export openai__key=$OPENAI_KEY
|
||||
- python -m pr_agent.cli --pr_url="$MR_URL" describe
|
||||
@ -25,8 +26,8 @@ pr_agent_job:
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
```
|
||||
This script will run PR-Agent on every new merge request. You can modify the `rules` section to run PR-Agent on different events.
|
||||
You can also modify the `script` section to run different PR-Agent commands, or with different parameters by exporting different environment variables.
|
||||
This script will run Qodo Merge on every new merge request. You can modify the `rules` section to run Qodo Merge on different events.
|
||||
You can also modify the `script` section to run different Qodo Merge commands, or with different parameters by exporting different environment variables.
|
||||
|
||||
|
||||
(2) Add the following masked variables to your GitLab repository (CI/CD -> Variables):
|
||||
@ -48,13 +49,13 @@ Note that if your base branches are not protected, don't set the variables as `p
|
||||
```
|
||||
WEBHOOK_SECRET=$(python -c "import secrets; print(secrets.token_hex(10))")
|
||||
```
|
||||
3. Follow the instructions to build the Docker image, setup a secrets file and deploy on your own server from [here](https://pr-agent-docs.codium.ai/installation/github/#run-as-a-github-app) steps 4-7.
|
||||
3. Follow the instructions to build the Docker image, setup a secrets file and deploy on your own server from [here](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-app) steps 4-7.
|
||||
|
||||
4. In the secrets file, fill in the following:
|
||||
- Your OpenAI key.
|
||||
- In the [gitlab] section, fill in personal_access_token and shared_secret. The access token can be a personal access token, or a group or project access token.
|
||||
- Set deployment_type to 'gitlab' in [configuration.toml](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml)
|
||||
|
||||
|
||||
5. Create a webhook in GitLab. Set the URL to ```http[s]://<PR_AGENT_HOSTNAME>/webhook```. Set the secret token to the generated secret from step 2.
|
||||
In the "Trigger" section, check the ‘comments’ and ‘merge request events’ boxes.
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
# Installation
|
||||
|
||||
## Self-hosted PR-Agent
|
||||
If you choose to host you own PR-Agent, you first need to acquire two tokens:
|
||||
## Self-hosted Qodo Merge
|
||||
If you choose to host you own Qodo Merge, you first need to acquire two tokens:
|
||||
|
||||
1. An OpenAI key from [here](https://platform.openai.com/api-keys), with access to GPT-4 (or a key for other [language models](https://pr-agent-docs.codium.ai/usage-guide/changing_a_model/), if you prefer).
|
||||
1. An OpenAI key from [here](https://platform.openai.com/api-keys), with access to GPT-4 (or a key for other [language models](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/), if you prefer).
|
||||
2. A GitHub\GitLab\BitBucket personal access token (classic), with the repo scope. [GitHub from [here](https://github.com/settings/tokens)]
|
||||
|
||||
There are several ways to use self-hosted PR-Agent:
|
||||
There are several ways to use self-hosted Qodo Merge:
|
||||
|
||||
- [Locally](./locally.md)
|
||||
- [GitHub](./github.md)
|
||||
@ -14,8 +14,8 @@ There are several ways to use self-hosted PR-Agent:
|
||||
- [BitBucket](./bitbucket.md)
|
||||
- [Azure DevOps](./azure.md)
|
||||
|
||||
## PR-Agent Pro 💎
|
||||
PR-Agent Pro, an app hosted by CodiumAI for GitHub\GitLab\BitBucket, is also available.
|
||||
## Qodo Merge Pro 💎
|
||||
Qodo Merge Pro, an app hosted by CodiumAI for GitHub\GitLab\BitBucket, is also available.
|
||||
<br>
|
||||
With PR-Agent Pro, installation is as simple as signing up and adding the PR-Agent app to your relevant repo.
|
||||
See [here](https://pr-agent-docs.codium.ai/installation/pr_agent_pro/) for more details.
|
||||
With Qodo Merge Pro, installation is as simple as signing up and adding the Qodo Merge app to your relevant repo.
|
||||
See [here](https://qodo-merge-docs.qodo.ai/installation/pr_agent_pro/) for more details.
|
@ -1,33 +1,33 @@
|
||||
|
||||
## Getting Started with PR-Agent Pro
|
||||
## Getting Started with Qodo Merge Pro
|
||||
|
||||
PR-Agent Pro is a versatile application compatible with GitHub, GitLab, and BitBucket, hosted by CodiumAI.
|
||||
See [here](https://pr-agent-docs.codium.ai/#pr-agent-pro) for more details about the benefits of using PR-Agent Pro.
|
||||
Qodo Merge Pro is a versatile application compatible with GitHub, GitLab, and BitBucket, hosted by CodiumAI.
|
||||
See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for more details about the benefits of using Qodo Merge Pro.
|
||||
|
||||
Interested parties can subscribe to PR-Agent Pro through the following [link](https://www.codium.ai/pricing/).
|
||||
Interested parties can subscribe to Qodo Merge Pro through the following [link](https://www.codium.ai/pricing/).
|
||||
After subscribing, you are granted the ability to easily install the application across any of your repositories.
|
||||
|
||||
{width=468}
|
||||
{width=468}
|
||||
|
||||
Each user who wants to use PR-Agent pro needs to buy a seat.
|
||||
Each user who wants to use Qodo Merge pro needs to buy a seat.
|
||||
Initially, CodiumAI offers a two-week trial period at no cost, after which continued access requires each user to secure a personal seat.
|
||||
Once a user acquires a seat, they gain the flexibility to use PR-Agent Pro across any repository where it was enabled.
|
||||
Once a user acquires a seat, they gain the flexibility to use Qodo Merge Pro across any repository where it was enabled.
|
||||
|
||||
Users without a purchased seat who interact with a repository featuring PR-Agent Pro are entitled to receive up to five complimentary feedbacks.
|
||||
Beyond this limit, PR-Agent Pro will cease to respond to their inquiries unless a seat is purchased.
|
||||
Users without a purchased seat who interact with a repository featuring Qodo Merge Pro are entitled to receive up to five complimentary feedbacks.
|
||||
Beyond this limit, Qodo Merge Pro will cease to respond to their inquiries unless a seat is purchased.
|
||||
|
||||
## Install PR-Agent Pro for GitHub Enterprise Server
|
||||
You can install PR-Agent Pro application on your GitHub Enterprise Server, and enjoy two weeks of free trial.
|
||||
After the trial period, to continue using PR-Agent Pro, you will need to contact us for an [Enterprise license](https://www.codium.ai/pricing/).
|
||||
## Install Qodo Merge Pro for GitHub Enterprise Server
|
||||
You can install Qodo Merge Pro application on your GitHub Enterprise Server, and enjoy two weeks of free trial.
|
||||
After the trial period, to continue using Qodo Merge Pro, you will need to contact us for an [Enterprise license](https://www.codium.ai/pricing/).
|
||||
|
||||
|
||||
## Install PR-Agent Pro for GitLab (Teams & Enterprise)
|
||||
## Install Qodo Merge Pro for GitLab (Teams & Enterprise)
|
||||
|
||||
Since GitLab platform does not support apps, installing PR-Agent Pro for GitLab is a bit more involved, and requires the following steps:
|
||||
Since GitLab platform does not support apps, installing Qodo Merge Pro for GitLab is a bit more involved, and requires the following steps:
|
||||
|
||||
### Step 1
|
||||
|
||||
Acquire a personal, project or group level access token. Enable the “api” scope in order to allow PR-Agent to read pull requests, comment and respond to requests.
|
||||
Acquire a personal, project or group level access token. Enable the “api” scope in order to allow Qodo Merge to read pull requests, comment and respond to requests.
|
||||
|
||||
<figure markdown="1">
|
||||
{width=750}
|
||||
@ -65,4 +65,4 @@ Enable SSL verification: Check the box.
|
||||
|
||||
You’re all set!
|
||||
|
||||
Open a new merge request or add a MR comment with one of PR-Agent’s commands such as /review, /describe or /improve.
|
||||
Open a new merge request or add a MR comment with one of Qodo Merge’s commands such as /review, /describe or /improve.
|
@ -1,16 +1,16 @@
|
||||
## Self-hosted PR-Agent
|
||||
## Self-hosted Qodo Merge
|
||||
|
||||
- If you self-host PR-Agent with your OpenAI (or other LLM provider) API key, it is between you and the provider. We don't send your code data to PR-Agent servers.
|
||||
- If you self-host Qodo Merge with your OpenAI (or other LLM provider) API key, it is between you and the provider. We don't send your code data to Qodo Merge servers.
|
||||
|
||||
## PR-Agent Pro 💎
|
||||
## Qodo Merge Pro 💎
|
||||
|
||||
- When using PR-Agent Pro 💎, hosted by CodiumAI, we will not store any of your data, nor will we use it for training. You will also benefit from an OpenAI account with zero data retention.
|
||||
- When using Qodo Merge Pro 💎, hosted by CodiumAI, we will not store any of your data, nor will we use it for training. You will also benefit from an OpenAI account with zero data retention.
|
||||
|
||||
- For certain clients, CodiumAI-hosted PR-Agent Pro will use CodiumAI’s proprietary models. If this is the case, you will be notified.
|
||||
- For certain clients, CodiumAI-hosted Qodo Merge Pro will use CodiumAI’s proprietary models. If this is the case, you will be notified.
|
||||
|
||||
- No passive collection of Code and Pull Requests’ data — PR-Agent will be active only when you invoke it, and it will then extract and analyze only data relevant to the executed command and queried pull request.
|
||||
- No passive collection of Code and Pull Requests’ data — Qodo Merge will be active only when you invoke it, and it will then extract and analyze only data relevant to the executed command and queried pull request.
|
||||
|
||||
|
||||
## PR-Agent Chrome extension
|
||||
## Qodo Merge Chrome extension
|
||||
|
||||
- The [PR-Agent Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) will not send your code to any external servers.
|
||||
- The [Qodo Merge Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl) will not send your code to any external servers.
|
||||
|
@ -1,25 +1,38 @@
|
||||
# Overview
|
||||
|
||||
CodiumAI PR-Agent is an open-source tool to help efficiently review and handle pull requests.
|
||||
Qodo Merge is an open-source tool to help efficiently review and handle pull requests.
|
||||
|
||||
- See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms.
|
||||
|
||||
- See the [Usage Guide](./usage-guide/index.md) for instructions on running the PR-Agent commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened.
|
||||
- See the [Usage Guide](./usage-guide/index.md) for instructions on running the Qodo Merge commands via different interfaces, including _CLI_, _online usage_, or by _automatically triggering_ them when a new PR is opened.
|
||||
|
||||
- See the [Tools Guide](./tools/index.md) for a detailed description of the different tools.
|
||||
|
||||
|
||||
## PR-Agent Features
|
||||
PR-Agent offers extensive pull request functionalities across various git providers.
|
||||
## Qodo Merge Docs Smart Search
|
||||
|
||||
To search the documentation site using natural language:
|
||||
|
||||
1) Comment `/help "your question"` in either:
|
||||
|
||||
- A pull request where Qodo Merge is installed
|
||||
- A [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat)
|
||||
|
||||
2) Qodo Merge will respond with an [answer](https://github.com/Codium-ai/pr-agent/pull/1241#issuecomment-2365259334) that includes relevant documentation links.
|
||||
|
||||
|
||||
## Qodo Merge Features
|
||||
|
||||
Qodo Merge offers extensive pull request functionalities across various git providers.
|
||||
|
||||
| | | GitHub | Gitlab | Bitbucket | Azure DevOps |
|
||||
|-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|
|
||||
| TOOLS | Review | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ Incremental | ✅ | | | |
|
||||
| | ⮑ [SOC2 Compliance](https://pr-agent-docs.codium.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ [SOC2 Compliance](https://qodo-merge-docs.qodo.ai/tools/review/#soc2-ticket-compliance){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||
| | Ask | ✅ | ✅ | ✅ | ✅ |
|
||||
| | Describe | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ [Inline file summary](https://pr-agent-docs.codium.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
||||
| | ⮑ [Inline file summary](https://qodo-merge-docs.qodo.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
||||
| | Improve | ✅ | ✅ | ✅ | ✅ |
|
||||
| | ⮑ Extended | ✅ | ✅ | ✅ | ✅ |
|
||||
| | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||
@ -42,7 +55,7 @@ PR-Agent offers extensive pull request functionalities across various git provid
|
||||
| | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||
| | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
💎 marks a feature available only in [PR-Agent Pro](https://www.codium.ai/pricing/){:target="_blank"}
|
||||
💎 marks a feature available only in [Qodo Merge Pro](https://www.codium.ai/pricing/){:target="_blank"}
|
||||
|
||||
|
||||
## Example Results
|
||||
@ -74,8 +87,8 @@ PR-Agent offers extensive pull request functionalities across various git provid
|
||||
|
||||
## How it Works
|
||||
|
||||
The following diagram illustrates PR-Agent tools and their flow:
|
||||
The following diagram illustrates Qodo Merge tools and their flow:
|
||||
|
||||

|
||||

|
||||
|
||||
Check out the [PR Compression strategy](core-abilities/index.md) page for more details on how we convert a code diff to a manageable LLM prompt
|
@ -1,52 +1,52 @@
|
||||
### Overview
|
||||
|
||||
[PR-Agent Pro](https://www.codium.ai/pricing/) is a hosted version of PR-Agent, provided by CodiumAI. A complimentary two-week trial is offered, followed by a monthly subscription fee.
|
||||
PR-Agent Pro is designed for companies and teams that require additional features and capabilities. It provides the following benefits:
|
||||
[Qodo Merge Pro](https://www.codium.ai/pricing/) is a hosted version of Qodo Merge, provided by Qodo. A complimentary two-week trial is offered, followed by a monthly subscription fee.
|
||||
Qodo Merge Pro is designed for companies and teams that require additional features and capabilities. It provides the following benefits:
|
||||
|
||||
1. **Fully managed** - We take care of everything for you - hosting, models, regular updates, and more. Installation is as simple as signing up and adding the PR-Agent app to your GitHub\GitLab\BitBucket repo.
|
||||
1. **Fully managed** - We take care of everything for you - hosting, models, regular updates, and more. Installation is as simple as signing up and adding the Qodo Merge app to your GitHub\GitLab\BitBucket repo.
|
||||
|
||||
2. **Improved privacy** - No data will be stored or used to train models. PR-Agent Pro will employ zero data retention, and will use an OpenAI and Claude accounts with zero data retention.
|
||||
2. **Improved privacy** - No data will be stored or used to train models. Qodo Merge Pro will employ zero data retention, and will use an OpenAI and Claude accounts with zero data retention.
|
||||
|
||||
3. **Improved support** - PR-Agent Pro users will receive priority support, and will be able to request new features and capabilities.
|
||||
3. **Improved support** - Qodo Merge Pro users will receive priority support, and will be able to request new features and capabilities.
|
||||
|
||||
4. **Supporting self-hosted git servers** - PR-Agent Pro can be installed on GitHub Enterprise Server, GitLab, and BitBucket. For more information, see the [installation guide](https://pr-agent-docs.codium.ai/installation/pr_agent_pro/).
|
||||
4. **Supporting self-hosted git servers** - Qodo Merge Pro can be installed on GitHub Enterprise Server, GitLab, and BitBucket. For more information, see the [installation guide](https://qodo-merge-docs.qodo.ai/installation/pr_agent_pro/).
|
||||
|
||||
5. **PR Chat** - PR-Agent Pro allows you to engage in [private chat](https://pr-agent-docs.codium.ai/chrome-extension/features/#pr-chat) about your pull requests on private repositories.
|
||||
5. **PR Chat** - Qodo Merge Pro allows you to engage in [private chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) about your pull requests on private repositories.
|
||||
|
||||
### Additional features
|
||||
|
||||
Here are some of the additional features and capabilities that PR-Agent Pro offers:
|
||||
Here are some of the additional features and capabilities that Qodo Merge Pro offers:
|
||||
|
||||
| Feature | Description |
|
||||
|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [**Model selection**](https://pr-agent-docs.codium.ai/usage-guide/PR_agent_pro_models/#pr-agent-pro-models) | Choose the model that best fits your needs, among top models like `GPT4` and `Claude-Sonnet-3.5`
|
||||
| [**Global and wiki configuration**](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/) | Control configurations for many repositories from a single location; <br>Edit configuration of a single repo without commiting code |
|
||||
| [**Apply suggestions**](https://pr-agent-docs.codium.ai/tools/improve/#overview) | Generate commitable code from the relevant suggestions interactively by clicking on a checkbox |
|
||||
| [**Suggestions impact**](https://pr-agent-docs.codium.ai/tools/improve/#assessing-impact) | Automatically mark suggestions that were implemented by the user (either directly in GitHub, or indirectly in the IDE) to enable tracking of the impact of the suggestions |
|
||||
| [**CI feedback**](https://pr-agent-docs.codium.ai/tools/ci_feedback/) | Automatically analyze failed CI checks on GitHub and provide actionable feedback in the PR conversation, helping to resolve issues quickly |
|
||||
| [**Advanced usage statistics**](https://www.codium.ai/contact/#/) | PR-Agent Pro offers detailed statistics at user, repository, and company levels, including metrics about PR-Agent usage, and also general statistics and insights |
|
||||
| [**Incorporating companies' best practices**](https://pr-agent-docs.codium.ai/tools/improve/#best-practices) | Use the companies' best practices as reference to increase the effectiveness and the relevance of the code suggestions |
|
||||
| [**Interactive triggering**](https://pr-agent-docs.codium.ai/tools/analyze/#example-usage) | Interactively apply different tools via the `analyze` command |
|
||||
| [**SOC2 compliance check**](https://pr-agent-docs.codium.ai/tools/review/#configuration-options) | Ensures the PR contains a ticket to a project management system (e.g., Jira, Asana, Trello, etc.)
|
||||
| [**Custom labels**](https://pr-agent-docs.codium.ai/tools/describe/#handle-custom-labels-from-the-repos-labels-page) | Define custom labels for PR-Agent to assign to the PR |
|
||||
| [**Model selection**](https://qodo-merge-docs.qodo.ai/usage-guide/PR_agent_pro_models/) | Choose the model that best fits your needs, among top models like `GPT4` and `Claude-Sonnet-3.5`
|
||||
| [**Global and wiki configuration**](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) | Control configurations for many repositories from a single location; <br>Edit configuration of a single repo without commiting code |
|
||||
| [**Apply suggestions**](https://qodo-merge-docs.qodo.ai/tools/improve/#overview) | Generate commitable code from the relevant suggestions interactively by clicking on a checkbox |
|
||||
| [**Suggestions impact**](https://qodo-merge-docs.qodo.ai/tools/improve/#assessing-impact) | Automatically mark suggestions that were implemented by the user (either directly in GitHub, or indirectly in the IDE) to enable tracking of the impact of the suggestions |
|
||||
| [**CI feedback**](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) | Automatically analyze failed CI checks on GitHub and provide actionable feedback in the PR conversation, helping to resolve issues quickly |
|
||||
| [**Advanced usage statistics**](https://www.codium.ai/contact/#/) | Qodo Merge Pro offers detailed statistics at user, repository, and company levels, including metrics about Qodo Merge usage, and also general statistics and insights |
|
||||
| [**Incorporating companies' best practices**](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) | Use the companies' best practices as reference to increase the effectiveness and the relevance of the code suggestions |
|
||||
| [**Interactive triggering**](https://qodo-merge-docs.qodo.ai/tools/analyze/#example-usage) | Interactively apply different tools via the `analyze` command |
|
||||
| [**SOC2 compliance check**](https://qodo-merge-docs.qodo.ai/tools/review/#configuration-options) | Ensures the PR contains a ticket to a project management system (e.g., Jira, Asana, Trello, etc.)
|
||||
| [**Custom labels**](https://qodo-merge-docs.qodo.ai/tools/describe/#handle-custom-labels-from-the-repos-labels-page) | Define custom labels for Qodo Merge to assign to the PR |
|
||||
|
||||
### Additional tools
|
||||
|
||||
Here are additional tools that are available only for PR-Agent Pro users:
|
||||
Here are additional tools that are available only for Qodo Merge Pro users:
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| [**Custom Prompt Suggestions**](https://pr-agent-docs.codium.ai/tools/custom_prompt/) | Generate code suggestions based on custom prompts from the user |
|
||||
| [**Analyze PR components**](https://pr-agent-docs.codium.ai/tools/analyze/) | Identify the components that changed in the PR, and enable to interactively apply different tools to them |
|
||||
| [**Tests**](https://pr-agent-docs.codium.ai/tools/test/) | Generate tests for code components that changed in the PR |
|
||||
| [**PR documentation**](https://pr-agent-docs.codium.ai/tools/documentation/) | Generate docstring for code components that changed in the PR |
|
||||
| [**Improve Component**](https://pr-agent-docs.codium.ai/tools/improve_component/) | Generate code suggestions for code components that changed in the PR |
|
||||
| [**Similar code search**](https://pr-agent-docs.codium.ai/tools/similar_code/) | Search for similar code in the repository, organization, or entire GitHub |
|
||||
| [**Custom Prompt Suggestions**](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) | Generate code suggestions based on custom prompts from the user |
|
||||
| [**Analyze PR components**](https://qodo-merge-docs.qodo.ai/tools/analyze/) | Identify the components that changed in the PR, and enable to interactively apply different tools to them |
|
||||
| [**Tests**](https://qodo-merge-docs.qodo.ai/tools/test/) | Generate tests for code components that changed in the PR |
|
||||
| [**PR documentation**](https://qodo-merge-docs.qodo.ai/tools/documentation/) | Generate docstring for code components that changed in the PR |
|
||||
| [**Improve Component**](https://qodo-merge-docs.qodo.ai/tools/improve_component/) | Generate code suggestions for code components that changed in the PR |
|
||||
| [**Similar code search**](https://qodo-merge-docs.qodo.ai/tools/similar_code/) | Search for similar code in the repository, organization, or entire GitHub |
|
||||
|
||||
|
||||
### Supported languages
|
||||
|
||||
PR-Agent Pro leverages the world's leading code models - Claude 3.5 Sonnet and GPT-4.
|
||||
Qodo Merge Pro leverages the world's leading code models - Claude 3.5 Sonnet and GPT-4.
|
||||
As a result, its primary tools such as `describe`, `review`, and `improve`, as well as the PR-chat feature, support virtually all programming languages.
|
||||
|
||||
For specialized commands that require static code analysis, PR-Agent Pro offers support for specific languages. For more details about features that require static code analysis, please refer to the [documentation](https://pr-agent-docs.codium.ai/tools/analyze/#overview).
|
||||
For specialized commands that require static code analysis, Qodo Merge Pro offers support for specific languages. For more details about features that require static code analysis, please refer to the [documentation](https://qodo-merge-docs.qodo.ai/tools/analyze/#overview).
|
@ -28,7 +28,7 @@ When working from CLI, you need to apply the [configuration changes](#configurat
|
||||
To enable custom labels, you need to apply the [configuration changes](#configuration-options) to the local `.pr_agent.toml` file in you repository.
|
||||
|
||||
#### 3. Handle custom labels from the Repo's labels page 💎
|
||||
> This feature is available only in PR-Agent Pro
|
||||
> This feature is available only in Qodo Merge Pro
|
||||
|
||||
* GitHub : `https://github.com/{owner}/{repo}/labels`, or click on the "Labels" tab in the issues or PRs page.
|
||||
* GitLab : `https://gitlab.com/{owner}/{repo}/-/labels`, or click on "Manage" -> "Labels" on the left menu.
|
||||
|
@ -25,7 +25,7 @@ If you want to edit [configurations](#configuration-options), add the relevant o
|
||||
|
||||
### Automatic triggering
|
||||
|
||||
To run the `describe` automatically when a PR is opened, define in a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#wiki-configuration-file):
|
||||
To run the `describe` automatically when a PR is opened, define in a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file):
|
||||
```
|
||||
[github_app]
|
||||
pr_commands = [
|
||||
@ -157,7 +157,7 @@ The marker `pr_agent:type` will be replaced with the PR type, `pr_agent:summary`
|
||||
The default labels of the describe tool are quite generic, since they are meant to be used in any repo: [`Bug fix`, `Tests`, `Enhancement`, `Documentation`, `Other`].
|
||||
|
||||
You can define custom labels that are relevant for your repo and use cases.
|
||||
Custom labels can be defined in a [configuration file](https://pr-agent-docs.codium.ai/tools/custom_labels/#configuration-options), or directly in the repo's [labels page](#handle-custom-labels-from-the-repos-labels-page).
|
||||
Custom labels can be defined in a [configuration file](https://qodo-merge-docs.qodo.ai/tools/custom_labels/#configuration-options), or directly in the repo's [labels page](#handle-custom-labels-from-the-repos-labels-page).
|
||||
|
||||
Make sure to provide proper title, and a detailed and well-phrased description for each label, so the tool will know when to suggest it.
|
||||
Each label description should be a **conditional statement**, that indicates if to add the label to the PR or not, according to the PR content.
|
||||
@ -205,7 +205,7 @@ The description should be comprehensive and detailed, indicating when to add the
|
||||
## Usage Tips
|
||||
|
||||
!!! tip "Automation"
|
||||
- When you first install PR-Agent app, the [default mode](../usage-guide/automations_and_usage.md#github-app) for the describe tool is:
|
||||
- When you first install Qodo Merge app, the [default mode](../usage-guide/automations_and_usage.md#github-app) for the describe tool is:
|
||||
```
|
||||
pr_commands = ["/describe", ...]
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
## Overview
|
||||
The `help` tool provides a list of all the available tools and their descriptions.
|
||||
For PR-Agent Pro users, it also enables to trigger each tool by checking the relevant box.
|
||||
For Qodo Merge Pro users, it also enables to trigger each tool by checking the relevant box.
|
||||
|
||||
It can be invoked manually by commenting on any PR:
|
||||
```
|
||||
|
@ -1,7 +1,7 @@
|
||||
## Overview
|
||||
The `improve` tool scans the PR code changes, and automatically generates [meaningful](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/pr_code_suggestions_prompts.toml#L41) suggestions for improving the PR code.
|
||||
The tool can be triggered automatically every time a new PR is [opened](../usage-guide/automations_and_usage.md#github-app-automatic-tools-when-a-new-pr-is-opened), or it can be invoked manually by commenting on any PR:
|
||||
```
|
||||
```toml
|
||||
/improve
|
||||
```
|
||||
|
||||
@ -9,7 +9,7 @@ The tool can be triggered automatically every time a new PR is [opened](../usage
|
||||
|
||||
{width=512}
|
||||
|
||||
Note that the `Apply this suggestion` checkbox, which interactively converts a suggestion into a commitable code comment, is available only for PR-Agent Pro 💎 users.
|
||||
Note that the `Apply this suggestion` checkbox, which interactively converts a suggestion into a commitable code comment, is available only for Qodo Merge Pro 💎 users.
|
||||
|
||||
|
||||
## Example usage
|
||||
@ -19,12 +19,12 @@ Note that the `Apply this suggestion` checkbox, which interactively converts a s
|
||||
Invoke the tool manually by commenting `/improve` on any PR. The code suggestions by default are presented as a single comment:
|
||||
|
||||
To edit [configurations](#configuration-options) related to the improve tool, use the following template:
|
||||
```
|
||||
```toml
|
||||
/improve --pr_code_suggestions.some_config1=... --pr_code_suggestions.some_config2=...
|
||||
```
|
||||
|
||||
For example, you can choose to present all the suggestions as commitable code comments, by running the following command:
|
||||
```
|
||||
```toml
|
||||
/improve --pr_code_suggestions.commitable_code_suggestions=true
|
||||
```
|
||||
|
||||
@ -36,8 +36,8 @@ Also note that collapsible are not supported in _Bitbucket_. Hence, the suggesti
|
||||
|
||||
### Automatic triggering
|
||||
|
||||
To run the `improve` automatically when a PR is opened, define in a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#wiki-configuration-file):
|
||||
```
|
||||
To run the `improve` automatically when a PR is opened, define in a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file):
|
||||
```toml
|
||||
[github_app]
|
||||
pr_commands = [
|
||||
"/improve",
|
||||
@ -54,14 +54,14 @@ num_code_suggestions_per_chunk = ...
|
||||
|
||||
### Assessing Impact 💎
|
||||
|
||||
Note that PR-Agent pro tracks two types of implementations:
|
||||
Note that Qodo Merge pro tracks two types of implementations:
|
||||
|
||||
- Direct implementation - when the user directly applies the suggestion by clicking the `Apply` checkbox.
|
||||
- Indirect implementation - when the user implements the suggestion in their IDE environment. In this case, PR-Agent will utilize, after each commit, a dedicated logic to identify if a suggestion was implemented, and will mark it as implemented.
|
||||
- Indirect implementation - when the user implements the suggestion in their IDE environment. In this case, Qodo Merge will utilize, after each commit, a dedicated logic to identify if a suggestion was implemented, and will mark it as implemented.
|
||||
|
||||
{width=512}
|
||||
|
||||
In post-process, PR-Agent counts the number of suggestions that were implemented, and provides general statistics and insights about the suggestions' impact on the PR process.
|
||||
In post-process, Qodo Merge counts the number of suggestions that were implemented, and provides general statistics and insights about the suggestions' impact on the PR process.
|
||||
|
||||
{width=512}
|
||||
|
||||
@ -70,15 +70,43 @@ In post-process, PR-Agent counts the number of suggestions that were implemented
|
||||
|
||||
## Usage Tips
|
||||
|
||||
### Implementing the proposed code suggestions
|
||||
Each generated suggestion consists of three key elements:
|
||||
|
||||
1. A single-line summary of the proposed change
|
||||
2. An expandable section containing a comprehensive description of the suggestion
|
||||
3. A diff snippet showing the recommended code modification (before and after)
|
||||
|
||||
We advise users to apply critical analysis and judgment when implementing the proposed suggestions.
|
||||
In addition to mistakes (which may happen, but are rare), sometimes the presented code modification may serve more as an _illustrative example_ than a direct applicable solution.
|
||||
In such cases, we recommend prioritizing the suggestion's detailed description, using the diff snippet primarily as a supporting reference.
|
||||
|
||||
### Dual publishing mode
|
||||
Our recommended approach for presenting code suggestions is through a [table](https://qodo-merge-docs.qodo.ai/tools/improve/#overview) (`--pr_code_suggestions.commitable_code_suggestions=false`).
|
||||
This method significantly reduces the PR footprint and allows for quick and easy digestion of multiple suggestions.
|
||||
|
||||
We also offer a complementary **dual publishing mode**. When enabled, suggestions exceeding a certain score threshold are not only displayed in the table, but also presented as commitable PR comments.
|
||||
This mode helps highlight suggestions deemed more critical.
|
||||
|
||||
To activate dual publishing mode, use the following setting:
|
||||
|
||||
```toml
|
||||
[pr_code_suggestions]
|
||||
dual_publishing_score_threshold = x
|
||||
```
|
||||
|
||||
Where x represents the minimum score threshold (>=) for suggestions to be presented as commitable PR comments in addition to the table. Default is -1 (disabled).
|
||||
|
||||
### Self-review
|
||||
If you set in a configuration file:
|
||||
```
|
||||
```toml
|
||||
[pr_code_suggestions]
|
||||
demand_code_suggestions_self_review = true
|
||||
```
|
||||
|
||||
The `improve` tool will add a checkbox below the suggestions, prompting user to acknowledge that they have reviewed the suggestions.
|
||||
You can set the content of the checkbox text via:
|
||||
```
|
||||
```toml
|
||||
[pr_code_suggestions]
|
||||
code_suggestions_self_review_text = "... (your text here) ..."
|
||||
```
|
||||
@ -86,18 +114,49 @@ code_suggestions_self_review_text = "... (your text here) ..."
|
||||
{width=512}
|
||||
|
||||
|
||||
💎 In addition, by setting:
|
||||
```
|
||||
[pr_code_suggestions]
|
||||
approve_pr_on_self_review = true
|
||||
```
|
||||
the tool can automatically approve the PR when the user checks the self-review checkbox.
|
||||
|
||||
!!! tip "Tip - demanding self-review from the PR author"
|
||||
If you set the number of required reviewers for a PR to 2, this effectively means that the PR author must click the self-review checkbox before the PR can be merged (in addition to a human reviewer).
|
||||
|
||||
!!! tip "Tip - demanding self-review from the PR author 💎"
|
||||
|
||||
By setting:
|
||||
```toml
|
||||
[pr_code_suggestions]
|
||||
approve_pr_on_self_review = true
|
||||
```
|
||||
the tool can automatically add an approval when the PR author clicks the self-review checkbox.
|
||||
|
||||
|
||||
- If you set the number of required reviewers for a PR to 2, this effectively means that the PR author must click the self-review checkbox before the PR can be merged (in addition to a human reviewer).
|
||||
|
||||
{width=512}
|
||||
|
||||
- If you keep the number of required reviewers for a PR to 1 and enable this configuration, this effectively means that the PR author can approve the PR by actively clicking the self-review checkbox.
|
||||
|
||||
To prevent unauthorized approvals, this configuration defaults to false, and cannot be altered through online comments; enabling requires a direct update to the configuration file and a commit to the repository. This ensures that utilizing the feature demands a deliberate documented decision by the repository owner.
|
||||
|
||||
|
||||
### How many code suggestions are generated?
|
||||
Qodo Merge uses a dynamic strategy to generate code suggestions based on the size of the pull request (PR). Here's how it works:
|
||||
|
||||
1) Chunking large PRs:
|
||||
|
||||
- Qodo Merge divides large PRs into 'chunks'.
|
||||
- Each chunk contains up to `pr_code_suggestions.max_context_tokens` tokens (default: 14,000).
|
||||
|
||||
|
||||
2) Generating suggestions:
|
||||
|
||||
- For each chunk, Qodo Merge generates up to `pr_code_suggestions.num_code_suggestions_per_chunk` suggestions (default: 4).
|
||||
|
||||
|
||||
This approach has two main benefits:
|
||||
|
||||
- Scalability: The number of suggestions scales with the PR size, rather than being fixed.
|
||||
- Quality: By processing smaller chunks, the AI can maintain higher quality suggestions, as larger contexts tend to decrease AI performance.
|
||||
|
||||
Note: Chunking is primarily relevant for large PRs. For most PRs (up to 500 lines of code), Qodo Merge will be able to process the entire code in a single call.
|
||||
|
||||
|
||||
### 'Extra instructions' and 'best practices'
|
||||
|
||||
#### Extra instructions
|
||||
@ -108,7 +167,7 @@ You can use the `extra_instructions` configuration option to give the AI model a
|
||||
Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Specify relevant aspects that you want the model to focus on.
|
||||
|
||||
Examples for possible instructions:
|
||||
```
|
||||
```toml
|
||||
[pr_code_suggestions]
|
||||
extra_instructions="""\
|
||||
(1) Answer in japanese
|
||||
@ -141,16 +200,16 @@ This file is only an example. Since it is used as a prompt for an AI model, we w
|
||||
2) A lengthy file probably represent a more "**generic**" set of guidelines, which the AI model is already familiar with. The objective is to focus on a more targeted set of guidelines tailored to the specific needs of this project.
|
||||
|
||||
##### Local and global best practices
|
||||
By default, PR-Agent will look for a local `best_practices.md` wiki file in the root of the relevant local repo.
|
||||
By default, Qodo Merge will look for a local `best_practices.md` wiki file in the root of the relevant local repo.
|
||||
|
||||
If you want to enable also a global `best_practices.md` wiki file, set first in the global configuration file:
|
||||
|
||||
```
|
||||
```toml
|
||||
[best_practices]
|
||||
enable_global_best_practices = true
|
||||
```
|
||||
|
||||
Then, create a `best_practices.md` wiki file in the root of [global](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#global-configuration-file) configuration repository, `pr-agent-settings`.
|
||||
Then, create a `best_practices.md` wiki file in the root of [global](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#global-configuration-file) configuration repository, `pr-agent-settings`.
|
||||
|
||||
##### Example results
|
||||
|
||||
@ -170,22 +229,18 @@ Using a combination of both can help the AI model to provide relevant and tailor
|
||||
??? example "General options"
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>num_code_suggestions</b></td>
|
||||
<td>Number of code suggestions provided by the 'improve' tool. Default is 4 for CLI, 0 for auto tools.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>extra_instructions</b></td>
|
||||
<td>Optional extra instructions to the tool. For example: "focus on the changes in the file X. Ignore change in ...".</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>rank_suggestions</b></td>
|
||||
<td>If set to true, the tool will rank the suggestions, based on importance. Default is false.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>commitable_code_suggestions</b></td>
|
||||
<td>If set to true, the tool will display the suggestions as commitable code comments. Default is false.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>dual_publishing_score_threshold</b></td>
|
||||
<td>Minimum score threshold for suggestions to be presented as commitable PR comments in addition to the table. Default is -1 (disabled).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>persistent_comment</b></td>
|
||||
<td>If set to true, the improve comment will be persistent, meaning that every new improve request will edit the previous one. Default is false.</td>
|
||||
@ -212,39 +267,35 @@ Using a combination of both can help the AI model to provide relevant and tailor
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
??? example "params for 'extended' mode"
|
||||
??? example "Params for number of suggestions and AI calls"
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>auto_extended_mode</b></td>
|
||||
<td>Enable extended mode automatically (no need for the --extended option). Default is true.</td>
|
||||
<td>Enable chunking the PR code and running the tool on each chunk. Default is true.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>num_code_suggestions_per_chunk</b></td>
|
||||
<td>Number of code suggestions provided by the 'improve' tool, per chunk. Default is 5.</td>
|
||||
<td>Number of code suggestions provided by the 'improve' tool, per chunk. Default is 4.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>max_number_of_calls</b></td>
|
||||
<td>Maximum number of chunks. Default is 3.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>rank_extended_suggestions</b></td>
|
||||
<td>If set to true, the tool will rank the suggestions, based on importance. Default is true.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>max_number_of_calls</b></td>
|
||||
<td>Maximum number of chunks. Default is 5.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>final_clip_factor</b></td>
|
||||
<td>Factor to remove suggestions with low confidence. Default is 0.9.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## A note on code suggestions quality
|
||||
|
||||
- AI models for code are getting better and better (Sonnet-3.5 and GPT-4), but they are not flawless. Not all the suggestions will be perfect, and a user should not accept all of them automatically. Critical reading and judgment are required.
|
||||
- While mistakes of the AI are rare but can happen, a real benefit from the suggestions of the `improve` (and [`review`](https://pr-agent-docs.codium.ai/tools/review/)) tool is to catch, with high probability, **mistakes or bugs done by the PR author**, when they happen. So, it's a good practice to spend the needed ~30-60 seconds to review the suggestions, even if not all of them are always relevant.
|
||||
- While mistakes of the AI are rare but can happen, a real benefit from the suggestions of the `improve` (and [`review`](https://qodo-merge-docs.qodo.ai/tools/review/)) tool is to catch, with high probability, **mistakes or bugs done by the PR author**, when they happen. So, it's a good practice to spend the needed ~30-60 seconds to review the suggestions, even if not all of them are always relevant.
|
||||
- The hierarchical structure of the suggestions is designed to help the user to _quickly_ understand them, and to decide which ones are relevant and which are not:
|
||||
|
||||
- Only if the `Category` header is relevant, the user should move to the summarized suggestion description
|
||||
- Only if the summarized suggestion description is relevant, the user should click on the collapsible, to read the full suggestion description with a code preview example.
|
||||
|
||||
- In addition, we recommend to use the [`extra_instructions`](https://pr-agent-docs.codium.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project.
|
||||
- The interactive [PR chat](https://pr-agent-docs.codium.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model.
|
||||
- In addition, we recommend to use the [`extra_instructions`](https://qodo-merge-docs.qodo.ai/tools/improve/#extra-instructions-and-best-practices) field to guide the model to suggestions that are more relevant to the specific needs of the project.
|
||||
- The interactive [PR chat](https://qodo-merge-docs.qodo.ai/chrome-extension/) also provides an easy way to get more tailored suggestions and feedback from the AI model.
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Tools
|
||||
|
||||
Here is a list of PR-Agent tools, each with a dedicated page that explains how to use it:
|
||||
Here is a list of Qodo Merge tools, each with a dedicated page that explains how to use it:
|
||||
|
||||
| Tool | Description |
|
||||
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
@ -19,4 +19,4 @@ Here is a list of PR-Agent tools, each with a dedicated page that explains how t
|
||||
| **💎 [Improve Component (`/improve_component component_name`](./improve_component.md))** | Generates code suggestions for a specific code component that changed in the PR |
|
||||
| **💎 [CI Feedback (`/checks ci_job`](./ci_feedback.md))** | Automatically generates feedback and analysis for a failed CI job |
|
||||
|
||||
Note that the tools marked with 💎 are available only for PR-Agent Pro users.
|
||||
Note that the tools marked with 💎 are available only for Qodo Merge Pro users.
|
@ -8,7 +8,7 @@ The tool can be triggered automatically every time a new PR is [opened](../usage
|
||||
|
||||
Note that the main purpose of the `review` tool is to provide the **PR reviewer** with useful feedbacks and insights. The PR author, in contrast, may prefer to save time and focus on the output of the [improve](./improve.md) tool, which provides actionable code suggestions.
|
||||
|
||||
(Read more about the different personas in the PR process and how PR-Agent aims to assist them in our [blog](https://www.codium.ai/blog/understanding-the-challenges-and-pain-points-of-the-pull-request-cycle/))
|
||||
(Read more about the different personas in the PR process and how Qodo Merge aims to assist them in our [blog](https://www.codium.ai/blog/understanding-the-challenges-and-pain-points-of-the-pull-request-cycle/))
|
||||
|
||||
|
||||
## Example usage
|
||||
@ -30,7 +30,7 @@ If you want to edit [configurations](#configuration-options), add the relevant o
|
||||
|
||||
### Automatic triggering
|
||||
|
||||
To run the `review` automatically when a PR is opened, define in a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#wiki-configuration-file):
|
||||
To run the `review` automatically when a PR is opened, define in a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file):
|
||||
```
|
||||
[github_app]
|
||||
pr_commands = [
|
||||
@ -49,7 +49,7 @@ num_code_suggestions = ...
|
||||
[//]: # ()
|
||||
[//]: # (### Incremental Mode)
|
||||
|
||||
[//]: # (Incremental review only considers changes since the last PR-Agent review. This can be useful when working on the PR in an iterative manner, and you want to focus on the changes since the last review instead of reviewing the entire PR again.)
|
||||
[//]: # (Incremental review only considers changes since the last Qodo Merge review. This can be useful when working on the PR in an iterative manner, and you want to focus on the changes since the last review instead of reviewing the entire PR again.)
|
||||
|
||||
[//]: # (For invoking the incremental mode, the following command can be used:)
|
||||
|
||||
@ -198,7 +198,7 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
|
||||
On the other hand, if you find one of the enabled features to be irrelevant for your use case, disable it. No default configuration can fit all use cases.
|
||||
|
||||
!!! tip "Automation"
|
||||
When you first install PR-Agent app, the [default mode](../usage-guide/automations_and_usage.md#github-app-automatic-tools-when-a-new-pr-is-opened) for the `review` tool is:
|
||||
When you first install Qodo Merge app, the [default mode](../usage-guide/automations_and_usage.md#github-app-automatic-tools-when-a-new-pr-is-opened) for the `review` tool is:
|
||||
```
|
||||
pr_commands = ["/review --pr_reviewer.num_code_suggestions=0", ...]
|
||||
```
|
||||
@ -237,7 +237,7 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
|
||||
|
||||
!!! tip "Auto-approval"
|
||||
|
||||
PR-Agent can approve a PR when a specific comment is invoked.
|
||||
Qodo Merge can approve a PR when a specific comment is invoked.
|
||||
|
||||
To ensure safety, the auto-approval feature is disabled by default. To enable auto-approval, you need to actively set in a pre-defined configuration file the following:
|
||||
```
|
||||
@ -251,7 +251,7 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
|
||||
```
|
||||
/review auto_approve
|
||||
```
|
||||
PR-Agent will automatically approve the PR, and add a comment with the approval.
|
||||
Qodo Merge will automatically approve the PR, and add a comment with the approval.
|
||||
|
||||
|
||||
You can also enable auto-approval only if the PR meets certain requirements, such as that the `estimated_review_effort` label is equal or below a certain threshold, by adjusting the flag:
|
||||
|
@ -8,9 +8,9 @@ For example:
|
||||
{width=768}
|
||||
|
||||
|
||||
PR-Agent will examine the code component and will extract the most relevant keywords to search for similar code:
|
||||
Qodo Merge will examine the code component and will extract the most relevant keywords to search for similar code:
|
||||
|
||||
- `extracted keywords`: the keywords that were extracted from the code by PR-Agent. the link will open a search page with the extracted keywords, to allow the user to modify the search if needed.
|
||||
- `extracted keywords`: the keywords that were extracted from the code by Qodo Merge. the link will open a search page with the extracted keywords, to allow the user to modify the search if needed.
|
||||
- `search context`: the context in which the search will be performed, organization's codebase or open-source code (Global).
|
||||
- `similar code`: the most similar code components found. the link will open the code component in the relevant file.
|
||||
- `relevant repositories`: the open-source repositories in which that are relevant to the searched code component and it's keywords.
|
||||
|
@ -1,30 +1,18 @@
|
||||
## PR-Agent Pro Models
|
||||
## Qodo Merge Pro Models
|
||||
|
||||
The default models used by PR-Agent Pro are OpenAI's GPT-4 models. We use a combination of GPT-4-Turbo and GPT-4o to strike a balance between speed and quality.
|
||||
The default models used by Qodo Merge Pro are a combination of Claude-3.5-sonnet and OpenAI's GPT-4 models.
|
||||
|
||||
However, users can change the model used by PR-Agent Pro to Claude-3.5-sonnet, which also excels at code tasks.
|
||||
To do so, add the following to your [configuration](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/) file:
|
||||
Users can configure Qodo Merge Pro to use solely a specific model by editing the [configuration](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) file.
|
||||
|
||||
For example, to restrict Qodo Merge Pro to using only `Claude-3.5-sonnet`, add this setting:
|
||||
|
||||
```
|
||||
[config]
|
||||
model="claude-3-5-sonnet"
|
||||
```
|
||||
|
||||
Note that Claude models tend to give lower scores for each suggestion, so if you are using a [threshold](https://pr-agent-docs.codium.ai/tools/improve/#configuration-options):
|
||||
Or to restrict Qodo Merge Pro to using only `GPT-4o`, add this setting:
|
||||
```
|
||||
[pr_code_suggestions]
|
||||
suggestions_score_threshold=...
|
||||
```
|
||||
You might need to adjust this value when switching models.
|
||||
|
||||
### Dedicated models per tool
|
||||
|
||||
You can also use different models for different tools. For example, you can use the Claude-3.5-sonnet model only for the `improve` tool (and keep the default GPT-4 model for the other tools) by adding the following to your configuration file:
|
||||
```
|
||||
[github_app]
|
||||
pr_commands = [
|
||||
"/describe --pr_description.final_update_message=false",
|
||||
"/review --pr_reviewer.num_code_suggestions=0",
|
||||
"/improve --config.model=claude-3-5-sonnet",
|
||||
]
|
||||
[config]
|
||||
model="gpt-4o"
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
## Show possible configurations
|
||||
The possible configurations of pr-agent are stored in [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml).
|
||||
In the [tools](https://pr-agent-docs.codium.ai/tools/) page you can find explanations on how to use these configurations for each tool.
|
||||
The possible configurations of Qodo Merge are stored in [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml).
|
||||
In the [tools](https://qodo-merge-docs.qodo.ai/tools/) page you can find explanations on how to use these configurations for each tool.
|
||||
|
||||
To print all the available configurations as a comment on your PR, you can use the following command:
|
||||
```
|
||||
@ -22,7 +22,7 @@ Will output an additional field showing the actual configurations used for the `
|
||||
|
||||
## Ignoring files from analysis
|
||||
|
||||
In some cases, you may want to exclude specific files or directories from the analysis performed by CodiumAI PR-Agent. This can be useful, for example, when you have files that are generated automatically or files that shouldn't be reviewed, like vendor code.
|
||||
In some cases, you may want to exclude specific files or directories from the analysis performed by Qodo Merge. This can be useful, for example, when you have files that are generated automatically or files that shouldn't be reviewed, like vendor code.
|
||||
|
||||
You can ignore files or folders using the following methods:
|
||||
- `IGNORE.GLOB`
|
||||
@ -52,7 +52,7 @@ regex = ['.*\.py$']
|
||||
|
||||
## Extra instructions
|
||||
|
||||
All PR-Agent tools have a parameter called `extra_instructions`, that enables to add free-text extra instructions. Example usage:
|
||||
All Qodo Merge tools have a parameter called `extra_instructions`, that enables to add free-text extra instructions. Example usage:
|
||||
```
|
||||
/update_changelog --pr_update_changelog.extra_instructions="Make sure to update also the version ..."
|
||||
```
|
||||
@ -64,8 +64,8 @@ This mode provides a very good speed-quality-cost tradeoff, and can handle most
|
||||
When the PR is above the token limit, it employs a [PR Compression strategy](../core-abilities/index.md).
|
||||
|
||||
However, for very large PRs, or in case you want to emphasize quality over speed and cost, there are two possible solutions:
|
||||
1) [Use a model](https://codium-ai.github.io/Docs-PR-Agent/usage-guide/#changing-a-model) with larger context, like GPT-32K, or claude-100K. This solution will be applicable for all the tools.
|
||||
2) For the `/improve` tool, there is an ['extended' mode](https://codium-ai.github.io/Docs-PR-Agent/tools/#improve) (`/improve --extended`),
|
||||
1) [Use a model](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) with larger context, like GPT-32K, or claude-100K. This solution will be applicable for all the tools.
|
||||
2) For the `/improve` tool, there is an ['extended' mode](https://qodo-merge-docs.qodo.ai/tools/improve/) (`/improve --extended`),
|
||||
which divides the PR into chunks, and processes each chunk separately. With this mode, regardless of the model, no compression will be done (but for large PRs, multiple model calls may occur)
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ By default, around any change in your PR, git patch provides three lines of cont
|
||||
code line that already existed in the file...
|
||||
```
|
||||
|
||||
PR-Agent will try to increase the number of lines of context, via the parameter:
|
||||
Qodo Merge will try to increase the number of lines of context, via the parameter:
|
||||
```
|
||||
[config]
|
||||
patch_extra_lines_before=3
|
||||
@ -94,12 +94,12 @@ patch_extra_lines_after=1
|
||||
|
||||
Increasing this number provides more context to the model, but will also increase the token budget, and may overwhelm the model with too much information, unrelated to the actual PR code changes.
|
||||
|
||||
If the PR is too large (see [PR Compression strategy](https://github.com/Codium-ai/pr-agent/blob/main/PR_COMPRESSION.md)), PR-Agent may automatically set this number to 0, and will use the original git patch.
|
||||
If the PR is too large (see [PR Compression strategy](https://github.com/Codium-ai/pr-agent/blob/main/PR_COMPRESSION.md)), Qodo Merge may automatically set this number to 0, and will use the original git patch.
|
||||
|
||||
|
||||
## Editing the prompts
|
||||
|
||||
The prompts for the various PR-Agent tools are defined in the `pr_agent/settings` folder.
|
||||
The prompts for the various Qodo Merge tools are defined in the `pr_agent/settings` folder.
|
||||
In practice, the prompts are loaded and stored as a standard setting object.
|
||||
Hence, editing them is similar to editing any other configuration value - just place the relevant key in `.pr_agent.toml`file, and override the default value.
|
||||
|
||||
@ -138,7 +138,7 @@ LANGSMITH_BASE_URL=<url>
|
||||
|
||||
## Ignoring automatic commands in PRs
|
||||
|
||||
In some cases, you may want to automatically ignore specific PRs . PR-Agent enables you to ignore PR with a specific title, or from/to specific branches (regex matching).
|
||||
In some cases, you may want to automatically ignore specific PRs . Qodo Merge enables you to ignore PR with a specific title, or from/to specific branches (regex matching).
|
||||
|
||||
To ignore PRs with a specific title such as "[Bump]: ...", you can add the following to your `configuration.toml` file:
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
## Local repo (CLI)
|
||||
When running from your locally cloned PR-Agent repo (CLI), your local configuration file will be used.
|
||||
When running from your locally cloned Qodo Merge repo (CLI), your local configuration file will be used.
|
||||
Examples of invoking the different tools via the CLI:
|
||||
|
||||
- **Review**: `python -m pr_agent.cli --pr_url=<pr_url> review`
|
||||
@ -28,7 +28,7 @@ This is useful for debugging or experimenting with different tools.
|
||||
|
||||
(3)
|
||||
|
||||
**git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L5) field in a configuration file determines the GIT provider that will be used by PR-Agent. Currently, the following providers are supported:
|
||||
**git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L5) field in a configuration file determines the GIT provider that will be used by Qodo Merge. Currently, the following providers are supported:
|
||||
`
|
||||
"github", "gitlab", "bitbucket", "azure", "codecommit", "local", "gerrit"
|
||||
`
|
||||
@ -39,7 +39,7 @@ Default is "github".
|
||||
|
||||
### Online usage
|
||||
|
||||
Online usage means invoking PR-Agent tools by [comments](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR.
|
||||
Online usage means invoking Qodo Merge tools by [comments](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR.
|
||||
Commands for invoking the different tools via comments:
|
||||
|
||||
- **Review**: `/review`
|
||||
@ -60,8 +60,8 @@ Any configuration value in [configuration file](https://github.com/Codium-ai/pr-
|
||||
|
||||
## GitHub App
|
||||
|
||||
!!! note "Configurations for PR-Agent Pro"
|
||||
PR-Agent Pro for GitHub is an App, hosted by CodiumAI. So all the instructions below are relevant also for PR-Agent Pro users.
|
||||
!!! note "Configurations for Qodo Merge Pro"
|
||||
Qodo Merge Pro for GitHub is an App, hosted by CodiumAI. So all the instructions below are relevant also for Qodo Merge Pro users.
|
||||
Same goes for [GitLab webhook](#gitlab-webhook) and [BitBucket App](#bitbucket-app) sections.
|
||||
|
||||
### GitHub app automatic tools when a new PR is opened
|
||||
@ -77,10 +77,10 @@ pr_commands = [
|
||||
"/improve",
|
||||
]
|
||||
```
|
||||
This means that when a new PR is opened/reopened or marked as ready for review, PR-Agent will run the `describe`, `review` and `improve` tools.
|
||||
This means that when a new PR is opened/reopened or marked as ready for review, Qodo Merge will run the `describe`, `review` and `improve` tools.
|
||||
For the `review` tool, for example, the `num_code_suggestions` parameter will be set to 0.
|
||||
|
||||
You can override the default tool parameters by using one the three options for a [configuration file](https://codium-ai.github.io/Docs-PR-Agent/usage-guide/#configuration-options): **wiki**, **local**, or **global**.
|
||||
You can override the default tool parameters by using one the three options for a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/): **wiki**, **local**, or **global**.
|
||||
For example, if your local `.pr_agent.toml` file contains:
|
||||
```
|
||||
[pr_description]
|
||||
@ -108,10 +108,10 @@ push_commands = [
|
||||
"/review --pr_reviewer.num_code_suggestions=0 --pr_reviewer.final_update_message=false",
|
||||
]
|
||||
```
|
||||
This means that when new code is pushed to the PR, the PR-Agent will run the `describe` and `review` tools, with the specified parameters.
|
||||
This means that when new code is pushed to the PR, the Qodo Merge will run the `describe` and `review` tools, with the specified parameters.
|
||||
|
||||
## GitHub Action
|
||||
`GitHub Action` is a different way to trigger PR-Agent tools, and uses a different configuration mechanism than `GitHub App`.<br>
|
||||
`GitHub Action` is a different way to trigger Qodo Merge tools, and uses a different configuration mechanism than `GitHub App`.<br>
|
||||
You can configure settings for `GitHub Action` by adding environment variables under the env section in `.github/workflows/pr_agent.yml` file.
|
||||
Specifically, start by setting the following environment variables:
|
||||
```yaml
|
||||
@ -133,14 +133,14 @@ If not set, the default configuration is `["opened", "reopened", "ready_for_revi
|
||||
Review result is output as JSON to `steps.{step-id}.outputs.review` property.
|
||||
The JSON structure is equivalent to the yaml data structure defined in [pr_reviewer_prompts.toml](https://github.com/idubnori/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml).
|
||||
|
||||
Note that you can give additional config parameters by adding environment variables to `.github/workflows/pr_agent.yml`, or by using a `.pr_agent.toml` [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/#global-configuration-file) in the root of your repo
|
||||
Note that you can give additional config parameters by adding environment variables to `.github/workflows/pr_agent.yml`, or by using a `.pr_agent.toml` [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#global-configuration-file) in the root of your repo
|
||||
|
||||
For example, you can set an environment variable: `pr_description.publish_labels=false`, or add a `.pr_agent.toml` file with the following content:
|
||||
```
|
||||
[pr_description]
|
||||
publish_labels = false
|
||||
```
|
||||
to prevent PR-Agent from publishing labels when running the `describe` tool.
|
||||
to prevent Qodo Merge from publishing labels when running the `describe` tool.
|
||||
|
||||
## GitLab Webhook
|
||||
After setting up a GitLab webhook, to control which commands will run automatically when a new MR is opened, you can set the `pr_commands` parameter in the configuration file, similar to the GitHub App:
|
||||
@ -168,22 +168,22 @@ push_commands = [
|
||||
Note that to use the 'handle_push_trigger' feature, you need to give the gitlab webhook also the "Push events" scope.
|
||||
|
||||
## BitBucket App
|
||||
Similar to GitHub app, when running PR-Agent from BitBucket App, the default [configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) from a pre-built docker will be initially loaded.
|
||||
Similar to GitHub app, when running Qodo Merge from BitBucket App, the default [configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml) from a pre-built docker will be initially loaded.
|
||||
|
||||
By uploading a local `.pr_agent.toml` file to the root of the repo's main branch, you can edit and customize any configuration parameter. Note that you need to upload `.pr_agent.toml` prior to creating a PR, in order for the configuration to take effect.
|
||||
|
||||
For example, if your local `.pr_agent.toml` file contains:
|
||||
```
|
||||
[pr_reviewer]
|
||||
inline_code_comments = true
|
||||
extra_instructions = "Answer in japanese"
|
||||
```
|
||||
|
||||
Each time you invoke a `/review` tool, it will use inline code comments.
|
||||
Each time you invoke a `/review` tool, it will use the extra instructions you set in the local configuration file.
|
||||
|
||||
|
||||
Note that among other limitations, BitBucket provides relatively low rate-limits for applications (up to 1000 requests per hour), and does not provide an API to track the actual rate-limit usage.
|
||||
If you experience lack of responses from PR-Agent, you might want to set: `bitbucket_app.avoid_full_files=true` in your configuration file.
|
||||
This will prevent PR-Agent from acquiring the full file content, and will only use the diff content. This will reduce the number of requests made to BitBucket, at the cost of small decrease in accuracy, as dynamic context will not be applicable.
|
||||
If you experience lack of responses from Qodo Merge, you might want to set: `bitbucket_app.avoid_full_files=true` in your configuration file.
|
||||
This will prevent Qodo Merge from acquiring the full file content, and will only use the diff content. This will reduce the number of requests made to BitBucket, at the cost of small decrease in accuracy, as dynamic context will not be applicable.
|
||||
|
||||
|
||||
### BitBucket Self-Hosted App automatic tools
|
||||
|
@ -1,7 +1,7 @@
|
||||
The different tools and sub-tools used by CodiumAI PR-Agent are adjustable via the **[configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml)**.
|
||||
The different tools and sub-tools used by Qodo Merge are adjustable via the **[configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml)**.
|
||||
|
||||
In addition to general configuration options, each tool has its own configurations. For example, the `review` tool will use parameters from the [pr_reviewer](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L16) section in the configuration file.
|
||||
See the [Tools Guide](https://codium-ai.github.io/Docs-PR-Agent/tools/) for a detailed description of the different tools and their configurations.
|
||||
See the [Tools Guide](https://qodo-merge-docs.qodo.ai/tools/) for a detailed description of the different tools and their configurations.
|
||||
|
||||
There are three ways to set persistent configurations:
|
||||
|
||||
@ -20,7 +20,7 @@ In terms of precedence, wiki configurations will override local configurations,
|
||||
|
||||
`Platforms supported: GitHub, GitLab`
|
||||
|
||||
With PR-Agent-Pro, you can set configurations by creating a page called `.pr_agent.toml` in the [wiki](https://github.com/Codium-ai/pr-agent/wiki/pr_agent.toml) of the repo.
|
||||
With Qodo Merge Pro, you can set configurations by creating a page called `.pr_agent.toml` in the [wiki](https://github.com/Codium-ai/pr-agent/wiki/pr_agent.toml) of the repo.
|
||||
The advantage of this method is that it allows to set configurations without needing to commit new content to the repo - just edit the wiki page and **save**.
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ An example content:
|
||||
generate_ai_title=true
|
||||
```
|
||||
|
||||
PR-Agent will know to remove the surrounding quotes when reading the configuration content.
|
||||
Qodo Merge will know to remove the surrounding quotes when reading the configuration content.
|
||||
|
||||
## Local configuration file
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Usage guide
|
||||
|
||||
This page provides a detailed guide on how to use PR-Agent.
|
||||
It includes information on how to adjust PR-Agent configurations, define which tools will run automatically, and other advanced configurations.
|
||||
This page provides a detailed guide on how to use Qodo Merge.
|
||||
It includes information on how to adjust Qodo Merge configurations, define which tools will run automatically, and other advanced configurations.
|
||||
|
||||
|
||||
- [Introduction](./introduction.md)
|
||||
@ -23,4 +23,4 @@ It includes information on how to adjust PR-Agent configurations, define which t
|
||||
- [Changing a model](./additional_configurations.md#changing-a-model)
|
||||
- [Patch Extra Lines](./additional_configurations.md#patch-extra-lines)
|
||||
- [Editing the prompts](./additional_configurations.md#editing-the-prompts)
|
||||
- [PR-Agent Pro Models](./PR_agent_pro_models.md)
|
||||
- [Qodo Merge Pro Models](./PR_agent_pro_models.md)
|
@ -1,13 +1,13 @@
|
||||
|
||||
After [installation](https://pr-agent-docs.codium.ai/installation/), there are three basic ways to invoke CodiumAI PR-Agent:
|
||||
After [installation](https://qodo-merge-docs.qodo.ai/installation/), there are three basic ways to invoke Qodo Merge:
|
||||
|
||||
1. Locally running a CLI command
|
||||
2. Online usage - by [commenting](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901) on a PR
|
||||
3. Enabling PR-Agent tools to run automatically when a new PR is opened
|
||||
3. Enabling Qodo Merge tools to run automatically when a new PR is opened
|
||||
|
||||
|
||||
Specifically, CLI commands can be issued by invoking a pre-built [docker image](https://pr-agent-docs.codium.ai/installation/locally/#using-docker-image), or by invoking a [locally cloned repo](https://pr-agent-docs.codium.ai/installation/locally/#run-from-source).
|
||||
Specifically, CLI commands can be issued by invoking a pre-built [docker image](https://qodo-merge-docs.qodo.ai/installation/locally/#using-docker-image), or by invoking a [locally cloned repo](https://qodo-merge-docs.qodo.ai/installation/locally/#run-from-source).
|
||||
|
||||
For online usage, you will need to setup either a [GitHub App](https://pr-agent-docs.codium.ai/installation/github/#run-as-a-github-app) or a [GitHub Action](https://pr-agent-docs.codium.ai/installation/github/#run-as-a-github-action) (GitHub), a [GitLab webhook](https://pr-agent-docs.codium.ai/installation/gitlab/#run-a-gitlab-webhook-server) (GitLab), or a [BitBucket App](https://pr-agent-docs.codium.ai/installation/bitbucket/#run-using-codiumai-hosted-bitbucket-app) (BitBucket).
|
||||
These platforms also enable to run PR-Agent specific tools automatically when a new PR is opened, or on each push to a branch.
|
||||
For online usage, you will need to setup either a [GitHub App](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-app) or a [GitHub Action](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) (GitHub), a [GitLab webhook](https://qodo-merge-docs.qodo.ai/installation/gitlab/#run-a-gitlab-webhook-server) (GitLab), or a [BitBucket App](https://qodo-merge-docs.qodo.ai/installation/bitbucket/#run-using-codiumai-hosted-bitbucket-app) (BitBucket).
|
||||
These platforms also enable to run Qodo Merge specific tools automatically when a new PR is opened, or on each push to a branch.
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
|
||||
Unfortunately, it is not possible in GitHub to disable mail notifications from a specific user.
|
||||
If you are subscribed to notifications for a repo with PR-Agent, we recommend turning off notifications for PR comments, to avoid lengthy emails:
|
||||
If you are subscribed to notifications for a repo with Qodo Merge, we recommend turning off notifications for PR comments, to avoid lengthy emails:
|
||||
|
||||
{width=512}
|
||||
|
||||
As an alternative, you can filter in your mail provider the notifications specifically from the PR-Agent bot, [see how](https://www.quora.com/How-can-you-filter-emails-for-specific-people-in-Gmail#:~:text=On%20the%20Filters%20and%20Blocked,the%20body%20of%20the%20email).
|
||||
As an alternative, you can filter in your mail provider the notifications specifically from the Qodo Merge bot, [see how](https://www.quora.com/How-can-you-filter-emails-for-specific-people-in-Gmail#:~:text=On%20the%20Filters%20and%20Blocked,the%20body%20of%20the%20email).
|
||||
|
||||
{width=512}
|
||||
|
||||
|
||||
Another option to reduce the mail overload, yet still receive notifications on PR-Agent tools, is to disable the help collapsible section in PR-Agent bot comments.
|
||||
Another option to reduce the mail overload, yet still receive notifications on Qodo Merge tools, is to disable the help collapsible section in Qodo Merge bot comments.
|
||||
This can done by setting `enable_help_text=false` for the relevant tool in the configuration file.
|
||||
For example, to disable the help text for the `pr_reviewer` tool, set:
|
||||
```
|
||||
|
@ -1,11 +1,11 @@
|
||||
site_name: PR-Agent Documentation
|
||||
site_name: Qodo Merge (formerly known as PR-Agent)
|
||||
repo_url: https://github.com/Codium-ai/pr-agent
|
||||
repo_name: Codium-ai/pr-agent
|
||||
|
||||
nav:
|
||||
- Overview:
|
||||
- 'index.md'
|
||||
- 💎 PR-Agent Pro: 'overview/pr_agent_pro.md'
|
||||
- 💎 Qodo Merge Pro: 'overview/pr_agent_pro.md'
|
||||
- Data Privacy: 'overview/data_privacy.md'
|
||||
- Installation:
|
||||
- 'installation/index.md'
|
||||
@ -14,7 +14,7 @@ nav:
|
||||
- GitLab: 'installation/gitlab.md'
|
||||
- BitBucket: 'installation/bitbucket.md'
|
||||
- Azure DevOps: 'installation/azure.md'
|
||||
- 💎 PR-Agent Pro: 'installation/pr_agent_pro.md'
|
||||
- 💎 Qodo Merge Pro: 'installation/pr_agent_pro.md'
|
||||
- Usage Guide:
|
||||
- 'usage-guide/index.md'
|
||||
- Introduction: 'usage-guide/introduction.md'
|
||||
@ -23,7 +23,7 @@ nav:
|
||||
- Managing Mail Notifications: 'usage-guide/mail_notifications.md'
|
||||
- Changing a Model: 'usage-guide/changing_a_model.md'
|
||||
- Additional Configurations: 'usage-guide/additional_configurations.md'
|
||||
- 💎 PR-Agent Pro Models: 'usage-guide/PR_agent_pro_models'
|
||||
- 💎 Qodo Merge Pro Models: 'usage-guide/PR_agent_pro_models'
|
||||
- Tools:
|
||||
- 'tools/index.md'
|
||||
- Describe: 'tools/describe.md'
|
||||
@ -53,7 +53,7 @@ nav:
|
||||
- Static code analysis: 'core-abilities/static_code_analysis.md'
|
||||
- Code Fine-tuning Benchmark: 'finetuning_benchmark/index.md'
|
||||
- Chrome Extension:
|
||||
- PR-Agent Chrome Extension: 'chrome-extension/index.md'
|
||||
- Qodo Merge Chrome Extension: 'chrome-extension/index.md'
|
||||
- Features: 'chrome-extension/features.md'
|
||||
- Data Privacy: 'chrome-extension/data_privacy.md'
|
||||
- FAQ:
|
||||
|
@ -101,11 +101,11 @@ def process_patch_lines(patch_str, original_file_str, patch_extra_lines_before,
|
||||
# Update start and size in one line each
|
||||
extended_start1, extended_start2 = extended_start1 + i, extended_start2 + i
|
||||
extended_size1, extended_size2 = extended_size1 - i, extended_size2 - i
|
||||
get_logger().debug(f"Found section header in line {i} before the hunk")
|
||||
# get_logger().debug(f"Found section header in line {i} before the hunk")
|
||||
section_header = ''
|
||||
break
|
||||
if not found_header:
|
||||
get_logger().debug(f"Section header not found in the extra lines before the hunk")
|
||||
# get_logger().debug(f"Section header not found in the extra lines before the hunk")
|
||||
extended_start1, extended_size1, extended_start2, extended_size2 = \
|
||||
_calc_context_limits(patch_extra_lines_before)
|
||||
else:
|
||||
|
@ -100,8 +100,8 @@ def convert_to_markdown_v2(output_data: dict,
|
||||
|
||||
emojis = {
|
||||
"Can be split": "🔀",
|
||||
"Possible issues": "⚡",
|
||||
"Key issues to review": "⚡",
|
||||
"Recommended focus areas for review": "⚡",
|
||||
"Score": "🏅",
|
||||
"Relevant tests": "🧪",
|
||||
"Focused PR": "✨",
|
||||
@ -120,6 +120,9 @@ def convert_to_markdown_v2(output_data: dict,
|
||||
if not output_data or not output_data.get('review', {}):
|
||||
return ""
|
||||
|
||||
if get_settings().get("pr_reviewer.enable_intro_text", False):
|
||||
markdown_text += f"Here are some key observations to aid the review process:\n\n"
|
||||
|
||||
if gfm_supported:
|
||||
markdown_text += "<table>\n"
|
||||
|
||||
@ -189,23 +192,21 @@ def convert_to_markdown_v2(output_data: dict,
|
||||
if is_value_no(value):
|
||||
if gfm_supported:
|
||||
markdown_text += f"<tr><td>"
|
||||
markdown_text += f"{emoji} <strong>No key issues to review</strong>"
|
||||
markdown_text += f"{emoji} <strong>No major issues detected</strong>"
|
||||
markdown_text += f"</td></tr>\n"
|
||||
else:
|
||||
markdown_text += f"### {emoji} No key issues to review\n\n"
|
||||
markdown_text += f"### {emoji} No major issues detected\n\n"
|
||||
else:
|
||||
# issues = value.split('\n- ')
|
||||
issues =value
|
||||
# for i, _ in enumerate(issues):
|
||||
# issues[i] = issues[i].strip().strip('-').strip()
|
||||
issues = value
|
||||
if gfm_supported:
|
||||
markdown_text += f"<tr><td>"
|
||||
markdown_text += f"{emoji} <strong>{key_nice}</strong><br><br>\n\n"
|
||||
# markdown_text += f"{emoji} <strong>{key_nice}</strong><br><br>\n\n"
|
||||
markdown_text += f"{emoji} <strong>Recommended focus areas for review</strong><br><br>\n\n"
|
||||
else:
|
||||
markdown_text += f"### {emoji} Key issues to review\n\n#### \n"
|
||||
markdown_text += f"### {emoji} Recommended focus areas for review\n\n#### \n"
|
||||
for i, issue in enumerate(issues):
|
||||
try:
|
||||
if not issue:
|
||||
if not issue or not isinstance(issue, dict):
|
||||
continue
|
||||
relevant_file = issue.get('relevant_file', '').strip()
|
||||
issue_header = issue.get('issue_header', '').strip()
|
||||
@ -220,7 +221,7 @@ def convert_to_markdown_v2(output_data: dict,
|
||||
issue_str = f"[**{issue_header}**]({reference_link})\n\n{issue_content}\n\n"
|
||||
markdown_text += f"{issue_str}\n\n"
|
||||
except Exception as e:
|
||||
get_logger().exception(f"Failed to process key issues to review: {e}")
|
||||
get_logger().exception(f"Failed to process 'Recommended focus areas for review': {e}")
|
||||
if gfm_supported:
|
||||
markdown_text += f"</td></tr>\n"
|
||||
else:
|
||||
|
@ -27,8 +27,9 @@ global_settings = Dynaconf(
|
||||
"settings/pr_update_changelog_prompts.toml",
|
||||
"settings/pr_custom_labels.toml",
|
||||
"settings/pr_add_docs.toml",
|
||||
"settings/custom_labels.toml",
|
||||
"settings/pr_help_prompts.toml",
|
||||
"settings_prod/.secrets.toml",
|
||||
"settings/custom_labels.toml"
|
||||
]]
|
||||
)
|
||||
|
||||
|
@ -80,7 +80,7 @@ async def run_action():
|
||||
except Exception as e:
|
||||
get_logger().info(f"github action: failed to apply repo settings: {e}")
|
||||
|
||||
# Handle pull request event
|
||||
# Handle pull request opened event
|
||||
if GITHUB_EVENT_NAME == "pull_request":
|
||||
action = event_payload.get("action")
|
||||
|
||||
@ -101,9 +101,13 @@ async def run_action():
|
||||
if auto_improve is None:
|
||||
auto_improve = get_setting_or_env("GITHUB_ACTION_CONFIG.AUTO_IMPROVE", None)
|
||||
|
||||
# Set the configuration for auto actions
|
||||
get_settings().config.is_auto_command = True # Set the flag to indicate that the command is auto
|
||||
get_settings().pr_description.final_update_message = False # No final update message when auto_describe is enabled
|
||||
get_logger().info(f"Running auto actions: auto_describe={auto_describe}, auto_review={auto_review}, auto_improve={auto_improve}")
|
||||
|
||||
# invoke by default all three tools
|
||||
if auto_describe is None or is_true(auto_describe):
|
||||
get_settings().pr_description.final_update_message = False # No final update message when auto_describe is enabled
|
||||
await PRDescription(pr_url).run()
|
||||
if auto_review is None or is_true(auto_review):
|
||||
await PRReviewer(pr_url).run()
|
||||
|
@ -69,6 +69,7 @@ enable_review_labels_effort=true
|
||||
require_all_thresholds_for_incremental_review=false
|
||||
minimal_commits_for_incremental_review=0
|
||||
minimal_minutes_for_incremental_review=0
|
||||
enable_intro_text=true
|
||||
enable_help_text=false # Determines whether to include help text in the PR review. Enabled by default.
|
||||
# auto approval
|
||||
enable_auto_approval=false
|
||||
@ -108,18 +109,22 @@ enable_help_text=false
|
||||
|
||||
[pr_code_suggestions] # /improve #
|
||||
max_context_tokens=14000
|
||||
num_code_suggestions=4
|
||||
#
|
||||
commitable_code_suggestions = false
|
||||
dual_publishing_score_threshold=-1 # -1 to disable, [0-10] to set the threshold (>=) for publishing a code suggestion both in a table and as commitable
|
||||
#
|
||||
extra_instructions = ""
|
||||
rank_suggestions = false
|
||||
enable_help_text=false
|
||||
enable_chat_text=false
|
||||
enable_intro_text=true
|
||||
persistent_comment=true
|
||||
max_history_len=4
|
||||
# enable to apply suggestion 💎
|
||||
apply_suggestions_checkbox=true
|
||||
# suggestions scoring
|
||||
self_reflect_on_suggestions=true
|
||||
suggestions_score_threshold=0 # [0-10]. highly recommend not to set this value above 8, since above it may clip highly relevant suggestions
|
||||
suggestions_score_threshold=0 # [0-10]| recommend not to set this value above 8, since above it may clip highly relevant suggestions
|
||||
# params for '/improve --extended' mode
|
||||
auto_extended_mode=true
|
||||
num_code_suggestions_per_chunk=4
|
||||
@ -183,6 +188,8 @@ enable_help_text=true
|
||||
final_update_message = false
|
||||
|
||||
[pr_help] # /help #
|
||||
force_local_db=false
|
||||
num_retrieved_snippets=5
|
||||
|
||||
[pr_config] # /config #
|
||||
|
||||
@ -303,4 +310,4 @@ uri = "./lancedb"
|
||||
[best_practices]
|
||||
content = ""
|
||||
max_lines_allowed = 800
|
||||
enable_global_best_practices = false
|
||||
enable_global_best_practices = false
|
||||
|
@ -1,9 +1,9 @@
|
||||
[pr_code_suggestions_prompt]
|
||||
system="""You are PR-Reviewer, a language model that specializes in suggesting improvements to a Pull Request (PR) code.
|
||||
Your task is to provide meaningful and actionable code suggestions, to improve the new code presented in a PR code diff (lines starting with '+').
|
||||
system="""You are PR-Reviewer, an AI specializing in Pull Request (PR) code analysis and suggestions.
|
||||
Your task is to examine the provided code diff, focusing on new code (lines prefixed with '+'), and offer concise, actionable suggestions to fix possible bugs and problems, and enhance code quality, readability, and performance.
|
||||
|
||||
|
||||
The format we will use to present the PR code diff:
|
||||
The PR code diff will be in the following structured format:
|
||||
======
|
||||
## File: 'src/file1.py'
|
||||
{%- if is_ai_metadata %}
|
||||
@ -35,28 +35,27 @@ __old hunk__
|
||||
...
|
||||
======
|
||||
|
||||
- In this format, we separate each hunk of diff code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code, that was removed. If no new code was added in a specific hunk, '__new hunk__' section will not be presented. If no code was removed, '__old hunk__' section will not be presented.
|
||||
- We also added line numbers for the '__new hunk__' code, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and should only used for reference.
|
||||
- Code lines are prefixed with symbols ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates unchanged code. \
|
||||
- In the format above, the diff is organized into separate '__new hunk__' and '__old hunk__' sections for each code chunk. '__new hunk__' contains the updated code, while '__old hunk__' shows the removed code. If no code was added or removed in a specific chunk, the corresponding section will be omitted.
|
||||
- Line numbers were added for the '__new hunk__' sections to help referencing specific lines in the code suggestions. These numbers are for reference only and are not part of the actual code.
|
||||
- Code lines are prefixed with symbols: '+' for new code added in the PR, '-' for code removed, and ' ' for unchanged code.
|
||||
{%- if is_ai_metadata %}
|
||||
- If available, an AI-generated summary will appear and provide a high-level overview of the file changes. Note that this summary may not be fully accurate or complete.
|
||||
- When available, an AI-generated summary will precede each file's diff, with a high-level overview of the changes. Note that this summary may not be fully accurate or complete.
|
||||
{%- endif %}
|
||||
|
||||
Specific instructions for generating code suggestions:
|
||||
- Provide up to {{ num_code_suggestions }} code suggestions.
|
||||
- The suggestions should be diverse and insightful. They should focus on improving only the new code introduced in the PR, meaning lines from '__new hunk__' sections, starting with '+' (after the line numbers).
|
||||
- Prioritize suggestions that address possible issues, major problems, and bugs in the PR code. Don't repeat changes already present in the PR. If there are no relevant suggestions for the PR, return an empty list.
|
||||
- Don't suggest to add docstring, type hints, or comments, or to remove unused imports.
|
||||
- Suggestions should not repeat code already present in the '__new hunk__' sections.
|
||||
- Provide the exact line numbers range (inclusive) for each suggestion. Use the line numbers from the '__new hunk__' sections.
|
||||
- Every time you cite variables or names from the code, use backticks ('`'). For example: 'ensure that `variable_name` is ...'
|
||||
- Take into account that you are reviewing a PR code diff, and that the entire codebase is not available for you as context. Hence, avoid suggestions that might conflict with unseen parts of the codebase.
|
||||
|
||||
Specific guidelines for generating code suggestions:
|
||||
- Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions.
|
||||
- Focus solely on enhancing new code introduced in the PR, identified by '+' prefixes in '__new hunk__' sections (after the line numbers).
|
||||
- Prioritize suggestions that address potential issues, critical problems, and bugs in the PR code. Avoid repeating changes already implemented in the PR. If no pertinent suggestions are applicable, return an empty list.
|
||||
- Avoid proposing additions of docstrings, type hints, or comments, or the removal of unused imports.
|
||||
- When referencing variables or names from the code, enclose them in backticks (`). Example: "ensure that `variable_name` is..."
|
||||
- Be mindful you are viewing a partial PR code diff, not the full codebase. Avoid suggestions that might conflict with unseen code or alerting on variables not declared in the visible scope, as the context is incomplete.
|
||||
|
||||
|
||||
{%- if extra_instructions %}
|
||||
|
||||
|
||||
Extra instructions from the user, that should be taken into account with high priority:
|
||||
Extra user-provided instructions (should be addressed with high priority):
|
||||
======
|
||||
{{ extra_instructions }}
|
||||
======
|
||||
@ -66,15 +65,16 @@ Extra instructions from the user, that should be taken into account with high pr
|
||||
The output must be a YAML object equivalent to type $PRCodeSuggestions, according to the following Pydantic definitions:
|
||||
=====
|
||||
class CodeSuggestion(BaseModel):
|
||||
relevant_file: str = Field(description="The full file path of the relevant file")
|
||||
language: str = Field(description="The programming language of the relevant file")
|
||||
suggestion_content: str = Field(description="an actionable suggestion for meaningfully improving the new code introduced in the PR")
|
||||
existing_code: str = Field(description="a short code snippet, demonstrating the relevant code lines from a '__new hunk__' section. It must be without line numbers. Quote only full code lines, not partial ones. Use abbreviations ("...") of full lines if needed")
|
||||
improved_code: str = Field(description="a new code snippet, that can be used to replace the relevant 'existing_code' lines in '__new hunk__' code after applying the suggestion")
|
||||
one_sentence_summary: str = Field(description="a short summary of the suggestion action, in a single sentence. Focus on the 'what'. Be general, and avoid method or variable names.")
|
||||
relevant_lines_start: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion starts (inclusive). Should be derived from the hunk line numbers, and correspond to the 'existing code' snippet above")
|
||||
relevant_lines_end: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion ends (inclusive). Should be derived from the hunk line numbers, and correspond to the 'existing code' snippet above")
|
||||
label: str = Field(description="a single label for the suggestion, to help the user understand the suggestion type. For example: 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability', etc. Other labels are also allowed")
|
||||
relevant_file: str = Field(description="Full path of the relevant file")
|
||||
language: str = Field(description="Programming language used by the relevant file")
|
||||
suggestion_content: str = Field(description="An actionable suggestion to enhance, improve or fix the new code introduced in the PR. Don't present here actual code snippets, just the suggestion. Be short and concise")
|
||||
existing_code: str = Field(description="A short code snippet from a '__new hunk__' section that the suggestion aims to enhance or fix. Include only complete code lines, without line numbers. Use ellipsis (...) for brevity if needed. This snippet should represent the specific PR code targeted for improvement.")
|
||||
improved_code: str = Field(description="A refined code snippet that replaces the 'existing_code' snippet after implementing the suggestion.")
|
||||
one_sentence_summary: str = Field(description="A concise, single-sentence overview of the suggested improvement. Focus on the 'what'. Be general, and avoid method or variable names.")
|
||||
relevant_lines_start: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion starts (inclusive). Should be derived from the hunk line numbers, and correspond to the beginning of the 'existing code' snippet above")
|
||||
relevant_lines_end: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion ends (inclusive). Should be derived from the hunk line numbers, and correspond to the end of the 'existing code' snippet above")
|
||||
label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability'. Other relevant labels are also acceptable.")
|
||||
|
||||
|
||||
class PRCodeSuggestions(BaseModel):
|
||||
code_suggestions: List[CodeSuggestion]
|
||||
@ -119,113 +119,4 @@ The PR Diff:
|
||||
|
||||
Response (should be a valid YAML, and nothing else):
|
||||
```yaml
|
||||
"""
|
||||
|
||||
|
||||
[pr_code_suggestions_prompt_claude]
|
||||
system="""You are PR-Reviewer, a language model that specializes in suggesting improvements to a Pull Request (PR) code.
|
||||
Your task is to provide meaningful and actionable code suggestions, to improve the new code presented in a PR code diff (lines starting with '+').
|
||||
|
||||
|
||||
The format we will use to present the PR code diff:
|
||||
======
|
||||
## File: 'src/file1.py'
|
||||
{%- if is_ai_metadata %}
|
||||
### AI-generated changes summary:
|
||||
* ...
|
||||
* ...
|
||||
{%- endif %}
|
||||
|
||||
@@ ... @@ def func1():
|
||||
__new hunk__
|
||||
11 unchanged code line0 in the PR
|
||||
12 unchanged code line1 in the PR
|
||||
13 +new code line2 added in the PR
|
||||
14 unchanged code line3 in the PR
|
||||
__old hunk__
|
||||
unchanged code line0
|
||||
unchanged code line1
|
||||
-old code line2 removed in the PR
|
||||
unchanged code line3
|
||||
|
||||
@@ ... @@ def func2():
|
||||
__new hunk__
|
||||
...
|
||||
__old hunk__
|
||||
...
|
||||
|
||||
|
||||
## File: 'src/file2.py'
|
||||
...
|
||||
======
|
||||
|
||||
- In this format, we separate each hunk of diff code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code, that was removed. If no new code was added in a specific hunk, '__new hunk__' section will not be presented. If no code was removed, '__old hunk__' section will not be presented.
|
||||
- We also added line numbers for the '__new hunk__' code, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and should only used for reference.
|
||||
- Code lines are prefixed with symbols ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates unchanged code. \
|
||||
{%- if is_ai_metadata %}
|
||||
- If available, an AI-generated summary will appear and provide a high-level overview of the file changes. Note that this summary may not be fully accurate or complete.
|
||||
{%- endif %}
|
||||
|
||||
Specific instructions for generating code suggestions:
|
||||
- Provide up to {{ num_code_suggestions }} code suggestions.
|
||||
- The suggestions should be diverse and insightful. They should focus on improving only the new code introduced in the PR, meaning lines from '__new hunk__' sections, starting with '+' (after the line numbers).
|
||||
- Prioritize suggestions that address possible issues, major problems, and bugs in the PR code. Don't repeat changes already present in the PR. If there are no relevant suggestions for the PR, return an empty list.
|
||||
- Don't suggest to add docstring, type hints, or comments, or to remove unused imports.
|
||||
- Provide the exact line numbers range (inclusive) for each suggestion. Use the line numbers from the '__new hunk__' sections.
|
||||
- Every time you cite variables or names from the code, use backticks ('`'). For example: 'ensure that `variable_name` is ...'
|
||||
- Take into account that you are recieving as an input only a PR code diff. The entire codebase is not available for you as context. Hence, avoid suggestions that might conflict with unseen parts of the codebase, like imports, global variables, etc.
|
||||
|
||||
|
||||
{%- if extra_instructions %}
|
||||
|
||||
|
||||
Extra instructions from the user, that should be taken into account with high priority:
|
||||
======
|
||||
{{ extra_instructions }}
|
||||
======
|
||||
{%- endif %}
|
||||
|
||||
|
||||
The output must be a YAML object equivalent to type $PRCodeSuggestions, according to the following Pydantic definitions:
|
||||
=====
|
||||
class CodeSuggestion(BaseModel):
|
||||
relevant_file: str = Field(description="The full file path of the relevant file")
|
||||
language: str = Field(description="the programming language of the relevant file")
|
||||
suggestion_content: str = Field(description="an actionable suggestion for meaningfully improving the new code introduced in the PR. Don't present here actual code snippets, just the suggestion. Be short and concise")
|
||||
existing_code: str = Field(description="a short code snippet, demonstrating the relevant code lines from a '__new hunk__' section. It must be without line numbers. Quote only full code lines, not partial ones. Use abbreviations ("...") of full lines if needed")
|
||||
improved_code: str = Field(description="a new code snippet, that can be used to replace the relevant 'existing_code' lines in '__new hunk__' code after applying the suggestion")
|
||||
one_sentence_summary: str = Field(description="a short summary of the suggestion action, in a single sentence. Focus on the 'what'. Be general, and avoid method or variable names.")
|
||||
relevant_lines_start: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion starts (inclusive). Should be derived from the hunk line numbers, and correspond to the 'existing code' snippet above")
|
||||
relevant_lines_end: int = Field(description="The relevant line number, from a '__new hunk__' section, where the suggestion ends (inclusive). Should be derived from the hunk line numbers, and correspond to the 'existing code' snippet above")
|
||||
label: str = Field(description="a single label for the suggestion, to help the user understand the suggestion type. For example: 'security', 'possible bug', 'possible issue', 'performance', 'enhancement', 'best practice', 'maintainability', etc. Other labels are also allowed")
|
||||
|
||||
|
||||
class PRCodeSuggestions(BaseModel):
|
||||
code_suggestions: List[CodeSuggestion]
|
||||
=====
|
||||
|
||||
|
||||
Example output:
|
||||
```yaml
|
||||
code_suggestions:
|
||||
- relevant_file: |
|
||||
src/file1.py
|
||||
language: |
|
||||
python
|
||||
suggestion_content: |
|
||||
...
|
||||
existing_code: |
|
||||
...
|
||||
improved_code: |
|
||||
...
|
||||
one_sentence_summary: |
|
||||
...
|
||||
relevant_lines_start: 12
|
||||
relevant_lines_end: 13
|
||||
label: |
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
Each YAML output MUST be after a newline, indented, with block scalar indicator ('|').
|
||||
"""
|
@ -1,32 +1,55 @@
|
||||
[pr_code_suggestions_reflect_prompt]
|
||||
system="""You are a language model that specializes in reviewing and evaluating suggestions for a Pull Request (PR) code.
|
||||
system="""You are an AI language model specialized in reviewing and evaluating code suggestions for a Pull Request (PR).
|
||||
Your task is to analyze a PR code diff and evaluate a set of AI-generated code suggestions. These suggestions aim to address potential bugs and problems, and enhance the new code introduced in the PR.
|
||||
|
||||
Your input is a PR code, and a list of code suggestions that were generated for the PR.
|
||||
Your goal is to inspect, review and score the suggestsions.
|
||||
Be aware - the suggestions may not always be correct or accurate, and you should evaluate them in relation to the actual PR code diff presented. Sometimes the suggestion may ignore parts of the actual code diff, and in that case, you should give it a score of 0.
|
||||
Examine each suggestion meticulously, assessing its quality, relevance, and accuracy within the context of PR. Keep in mind that the suggestions may vary in their correctness and accuracy. Your evaluation should be based on a thorough comparison between each suggestion and the actual PR code diff.
|
||||
Consider the following components of each suggestion:
|
||||
1. 'one_sentence_summary' - A brief summary of the suggestion's purpose
|
||||
2. 'suggestion_content' - The detailed suggestion content, explaining the proposed modification
|
||||
3. 'existing_code' - a code snippet from a __new hunk__ section in the PR code diff that the suggestion addresses
|
||||
4. 'improved_code' - a code snippet demonstrating how the 'existing_code' should be after the suggestion is applied
|
||||
|
||||
Specific instructions:
|
||||
- Carefully review both the suggestion content, and the related PR code diff. Mistakes in the suggestions can occur. Make sure the suggestions are logical and correct, and properly derived from the PR code diff.
|
||||
- In addition to the exact code lines mentioned in each suggestion, review the code around them, to ensure that the suggestions are contextually accurate.
|
||||
- Check that the 'existing_code' field is valid. The 'existing_code' content should match, or be derived, from code lines from a 'new hunk' section in the PR code diff.
|
||||
- Check that the 'improved_code' section correctly reflects the suggestion content.
|
||||
- High scores (8 to 10) should be given to correct suggestions that address major bugs and issues, or security concerns. Lower scores (3 to 7) should be for correct suggestions addressing minor issues, code style, code readability, maintainability, etc. Don't give high scores to suggestions that are not crucial, and bring only small improvement or optimization.
|
||||
- Order the feedback the same way the suggestions are ordered in the input.
|
||||
Be particularly vigilant for suggestions that:
|
||||
- Overlook crucial details in the PR
|
||||
- The 'improved_code' section does not accurately reflect the suggested changes, in relation to the 'existing_code'
|
||||
- Contradict or ignore parts of the PR's modifications
|
||||
In such cases, assign the suggestion a score of 0.
|
||||
|
||||
For valid suggestions, your role is to provide an impartial and precise score assessment that accurately reflects each suggestion's potential impact on the PR's correctness, quality and functionality.
|
||||
|
||||
|
||||
The format that is used to present the PR code diff is as follows:
|
||||
Key guidelines for evaluation:
|
||||
- Thoroughly examine both the suggestion content and the corresponding PR code diff. Be vigilant for potential errors in each suggestion, ensuring they are logically sound, accurate, and directly derived from the PR code diff.
|
||||
- Extend your review beyond the specifically mentioned code lines to encompass surrounding context, verifying the suggestions' contextual accuracy.
|
||||
- Validate the 'existing_code' field by confirming it matches or is accurately derived from code lines within a '__new hunk__' section of the PR code diff.
|
||||
- Ensure the 'improved_code' section accurately reflects the 'existing_code' segment after the suggested modification is applied.
|
||||
- Apply a nuanced scoring system:
|
||||
- Reserve high scores (8-10) for suggestions addressing critical issues such as major bugs or security concerns.
|
||||
- Assign moderate scores (3-7) to suggestions that tackle minor issues, improve code style, enhance readability, or boost maintainability.
|
||||
- Avoid inflating scores for suggestions that, while correct, offer only marginal improvements or optimizations.
|
||||
- Maintain the original order of suggestions in your feedback, corresponding to their input sequence.
|
||||
|
||||
|
||||
The PR code diff will be presented in the following structured format:
|
||||
======
|
||||
## File: 'src/file1.py'
|
||||
{%- if is_ai_metadata %}
|
||||
### AI-generated changes summary:
|
||||
* ...
|
||||
* ...
|
||||
{%- endif %}
|
||||
|
||||
@@ ... @@ def func1():
|
||||
__new hunk__
|
||||
12 code line1 that remained unchanged in the PR
|
||||
11 unchanged code line0 in the PR
|
||||
12 unchanged code line1 in the PR
|
||||
13 +new code line2 added in the PR
|
||||
14 code line3 that remained unchanged in the PR
|
||||
14 unchanged code line3 in the PR
|
||||
__old hunk__
|
||||
code line1 that remained unchanged in the PR
|
||||
-old code line2 that was removed in the PR
|
||||
code line3 that remained unchanged in the PR
|
||||
unchanged code line0
|
||||
unchanged code line1
|
||||
-old code line2 removed in the PR
|
||||
unchanged code line3
|
||||
|
||||
@@ ... @@ def func2():
|
||||
__new hunk__
|
||||
@ -38,19 +61,21 @@ __old hunk__
|
||||
## File: 'src/file2.py'
|
||||
...
|
||||
======
|
||||
- In this format, we separated each hunk of code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code that was removed.
|
||||
- If no new code was added in a specific hunk, '__new hunk__' section will not be presented. If no code was removed, '__old hunk__' section will not be presented.
|
||||
- We added line numbers for the '__new hunk__' sections, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and are only used for reference.
|
||||
- Code lines are prefixed symbols ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates unchanged code.
|
||||
- In the format above, the diff is organized into separate '__new hunk__' and '__old hunk__' sections for each code chunk. '__new hunk__' contains the updated code, while '__old hunk__' shows the removed code. If no code was added or removed in a specific chunk, the corresponding section will be omitted.
|
||||
- Line numbers are included for the '__new hunk__' sections to enable referencing specific lines in the code suggestions. These numbers are for reference only and are not part of the actual code.
|
||||
- Code lines are prefixed with symbols: '+' for new code added in the PR, '-' for code removed, and ' ' for unchanged code.
|
||||
{%- if is_ai_metadata %}
|
||||
- When available, an AI-generated summary will precede each file's diff, with a high-level overview of the changes. Note that this summary may not be fully accurate or comprehensive.
|
||||
{%- endif %}
|
||||
|
||||
|
||||
The output must be a YAML object equivalent to type $PRCodeSuggestionsFeedback, according to the following Pydantic definitions:
|
||||
=====
|
||||
class CodeSuggestionFeedback(BaseModel):
|
||||
suggestion_summary: str = Field(description="repeated from the input")
|
||||
relevant_file: str = Field(description="repeated from the input")
|
||||
suggestion_score: int = Field(description="The actual output - the score of the suggestion, from 0 to 10. Give 0 if the suggestion is wrong. Otherwise, give a score from 1 to 10 (inclusive), where 1 is the lowest and 10 is the highest.")
|
||||
why: str = Field(description="Short and concise explanation of why the suggestion received the score (one to two sentences).")
|
||||
suggestion_summary: str = Field(description="Repeated from the input")
|
||||
relevant_file: str = Field(description="Repeated from the input")
|
||||
suggestion_score: int = Field(description="Evaluate the suggestion and assign a score from 0 to 10. Give 0 if the suggestion is wrong. For valid suggestions, score from 1 (lowest impact/importance) to 10 (highest impact/importance).")
|
||||
why: str = Field(description="Briefly explain the score given in 1-2 sentences, focusing on the suggestion's impact, relevance, and accuracy.")
|
||||
|
||||
class PRCodeSuggestionsFeedback(BaseModel):
|
||||
code_suggestions: List[CodeSuggestionFeedback]
|
||||
@ -79,7 +104,7 @@ user="""You are given a Pull Request (PR) code diff:
|
||||
======
|
||||
|
||||
|
||||
And here is a list of corresponding {{ num_code_suggestions }} code suggestions to improve this Pull Request code:
|
||||
Below are {{ num_code_suggestions }} AI-generated code suggestions for enhancing the Pull Request:
|
||||
======
|
||||
{{ suggestion_str|trim }}
|
||||
======
|
||||
|
48
pr_agent/settings/pr_help_prompts.toml
Normal file
48
pr_agent/settings/pr_help_prompts.toml
Normal file
@ -0,0 +1,48 @@
|
||||
[pr_help_prompts]
|
||||
system="""You are Doc-helper, a language models designed to answer questions about a documentation website for an open-soure project called "PR-Agent".
|
||||
You will recieve a question, and a list of snippets that were collected for a documentation site using RAG as the retrieval method.
|
||||
Your goal is to provide the best answer to the question using the snippets provided.
|
||||
|
||||
Additional instructions:
|
||||
- Try to be short and concise in your answers. Give examples if needed.
|
||||
- It is possible some of the snippets may not be relevant to the question. In that case, you should ignore them and focus on the ones that are relevant.
|
||||
- The main tools of pr-agent are 'describe', 'review', 'improve'. If there is ambiguity to which tool the user is referring to, prioritize snippets of these tools over others.
|
||||
|
||||
|
||||
The output must be a YAML object equivalent to type $DocHelper, according to the following Pydantic definitions:
|
||||
=====
|
||||
class DocHelper(BaseModel):
|
||||
user_question: str = Field(description="The user's question")
|
||||
response: str = Field(description="The response to the user's question")
|
||||
relevant_snippets: List[int] = Field(description="One-based index of the relevant snippets in the list of snippets provided. Order the by relevance, with the most relevant first. If a snippet was not relevant, do not include it in the list.")
|
||||
=====
|
||||
|
||||
|
||||
Example output:
|
||||
```yaml
|
||||
user_question: |
|
||||
...
|
||||
response: |
|
||||
...
|
||||
relevant_snippets:
|
||||
- 1
|
||||
- 2
|
||||
- 4
|
||||
"""
|
||||
|
||||
user="""\
|
||||
User's Question:
|
||||
=====
|
||||
{{ question|trim }}
|
||||
=====
|
||||
|
||||
|
||||
Relevant doc snippets retrieved:
|
||||
=====
|
||||
{{ snippets|trim }}
|
||||
=====
|
||||
|
||||
|
||||
Response (should be a valid YAML, and nothing else):
|
||||
```yaml
|
||||
"""
|
@ -81,10 +81,10 @@ class SubPR(BaseModel):
|
||||
|
||||
class KeyIssuesComponentLink(BaseModel):
|
||||
relevant_file: str = Field(description="The full file path of the relevant file")
|
||||
issue_header: str = Field(description="one or two word title for the the issue. For example: 'Possible Bug', 'Performance Issue', 'Code Smell', etc.")
|
||||
issue_content: str = Field(description="a short and concise description of the issue that needs to be reviewed")
|
||||
start_line: int = Field(description="the start line that corresponds to this issue in the relevant file")
|
||||
end_line: int = Field(description="the end line that corresponds to this issue in the relevant file")
|
||||
issue_header: str = Field(description="One or two word title for the the issue. For example: 'Possible Bug', 'Performance Issue', 'Code Smell', etc.")
|
||||
issue_content: str = Field(description="A short and concise summary of what should be further inspected and validated during the PR review process for this issue. Don't state line numbers here")
|
||||
start_line: int = Field(description="The start line that corresponds to this issue in the relevant file")
|
||||
end_line: int = Field(description="The end line that corresponds to this issue in the relevant file")
|
||||
|
||||
class Review(BaseModel):
|
||||
{%- if require_estimate_effort_to_review %}
|
||||
@ -99,7 +99,7 @@ class Review(BaseModel):
|
||||
{%- if question_str %}
|
||||
insights_from_user_answers: str = Field(description="shortly summarize the insights you gained from the user's answers to the questions")
|
||||
{%- endif %}
|
||||
key_issues_to_review: List[KeyIssuesComponentLink] = Field("A list of bugs, issue or major performance concerns introduced in this PR, which the PR reviewer should further investigate")
|
||||
key_issues_to_review: List[KeyIssuesComponentLink] = Field("A diverse list of bugs, issue or major performance concerns introduced in this PR, which the PR reviewer should further investigate")
|
||||
{%- if require_security_review %}
|
||||
security_concerns: str = Field(description="Does this PR code introduce possible vulnerabilities such as exposure of sensitive information (e.g., API keys, secrets, passwords), or security concerns like SQL injection, XSS, CSRF, and others ? Answer 'No' (without explaining why) if there are no possible issues. If there are security concerns or issues, start your answer with a short header, such as: 'Sensitive information exposure: ...', 'SQL injection: ...' etc. Explain your answer. Be specific and give examples if possible")
|
||||
{%- endif %}
|
||||
|
5
pr_agent/static_analysis/queries/Credits.md
Normal file
5
pr_agent/static_analysis/queries/Credits.md
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
# Credits
|
||||
|
||||
These queries, and some of the logic, were adopted from the excellent [Aider](https://github.com/paul-gauthier/aider/blob/main/aider/queries/README.md) project.
|
||||
|
9
pr_agent/static_analysis/queries/tree-sitter-c-tags.scm
Normal file
9
pr_agent/static_analysis/queries/tree-sitter-c-tags.scm
Normal file
@ -0,0 +1,9 @@
|
||||
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
|
||||
|
||||
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
|
||||
|
||||
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
|
||||
|
||||
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type
|
@ -0,0 +1,46 @@
|
||||
(class_declaration
|
||||
name: (identifier) @name.definition.class
|
||||
) @definition.class
|
||||
|
||||
(class_declaration
|
||||
bases: (base_list (_) @name.reference.class)
|
||||
) @reference.class
|
||||
|
||||
(interface_declaration
|
||||
name: (identifier) @name.definition.interface
|
||||
) @definition.interface
|
||||
|
||||
(interface_declaration
|
||||
bases: (base_list (_) @name.reference.interface)
|
||||
) @reference.interface
|
||||
|
||||
(method_declaration
|
||||
name: (identifier) @name.definition.method
|
||||
) @definition.method
|
||||
|
||||
(object_creation_expression
|
||||
type: (identifier) @name.reference.class
|
||||
) @reference.class
|
||||
|
||||
(type_parameter_constraints_clause
|
||||
target: (identifier) @name.reference.class
|
||||
) @reference.class
|
||||
|
||||
(type_constraint
|
||||
type: (identifier) @name.reference.class
|
||||
) @reference.class
|
||||
|
||||
(variable_declaration
|
||||
type: (identifier) @name.reference.class
|
||||
) @reference.class
|
||||
|
||||
(invocation_expression
|
||||
function:
|
||||
(member_access_expression
|
||||
name: (identifier) @name.reference.send
|
||||
)
|
||||
) @reference.send
|
||||
|
||||
(namespace_declaration
|
||||
name: (identifier) @name.definition.module
|
||||
) @definition.module
|
15
pr_agent/static_analysis/queries/tree-sitter-cpp-tags.scm
Normal file
15
pr_agent/static_analysis/queries/tree-sitter-cpp-tags.scm
Normal file
@ -0,0 +1,15 @@
|
||||
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
|
||||
|
||||
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
|
||||
|
||||
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
(function_declarator declarator: (field_identifier) @name.definition.function) @definition.function
|
||||
|
||||
(function_declarator declarator: (qualified_identifier scope: (namespace_identifier) @scope name: (identifier) @name.definition.method)) @definition.method
|
||||
|
||||
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
|
||||
|
||||
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type
|
||||
|
||||
(class_specifier name: (type_identifier) @name.definition.class) @definition.class
|
@ -0,0 +1,8 @@
|
||||
;; defun/defsubst
|
||||
(function_definition name: (symbol) @name.definition.function) @definition.function
|
||||
|
||||
;; Treat macros as function definitions for the sake of TAGS.
|
||||
(macro_definition name: (symbol) @name.definition.function) @definition.function
|
||||
|
||||
;; Match function calls
|
||||
(list (symbol) @name.reference.function) @reference.function
|
54
pr_agent/static_analysis/queries/tree-sitter-elixir-tags.scm
Normal file
54
pr_agent/static_analysis/queries/tree-sitter-elixir-tags.scm
Normal file
@ -0,0 +1,54 @@
|
||||
; Definitions
|
||||
|
||||
; * modules and protocols
|
||||
(call
|
||||
target: (identifier) @ignore
|
||||
(arguments (alias) @name.definition.module)
|
||||
(#match? @ignore "^(defmodule|defprotocol)$")) @definition.module
|
||||
|
||||
; * functions/macros
|
||||
(call
|
||||
target: (identifier) @ignore
|
||||
(arguments
|
||||
[
|
||||
; zero-arity functions with no parentheses
|
||||
(identifier) @name.definition.function
|
||||
; regular function clause
|
||||
(call target: (identifier) @name.definition.function)
|
||||
; function clause with a guard clause
|
||||
(binary_operator
|
||||
left: (call target: (identifier) @name.definition.function)
|
||||
operator: "when")
|
||||
])
|
||||
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @definition.function
|
||||
|
||||
; References
|
||||
|
||||
; ignore calls to kernel/special-forms keywords
|
||||
(call
|
||||
target: (identifier) @ignore
|
||||
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defmodule|defprotocol|defimpl|defstruct|defexception|defoverridable|alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
|
||||
|
||||
; ignore module attributes
|
||||
(unary_operator
|
||||
operator: "@"
|
||||
operand: (call
|
||||
target: (identifier) @ignore))
|
||||
|
||||
; * function call
|
||||
(call
|
||||
target: [
|
||||
; local
|
||||
(identifier) @name.reference.call
|
||||
; remote
|
||||
(dot
|
||||
right: (identifier) @name.reference.call)
|
||||
]) @reference.call
|
||||
|
||||
; * pipe into function call
|
||||
(binary_operator
|
||||
operator: "|>"
|
||||
right: (identifier) @name.reference.call) @reference.call
|
||||
|
||||
; * modules
|
||||
(alias) @name.reference.module @reference.module
|
19
pr_agent/static_analysis/queries/tree-sitter-elm-tags.scm
Normal file
19
pr_agent/static_analysis/queries/tree-sitter-elm-tags.scm
Normal file
@ -0,0 +1,19 @@
|
||||
(value_declaration (function_declaration_left (lower_case_identifier) @name.definition.function)) @definition.function
|
||||
|
||||
(function_call_expr (value_expr (value_qid) @name.reference.function)) @reference.function
|
||||
(exposed_value (lower_case_identifier) @name.reference.function) @reference.function
|
||||
(type_annotation ((lower_case_identifier) @name.reference.function) (colon)) @reference.function
|
||||
|
||||
(type_declaration ((upper_case_identifier) @name.definition.type)) @definition.type
|
||||
|
||||
(type_ref (upper_case_qid (upper_case_identifier) @name.reference.type)) @reference.type
|
||||
(exposed_type (upper_case_identifier) @name.reference.type) @reference.type
|
||||
|
||||
(type_declaration (union_variant (upper_case_identifier) @name.definition.union)) @definition.union
|
||||
|
||||
(value_expr (upper_case_qid (upper_case_identifier) @name.reference.union)) @reference.union
|
||||
|
||||
|
||||
(module_declaration
|
||||
(upper_case_qid (upper_case_identifier)) @name.definition.module
|
||||
) @definition.module
|
30
pr_agent/static_analysis/queries/tree-sitter-go-tags.scm
Normal file
30
pr_agent/static_analysis/queries/tree-sitter-go-tags.scm
Normal file
@ -0,0 +1,30 @@
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
(function_declaration
|
||||
name: (identifier) @name.definition.function) @definition.function
|
||||
(#strip! @doc "^//\\s*")
|
||||
(#set-adjacent! @doc @definition.function)
|
||||
)
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
(method_declaration
|
||||
name: (field_identifier) @name.definition.method) @definition.method
|
||||
(#strip! @doc "^//\\s*")
|
||||
(#set-adjacent! @doc @definition.method)
|
||||
)
|
||||
|
||||
(call_expression
|
||||
function: [
|
||||
(identifier) @name.reference.call
|
||||
(parenthesized_expression (identifier) @name.reference.call)
|
||||
(selector_expression field: (field_identifier) @name.reference.call)
|
||||
(parenthesized_expression (selector_expression field: (field_identifier) @name.reference.call))
|
||||
]) @reference.call
|
||||
|
||||
(type_spec
|
||||
name: (type_identifier) @name.definition.type) @definition.type
|
||||
|
||||
(type_identifier) @name.reference.type @reference.type
|
20
pr_agent/static_analysis/queries/tree-sitter-java-tags.scm
Normal file
20
pr_agent/static_analysis/queries/tree-sitter-java-tags.scm
Normal file
@ -0,0 +1,20 @@
|
||||
(class_declaration
|
||||
name: (identifier) @name.definition.class) @definition.class
|
||||
|
||||
(method_declaration
|
||||
name: (identifier) @name.definition.method) @definition.method
|
||||
|
||||
(method_invocation
|
||||
name: (identifier) @name.reference.call
|
||||
arguments: (argument_list) @reference.call)
|
||||
|
||||
(interface_declaration
|
||||
name: (identifier) @name.definition.interface) @definition.interface
|
||||
|
||||
(type_list
|
||||
(type_identifier) @name.reference.implementation) @reference.implementation
|
||||
|
||||
(object_creation_expression
|
||||
type: (type_identifier) @name.reference.class) @reference.class
|
||||
|
||||
(superclass (type_identifier) @name.reference.class) @reference.class
|
@ -0,0 +1,88 @@
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
(method_definition
|
||||
name: (property_identifier) @name.definition.method) @definition.method
|
||||
(#not-eq? @name.definition.method "constructor")
|
||||
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||
(#select-adjacent! @doc @definition.method)
|
||||
)
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
[
|
||||
(class
|
||||
name: (_) @name.definition.class)
|
||||
(class_declaration
|
||||
name: (_) @name.definition.class)
|
||||
] @definition.class
|
||||
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||
(#select-adjacent! @doc @definition.class)
|
||||
)
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
[
|
||||
(function
|
||||
name: (identifier) @name.definition.function)
|
||||
(function_declaration
|
||||
name: (identifier) @name.definition.function)
|
||||
(generator_function
|
||||
name: (identifier) @name.definition.function)
|
||||
(generator_function_declaration
|
||||
name: (identifier) @name.definition.function)
|
||||
] @definition.function
|
||||
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||
(#select-adjacent! @doc @definition.function)
|
||||
)
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
(lexical_declaration
|
||||
(variable_declarator
|
||||
name: (identifier) @name.definition.function
|
||||
value: [(arrow_function) (function)]) @definition.function)
|
||||
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||
(#select-adjacent! @doc @definition.function)
|
||||
)
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
(variable_declaration
|
||||
(variable_declarator
|
||||
name: (identifier) @name.definition.function
|
||||
value: [(arrow_function) (function)]) @definition.function)
|
||||
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||
(#select-adjacent! @doc @definition.function)
|
||||
)
|
||||
|
||||
(assignment_expression
|
||||
left: [
|
||||
(identifier) @name.definition.function
|
||||
(member_expression
|
||||
property: (property_identifier) @name.definition.function)
|
||||
]
|
||||
right: [(arrow_function) (function)]
|
||||
) @definition.function
|
||||
|
||||
(pair
|
||||
key: (property_identifier) @name.definition.function
|
||||
value: [(arrow_function) (function)]) @definition.function
|
||||
|
||||
(
|
||||
(call_expression
|
||||
function: (identifier) @name.reference.call) @reference.call
|
||||
(#not-match? @name.reference.call "^(require)$")
|
||||
)
|
||||
|
||||
(call_expression
|
||||
function: (member_expression
|
||||
property: (property_identifier) @name.reference.call)
|
||||
arguments: (_) @reference.call)
|
||||
|
||||
(new_expression
|
||||
constructor: (_) @name.reference.class) @reference.class
|
115
pr_agent/static_analysis/queries/tree-sitter-ocaml-tags.scm
Normal file
115
pr_agent/static_analysis/queries/tree-sitter-ocaml-tags.scm
Normal file
@ -0,0 +1,115 @@
|
||||
; Modules
|
||||
;--------
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
(module_definition (module_binding (module_name) @name.definition.module) @definition.module)
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
(module_path (module_name) @name.reference.module) @reference.module
|
||||
|
||||
; Module types
|
||||
;--------------
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
(module_type_definition (module_type_name) @name.definition.interface) @definition.interface
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
(module_type_path (module_type_name) @name.reference.implementation) @reference.implementation
|
||||
|
||||
; Functions
|
||||
;----------
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
(value_definition
|
||||
[
|
||||
(let_binding
|
||||
pattern: (value_name) @name.definition.function
|
||||
(parameter))
|
||||
(let_binding
|
||||
pattern: (value_name) @name.definition.function
|
||||
body: [(fun_expression) (function_expression)])
|
||||
] @definition.function
|
||||
)
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
(external (value_name) @name.definition.function) @definition.function
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
(application_expression
|
||||
function: (value_path (value_name) @name.reference.call)) @reference.call
|
||||
|
||||
(infix_expression
|
||||
left: (value_path (value_name) @name.reference.call)
|
||||
operator: (concat_operator) @reference.call
|
||||
(#eq? @reference.call "@@"))
|
||||
|
||||
(infix_expression
|
||||
operator: (rel_operator) @reference.call
|
||||
right: (value_path (value_name) @name.reference.call)
|
||||
(#eq? @reference.call "|>"))
|
||||
|
||||
; Operator
|
||||
;---------
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
(value_definition
|
||||
(let_binding
|
||||
pattern: (parenthesized_operator (_) @name.definition.function)) @definition.function)
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
[
|
||||
(prefix_operator)
|
||||
(sign_operator)
|
||||
(pow_operator)
|
||||
(mult_operator)
|
||||
(add_operator)
|
||||
(concat_operator)
|
||||
(rel_operator)
|
||||
(and_operator)
|
||||
(or_operator)
|
||||
(assign_operator)
|
||||
(hash_operator)
|
||||
(indexing_operator)
|
||||
(let_operator)
|
||||
(let_and_operator)
|
||||
(match_operator)
|
||||
] @name.reference.call @reference.call
|
||||
|
||||
; Classes
|
||||
;--------
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
[
|
||||
(class_definition (class_binding (class_name) @name.definition.class) @definition.class)
|
||||
(class_type_definition (class_type_binding (class_type_name) @name.definition.class) @definition.class)
|
||||
]
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
[
|
||||
(class_path (class_name) @name.reference.class)
|
||||
(class_type_path (class_type_name) @name.reference.class)
|
||||
] @reference.class
|
||||
|
||||
; Methods
|
||||
;--------
|
||||
|
||||
(
|
||||
(comment)? @doc .
|
||||
(method_definition (method_name) @name.definition.method) @definition.method
|
||||
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||
)
|
||||
|
||||
(method_invocation (method_name) @name.reference.call) @reference.call
|
26
pr_agent/static_analysis/queries/tree-sitter-php-tags.scm
Normal file
26
pr_agent/static_analysis/queries/tree-sitter-php-tags.scm
Normal file
@ -0,0 +1,26 @@
|
||||
(class_declaration
|
||||
name: (name) @name.definition.class) @definition.class
|
||||
|
||||
(function_definition
|
||||
name: (name) @name.definition.function) @definition.function
|
||||
|
||||
(method_declaration
|
||||
name: (name) @name.definition.function) @definition.function
|
||||
|
||||
(object_creation_expression
|
||||
[
|
||||
(qualified_name (name) @name.reference.class)
|
||||
(variable_name (name) @name.reference.class)
|
||||
]) @reference.class
|
||||
|
||||
(function_call_expression
|
||||
function: [
|
||||
(qualified_name (name) @name.reference.call)
|
||||
(variable_name (name)) @name.reference.call
|
||||
]) @reference.call
|
||||
|
||||
(scoped_call_expression
|
||||
name: (name) @name.reference.call) @reference.call
|
||||
|
||||
(member_call_expression
|
||||
name: (name) @name.reference.call) @reference.call
|
12
pr_agent/static_analysis/queries/tree-sitter-python-tags.scm
Normal file
12
pr_agent/static_analysis/queries/tree-sitter-python-tags.scm
Normal file
@ -0,0 +1,12 @@
|
||||
(class_definition
|
||||
name: (identifier) @name.definition.class) @definition.class
|
||||
|
||||
(function_definition
|
||||
name: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
(call
|
||||
function: [
|
||||
(identifier) @name.reference.call
|
||||
(attribute
|
||||
attribute: (identifier) @name.reference.call)
|
||||
]) @reference.call
|
26
pr_agent/static_analysis/queries/tree-sitter-ql-tags.scm
Normal file
26
pr_agent/static_analysis/queries/tree-sitter-ql-tags.scm
Normal file
@ -0,0 +1,26 @@
|
||||
(classlessPredicate
|
||||
name: (predicateName) @name.definition.function) @definition.function
|
||||
|
||||
(memberPredicate
|
||||
name: (predicateName) @name.definition.method) @definition.method
|
||||
|
||||
(aritylessPredicateExpr
|
||||
name: (literalId) @name.reference.call) @reference.call
|
||||
|
||||
(module
|
||||
name: (moduleName) @name.definition.module) @definition.module
|
||||
|
||||
(dataclass
|
||||
name: (className) @name.definition.class) @definition.class
|
||||
|
||||
(datatype
|
||||
name: (className) @name.definition.class) @definition.class
|
||||
|
||||
(datatypeBranch
|
||||
name: (className) @name.definition.class) @definition.class
|
||||
|
||||
(qualifiedRhs
|
||||
name: (predicateName) @name.reference.call) @reference.call
|
||||
|
||||
(typeExpr
|
||||
name: (className) @name.reference.type) @reference.type
|
64
pr_agent/static_analysis/queries/tree-sitter-ruby-tags.scm
Normal file
64
pr_agent/static_analysis/queries/tree-sitter-ruby-tags.scm
Normal file
@ -0,0 +1,64 @@
|
||||
; Method definitions
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
[
|
||||
(method
|
||||
name: (_) @name.definition.method) @definition.method
|
||||
(singleton_method
|
||||
name: (_) @name.definition.method) @definition.method
|
||||
]
|
||||
(#strip! @doc "^#\\s*")
|
||||
(#select-adjacent! @doc @definition.method)
|
||||
)
|
||||
|
||||
(alias
|
||||
name: (_) @name.definition.method) @definition.method
|
||||
|
||||
(setter
|
||||
(identifier) @ignore)
|
||||
|
||||
; Class definitions
|
||||
|
||||
(
|
||||
(comment)* @doc
|
||||
.
|
||||
[
|
||||
(class
|
||||
name: [
|
||||
(constant) @name.definition.class
|
||||
(scope_resolution
|
||||
name: (_) @name.definition.class)
|
||||
]) @definition.class
|
||||
(singleton_class
|
||||
value: [
|
||||
(constant) @name.definition.class
|
||||
(scope_resolution
|
||||
name: (_) @name.definition.class)
|
||||
]) @definition.class
|
||||
]
|
||||
(#strip! @doc "^#\\s*")
|
||||
(#select-adjacent! @doc @definition.class)
|
||||
)
|
||||
|
||||
; Module definitions
|
||||
|
||||
(
|
||||
(module
|
||||
name: [
|
||||
(constant) @name.definition.module
|
||||
(scope_resolution
|
||||
name: (_) @name.definition.module)
|
||||
]) @definition.module
|
||||
)
|
||||
|
||||
; Calls
|
||||
|
||||
(call method: (identifier) @name.reference.call) @reference.call
|
||||
|
||||
(
|
||||
[(identifier) (constant)] @name.reference.call @reference.call
|
||||
(#is-not? local)
|
||||
(#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$")
|
||||
)
|
60
pr_agent/static_analysis/queries/tree-sitter-rust-tags.scm
Normal file
60
pr_agent/static_analysis/queries/tree-sitter-rust-tags.scm
Normal file
@ -0,0 +1,60 @@
|
||||
; ADT definitions
|
||||
|
||||
(struct_item
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
(enum_item
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
(union_item
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
; type aliases
|
||||
|
||||
(type_item
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
; method definitions
|
||||
|
||||
(declaration_list
|
||||
(function_item
|
||||
name: (identifier) @name.definition.method)) @definition.method
|
||||
|
||||
; function definitions
|
||||
|
||||
(function_item
|
||||
name: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
; trait definitions
|
||||
(trait_item
|
||||
name: (type_identifier) @name.definition.interface) @definition.interface
|
||||
|
||||
; module definitions
|
||||
(mod_item
|
||||
name: (identifier) @name.definition.module) @definition.module
|
||||
|
||||
; macro definitions
|
||||
|
||||
(macro_definition
|
||||
name: (identifier) @name.definition.macro) @definition.macro
|
||||
|
||||
; references
|
||||
|
||||
(call_expression
|
||||
function: (identifier) @name.reference.call) @reference.call
|
||||
|
||||
(call_expression
|
||||
function: (field_expression
|
||||
field: (field_identifier) @name.reference.call)) @reference.call
|
||||
|
||||
(macro_invocation
|
||||
macro: (identifier) @name.reference.call) @reference.call
|
||||
|
||||
; implementations
|
||||
|
||||
(impl_item
|
||||
trait: (type_identifier) @name.reference.implementation) @reference.implementation
|
||||
|
||||
(impl_item
|
||||
type: (type_identifier) @name.reference.implementation
|
||||
!trait) @reference.implementation
|
@ -0,0 +1,41 @@
|
||||
(function_signature
|
||||
name: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
(method_signature
|
||||
name: (property_identifier) @name.definition.method) @definition.method
|
||||
|
||||
(abstract_method_signature
|
||||
name: (property_identifier) @name.definition.method) @definition.method
|
||||
|
||||
(abstract_class_declaration
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
(module
|
||||
name: (identifier) @name.definition.module) @definition.module
|
||||
|
||||
(interface_declaration
|
||||
name: (type_identifier) @name.definition.interface) @definition.interface
|
||||
|
||||
(type_annotation
|
||||
(type_identifier) @name.reference.type) @reference.type
|
||||
|
||||
(new_expression
|
||||
constructor: (identifier) @name.reference.class) @reference.class
|
||||
|
||||
(function_declaration
|
||||
name: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
(method_definition
|
||||
name: (property_identifier) @name.definition.method) @definition.method
|
||||
|
||||
(class_declaration
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
(interface_declaration
|
||||
name: (type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
(type_alias_declaration
|
||||
name: (type_identifier) @name.definition.type) @definition.type
|
||||
|
||||
(enum_declaration
|
||||
name: (identifier) @name.definition.enum) @definition.enum
|
150
pr_agent/static_analysis/src/file_summary.py
Normal file
150
pr_agent/static_analysis/src/file_summary.py
Normal file
@ -0,0 +1,150 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from grep_ast import TreeContext
|
||||
from grep_ast.parsers import PARSERS
|
||||
# from pygments.lexers import guess_lexer_for_filename
|
||||
# from pygments.token import Token
|
||||
from tree_sitter_languages import get_language, get_parser
|
||||
|
||||
|
||||
def filename_to_lang(filename):
|
||||
file_extension = os.path.splitext(filename)[0]
|
||||
lang = PARSERS.get(file_extension)
|
||||
return lang
|
||||
|
||||
class FileSummary:
|
||||
"""
|
||||
This class is used to summarize the content of a file using tree-sitter queries.
|
||||
Supported languages: C, C++, C#, elisp, elixir, go, java, javascript, ocaml, php, python, ql, ruby, rust, typescript
|
||||
"""
|
||||
def __init__(self, fname_full_path: str, project_base_path, parent_context=True, child_context=False, header_max=0):
|
||||
self.fname_full_path = fname_full_path
|
||||
self.project_base_path = project_base_path
|
||||
self.fname_rel = os.path.relpath(fname_full_path, project_base_path)
|
||||
self.main_queries_path = Path(__file__).parent.parent // 'queries'
|
||||
if not os.path.exists(fname_full_path):
|
||||
print(f"File {fname_full_path} does not exist")
|
||||
with open(fname_full_path, "w") as f:
|
||||
code = f.read()
|
||||
self.code = code.rstrip("\n") + "\n"
|
||||
self.parent_context = parent_context
|
||||
self.child_context = child_context
|
||||
self.header_max = header_max
|
||||
|
||||
def summarize(self):
|
||||
query_results = self.get_query_results()
|
||||
summary_str = self.query_processing(query_results)
|
||||
return summary_str
|
||||
|
||||
def render_file_summary(self, lines_of_interest: list):
|
||||
code = self.code
|
||||
fname_rel = self.fname_rel
|
||||
context = TreeContext(
|
||||
fname_rel,
|
||||
code,
|
||||
color=False,
|
||||
line_number=True, # number the lines (1-indexed)
|
||||
parent_context=self.parent_context,
|
||||
child_context=self.child_context,
|
||||
last_line=False,
|
||||
margin=0,
|
||||
mark_lois=False,
|
||||
loi_pad=0,
|
||||
header_max=self.header_max, # max number of lines to show in a function header
|
||||
show_top_of_file_parent_scope=False,
|
||||
)
|
||||
|
||||
context.lines_of_interest = set()
|
||||
context.add_lines_of_interest(lines_of_interest)
|
||||
context.add_context()
|
||||
res = context.format()
|
||||
return res
|
||||
|
||||
def query_processing(self, query_results: list):
|
||||
if not query_results:
|
||||
return ""
|
||||
|
||||
output = ""
|
||||
def_lines = [q['line'] for q in query_results if q['kind'] == "def"]
|
||||
output += "\n"
|
||||
output += query_results[0]['fname'] + ":\n"
|
||||
output += self.render_file_summary(def_lines)
|
||||
return output
|
||||
|
||||
def get_queries_scheme(self, lang) -> str:
|
||||
try:
|
||||
# Load the relevant queries
|
||||
path = os.path.join(self.main_queries_path, f"tree-sitter-{lang}-tags.scm")
|
||||
with open(path, "r") as f:
|
||||
return f.read()
|
||||
except KeyError:
|
||||
return 0
|
||||
|
||||
def get_query_results(self):
|
||||
fname_rel = self.fname_rel
|
||||
code = self.code
|
||||
lang = filename_to_lang(fname_rel)
|
||||
if not lang:
|
||||
return
|
||||
|
||||
try:
|
||||
language = get_language(lang)
|
||||
parser = get_parser(lang)
|
||||
except Exception as err:
|
||||
print(f"Skipping file {fname_rel}: {err}")
|
||||
return
|
||||
|
||||
query_scheme_str = self.get_queries_scheme(lang)
|
||||
tree = parser.parse(bytes(code, "utf-8"))
|
||||
|
||||
# Run the queries
|
||||
query = language.query(query_scheme_str)
|
||||
captures = list(query.captures(tree.root_node))
|
||||
|
||||
# Parse the results into a list of "def" and "ref" tags
|
||||
visited_set = set()
|
||||
results = []
|
||||
for node, tag in captures:
|
||||
if tag.startswith("name.definition."):
|
||||
kind = "ref"
|
||||
elif tag.startswith("name.reference."):
|
||||
kind = "def"
|
||||
else:
|
||||
continue
|
||||
|
||||
visited_set.add(kind)
|
||||
result = dict(
|
||||
fname=fname_rel,
|
||||
name=node.text.decode("utf-8"),
|
||||
kind=kind,
|
||||
line=node.start_point[0],
|
||||
)
|
||||
results.append(result)
|
||||
|
||||
if "ref" in visited_set:
|
||||
return results
|
||||
if "def" not in visited_set:
|
||||
return results
|
||||
|
||||
## currently we are interested only in defs
|
||||
# # We saw defs, without any refs
|
||||
# # Some files only provide defs (cpp, for example)
|
||||
# # Use pygments to backfill refs
|
||||
# try:
|
||||
# lexer = guess_lexer_for_filename(fname, code)
|
||||
# except Exception:
|
||||
# return
|
||||
#
|
||||
# tokens = list(lexer.get_tokens(code))
|
||||
# tokens = [token[1] for token in tokens if token[0] in Token.Name]
|
||||
#
|
||||
# for t in tokens:
|
||||
# result = dict(
|
||||
# fname=fname,
|
||||
# name=t,
|
||||
# kind="ref",
|
||||
# line=-1,
|
||||
# )
|
||||
# results.append(result)
|
||||
return results
|
428
pr_agent/static_analysis/tests/example_files/AES.cpp
Normal file
428
pr_agent/static_analysis/tests/example_files/AES.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
// Taken from 'https://github.com/dolphin-emu/dolphin'
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <memory>
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/Crypto/AES.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#if defined(_M_X86_64)
|
||||
#include <x86intrin.h>
|
||||
#elif defined(_M_ARM_64)
|
||||
#include <arm_acle.h>
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ATTRIBUTE_TARGET(x)
|
||||
#else
|
||||
#define ATTRIBUTE_TARGET(x) [[gnu::target(x)]]
|
||||
#endif
|
||||
|
||||
namespace Common::AES
|
||||
{
|
||||
// For x64 and arm64, it's very unlikely a user's cpu does not support the accelerated version,
|
||||
// fallback is just in case.
|
||||
template <Mode AesMode>
|
||||
class ContextGeneric final : public Context
|
||||
{
|
||||
public:
|
||||
ContextGeneric(const u8* key)
|
||||
{
|
||||
mbedtls_aes_init(&ctx);
|
||||
if constexpr (AesMode == Mode::Encrypt)
|
||||
ASSERT(!mbedtls_aes_setkey_enc(&ctx, key, 128));
|
||||
else
|
||||
ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128));
|
||||
}
|
||||
|
||||
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
||||
size_t len) const override
|
||||
{
|
||||
std::array<u8, BLOCK_SIZE> iv_tmp{};
|
||||
if (iv)
|
||||
std::memcpy(&iv_tmp[0], iv, BLOCK_SIZE);
|
||||
|
||||
constexpr int mode = (AesMode == Mode::Encrypt) ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT;
|
||||
if (mbedtls_aes_crypt_cbc(const_cast<mbedtls_aes_context*>(&ctx), mode, len, &iv_tmp[0], buf_in,
|
||||
buf_out))
|
||||
return false;
|
||||
|
||||
if (iv_out)
|
||||
std::memcpy(iv_out, &iv_tmp[0], BLOCK_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
mbedtls_aes_context ctx{};
|
||||
};
|
||||
|
||||
#if defined(_M_X86_64)
|
||||
|
||||
// Note that (for instructions with same data width) the actual instructions emitted vary depending
|
||||
// on compiler and flags. The naming is somewhat confusing, because VAES cpuid flag was added after
|
||||
// VAES(VEX.128):
|
||||
// clang-format off
|
||||
// instructions | cpuid flag | #define
|
||||
// AES(128) | AES | -
|
||||
// VAES(VEX.128) | AES & AVX | __AVX__
|
||||
// VAES(VEX.256) | VAES | -
|
||||
// VAES(EVEX.128) | VAES & AVX512VL | __AVX512VL__
|
||||
// VAES(EVEX.256) | VAES & AVX512VL | __AVX512VL__
|
||||
// VAES(EVEX.512) | VAES & AVX512F | __AVX512F__
|
||||
// clang-format on
|
||||
template <Mode AesMode>
|
||||
class ContextAESNI final : public Context
|
||||
{
|
||||
static inline __m128i Aes128KeygenAssistFinish(__m128i key, __m128i kga)
|
||||
{
|
||||
__m128i tmp = _mm_shuffle_epi32(kga, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
tmp = _mm_xor_si128(tmp, key);
|
||||
|
||||
key = _mm_slli_si128(key, 4);
|
||||
tmp = _mm_xor_si128(tmp, key);
|
||||
key = _mm_slli_si128(key, 4);
|
||||
tmp = _mm_xor_si128(tmp, key);
|
||||
key = _mm_slli_si128(key, 4);
|
||||
tmp = _mm_xor_si128(tmp, key);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <size_t RoundIdx>
|
||||
ATTRIBUTE_TARGET("aes")
|
||||
inline constexpr void StoreRoundKey(__m128i rk)
|
||||
{
|
||||
if constexpr (AesMode == Mode::Encrypt)
|
||||
round_keys[RoundIdx] = rk;
|
||||
else
|
||||
{
|
||||
constexpr size_t idx = NUM_ROUND_KEYS - RoundIdx - 1;
|
||||
if constexpr (idx == 0 || idx == NUM_ROUND_KEYS - 1)
|
||||
round_keys[idx] = rk;
|
||||
else
|
||||
round_keys[idx] = _mm_aesimc_si128(rk);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t RoundIdx, int Rcon>
|
||||
ATTRIBUTE_TARGET("aes")
|
||||
inline constexpr __m128i Aes128Keygen(__m128i rk)
|
||||
{
|
||||
rk = Aes128KeygenAssistFinish(rk, _mm_aeskeygenassist_si128(rk, Rcon));
|
||||
StoreRoundKey<RoundIdx>(rk);
|
||||
return rk;
|
||||
}
|
||||
|
||||
public:
|
||||
ContextAESNI(const u8* key)
|
||||
{
|
||||
__m128i rk = _mm_loadu_si128((const __m128i*)key);
|
||||
StoreRoundKey<0>(rk);
|
||||
rk = Aes128Keygen<1, 0x01>(rk);
|
||||
rk = Aes128Keygen<2, 0x02>(rk);
|
||||
rk = Aes128Keygen<3, 0x04>(rk);
|
||||
rk = Aes128Keygen<4, 0x08>(rk);
|
||||
rk = Aes128Keygen<5, 0x10>(rk);
|
||||
rk = Aes128Keygen<6, 0x20>(rk);
|
||||
rk = Aes128Keygen<7, 0x40>(rk);
|
||||
rk = Aes128Keygen<8, 0x80>(rk);
|
||||
rk = Aes128Keygen<9, 0x1b>(rk);
|
||||
Aes128Keygen<10, 0x36>(rk);
|
||||
}
|
||||
|
||||
ATTRIBUTE_TARGET("aes")
|
||||
inline void CryptBlock(__m128i* iv, const u8* buf_in, u8* buf_out) const
|
||||
{
|
||||
__m128i block = _mm_loadu_si128((const __m128i*)buf_in);
|
||||
|
||||
if constexpr (AesMode == Mode::Encrypt)
|
||||
{
|
||||
block = _mm_xor_si128(_mm_xor_si128(block, *iv), round_keys[0]);
|
||||
|
||||
for (size_t i = 1; i < Nr; ++i)
|
||||
block = _mm_aesenc_si128(block, round_keys[i]);
|
||||
block = _mm_aesenclast_si128(block, round_keys[Nr]);
|
||||
|
||||
*iv = block;
|
||||
}
|
||||
else
|
||||
{
|
||||
__m128i iv_next = block;
|
||||
|
||||
block = _mm_xor_si128(block, round_keys[0]);
|
||||
|
||||
for (size_t i = 1; i < Nr; ++i)
|
||||
block = _mm_aesdec_si128(block, round_keys[i]);
|
||||
block = _mm_aesdeclast_si128(block, round_keys[Nr]);
|
||||
|
||||
block = _mm_xor_si128(block, *iv);
|
||||
*iv = iv_next;
|
||||
}
|
||||
|
||||
_mm_storeu_si128((__m128i*)buf_out, block);
|
||||
}
|
||||
|
||||
// Takes advantage of instruction pipelining to parallelize.
|
||||
template <size_t NumBlocks>
|
||||
ATTRIBUTE_TARGET("aes")
|
||||
inline void DecryptPipelined(__m128i* iv, const u8* buf_in, u8* buf_out) const
|
||||
{
|
||||
constexpr size_t Depth = NumBlocks;
|
||||
|
||||
__m128i block[Depth];
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
block[d] = _mm_loadu_si128(&((const __m128i*)buf_in)[d]);
|
||||
|
||||
__m128i iv_next[1 + Depth];
|
||||
iv_next[0] = *iv;
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
iv_next[1 + d] = block[d];
|
||||
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
block[d] = _mm_xor_si128(block[d], round_keys[0]);
|
||||
|
||||
// The main speedup is here
|
||||
for (size_t i = 1; i < Nr; ++i)
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
block[d] = _mm_aesdec_si128(block[d], round_keys[i]);
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
block[d] = _mm_aesdeclast_si128(block[d], round_keys[Nr]);
|
||||
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
block[d] = _mm_xor_si128(block[d], iv_next[d]);
|
||||
*iv = iv_next[1 + Depth - 1];
|
||||
|
||||
for (size_t d = 0; d < Depth; d++)
|
||||
_mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]);
|
||||
}
|
||||
|
||||
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
||||
size_t len) const override
|
||||
{
|
||||
if (len % BLOCK_SIZE)
|
||||
return false;
|
||||
|
||||
__m128i iv_block = iv ? _mm_loadu_si128((const __m128i*)iv) : _mm_setzero_si128();
|
||||
|
||||
if constexpr (AesMode == Mode::Decrypt)
|
||||
{
|
||||
// On amd zen2...(benchmark, not real-world):
|
||||
// With AES(128) instructions, BLOCK_DEPTH results in following speedup vs. non-pipelined: 4:
|
||||
// 18%, 8: 22%, 9: 26%, 10-15: 31%. 16: 8% (register exhaustion). With VAES(VEX.128), 10 gives
|
||||
// 36% speedup vs. its corresponding baseline. VAES(VEX.128) is ~4% faster than AES(128). The
|
||||
// result is similar on zen3.
|
||||
// Zen3 in general is 20% faster than zen2 in aes, and VAES(VEX.256) is 35% faster than
|
||||
// zen3/VAES(VEX.128).
|
||||
// It seems like VAES(VEX.256) should be faster?
|
||||
constexpr size_t BLOCK_DEPTH = 10;
|
||||
constexpr size_t CHUNK_LEN = BLOCK_DEPTH * BLOCK_SIZE;
|
||||
while (len >= CHUNK_LEN)
|
||||
{
|
||||
DecryptPipelined<BLOCK_DEPTH>(&iv_block, buf_in, buf_out);
|
||||
buf_in += CHUNK_LEN;
|
||||
buf_out += CHUNK_LEN;
|
||||
len -= CHUNK_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
len /= BLOCK_SIZE;
|
||||
while (len--)
|
||||
{
|
||||
CryptBlock(&iv_block, buf_in, buf_out);
|
||||
buf_in += BLOCK_SIZE;
|
||||
buf_out += BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (iv_out)
|
||||
_mm_storeu_si128((__m128i*)iv_out, iv_block);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<__m128i, NUM_ROUND_KEYS> round_keys;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_M_ARM_64)
|
||||
|
||||
template <Mode AesMode>
|
||||
class ContextNeon final : public Context
|
||||
{
|
||||
public:
|
||||
template <size_t RoundIdx>
|
||||
inline constexpr void StoreRoundKey(const u32* rk)
|
||||
{
|
||||
const uint8x16_t rk_block = vreinterpretq_u8_u32(vld1q_u32(rk));
|
||||
if constexpr (AesMode == Mode::Encrypt)
|
||||
round_keys[RoundIdx] = rk_block;
|
||||
else
|
||||
{
|
||||
constexpr size_t idx = NUM_ROUND_KEYS - RoundIdx - 1;
|
||||
if constexpr (idx == 0 || idx == NUM_ROUND_KEYS - 1)
|
||||
round_keys[idx] = rk_block;
|
||||
else
|
||||
round_keys[idx] = vaesimcq_u8(rk_block);
|
||||
}
|
||||
}
|
||||
|
||||
ContextNeon(const u8* key)
|
||||
{
|
||||
constexpr u8 rcon[]{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
|
||||
std::array<u32, Nb * NUM_ROUND_KEYS> rk{};
|
||||
|
||||
// This uses a nice trick I've seen in wolfssl (not sure original author),
|
||||
// which uses vaeseq_u8 to assist keygen.
|
||||
// vaeseq_u8: op1 = SubBytes(ShiftRows(AddRoundKey(op1, op2)))
|
||||
// given RotWord == ShiftRows for row 1 (rol(x,8))
|
||||
// Probably not super fast (moves to/from vector regs constantly), but it is nice and simple.
|
||||
|
||||
std::memcpy(&rk[0], key, KEY_SIZE);
|
||||
StoreRoundKey<0>(&rk[0]);
|
||||
for (size_t i = 0; i < rk.size() - Nk; i += Nk)
|
||||
{
|
||||
const uint8x16_t enc = vaeseq_u8(vreinterpretq_u8_u32(vmovq_n_u32(rk[i + 3])), vmovq_n_u8(0));
|
||||
const u32 temp = vgetq_lane_u32(vreinterpretq_u32_u8(enc), 0);
|
||||
rk[i + 4] = rk[i + 0] ^ std::rotr(temp, 8) ^ rcon[i / Nk];
|
||||
rk[i + 5] = rk[i + 4] ^ rk[i + 1];
|
||||
rk[i + 6] = rk[i + 5] ^ rk[i + 2];
|
||||
rk[i + 7] = rk[i + 6] ^ rk[i + 3];
|
||||
// clang-format off
|
||||
// Not great
|
||||
const size_t rki = 1 + i / Nk;
|
||||
switch (rki)
|
||||
{
|
||||
case 1: StoreRoundKey< 1>(&rk[Nk * rki]); break;
|
||||
case 2: StoreRoundKey< 2>(&rk[Nk * rki]); break;
|
||||
case 3: StoreRoundKey< 3>(&rk[Nk * rki]); break;
|
||||
case 4: StoreRoundKey< 4>(&rk[Nk * rki]); break;
|
||||
case 5: StoreRoundKey< 5>(&rk[Nk * rki]); break;
|
||||
case 6: StoreRoundKey< 6>(&rk[Nk * rki]); break;
|
||||
case 7: StoreRoundKey< 7>(&rk[Nk * rki]); break;
|
||||
case 8: StoreRoundKey< 8>(&rk[Nk * rki]); break;
|
||||
case 9: StoreRoundKey< 9>(&rk[Nk * rki]); break;
|
||||
case 10: StoreRoundKey<10>(&rk[Nk * rki]); break;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
inline void CryptBlock(uint8x16_t* iv, const u8* buf_in, u8* buf_out) const
|
||||
{
|
||||
uint8x16_t block = vld1q_u8(buf_in);
|
||||
|
||||
if constexpr (AesMode == Mode::Encrypt)
|
||||
{
|
||||
block = veorq_u8(block, *iv);
|
||||
|
||||
for (size_t i = 0; i < Nr - 1; ++i)
|
||||
block = vaesmcq_u8(vaeseq_u8(block, round_keys[i]));
|
||||
block = vaeseq_u8(block, round_keys[Nr - 1]);
|
||||
block = veorq_u8(block, round_keys[Nr]);
|
||||
|
||||
*iv = block;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8x16_t iv_next = block;
|
||||
|
||||
for (size_t i = 0; i < Nr - 1; ++i)
|
||||
block = vaesimcq_u8(vaesdq_u8(block, round_keys[i]));
|
||||
block = vaesdq_u8(block, round_keys[Nr - 1]);
|
||||
block = veorq_u8(block, round_keys[Nr]);
|
||||
|
||||
block = veorq_u8(block, *iv);
|
||||
*iv = iv_next;
|
||||
}
|
||||
|
||||
vst1q_u8(buf_out, block);
|
||||
}
|
||||
|
||||
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
||||
size_t len) const override
|
||||
{
|
||||
if (len % BLOCK_SIZE)
|
||||
return false;
|
||||
|
||||
uint8x16_t iv_block = iv ? vld1q_u8(iv) : vmovq_n_u8(0);
|
||||
|
||||
len /= BLOCK_SIZE;
|
||||
while (len--)
|
||||
{
|
||||
CryptBlock(&iv_block, buf_in, buf_out);
|
||||
buf_in += BLOCK_SIZE;
|
||||
buf_out += BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (iv_out)
|
||||
vst1q_u8(iv_out, iv_block);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<uint8x16_t, NUM_ROUND_KEYS> round_keys;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <Mode AesMode>
|
||||
std::unique_ptr<Context> CreateContext(const u8* key)
|
||||
{
|
||||
if (cpu_info.bAES)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
#if defined(__AVX__)
|
||||
// If compiler enables AVX, the intrinsics will generate VAES(VEX.128) instructions.
|
||||
// In the future we may want to compile the code twice and explicitly override the compiler
|
||||
// flags. There doesn't seem to be much performance difference between AES(128) and
|
||||
// VAES(VEX.128) at the moment, though.
|
||||
if (cpu_info.bAVX)
|
||||
#endif
|
||||
return std::make_unique<ContextAESNI<AesMode>>(key);
|
||||
#elif defined(_M_ARM_64)
|
||||
return std::make_unique<ContextNeon<AesMode>>(key);
|
||||
#endif
|
||||
}
|
||||
return std::make_unique<ContextGeneric<AesMode>>(key);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> CreateContextEncrypt(const u8* key)
|
||||
{
|
||||
return CreateContext<Mode::Encrypt>(key);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> CreateContextDecrypt(const u8* key)
|
||||
{
|
||||
return CreateContext<Mode::Decrypt>(key);
|
||||
}
|
||||
|
||||
// OFB encryption and decryption are the exact same. We don't encrypt though.
|
||||
void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)
|
||||
{
|
||||
mbedtls_aes_context aes_ctx;
|
||||
size_t iv_offset = 0;
|
||||
|
||||
std::array<u8, 16> iv_tmp{};
|
||||
if (iv)
|
||||
std::memcpy(&iv_tmp[0], iv, 16);
|
||||
|
||||
ASSERT(!mbedtls_aes_setkey_enc(&aes_ctx, key, 128));
|
||||
mbedtls_aes_crypt_ofb(&aes_ctx, size, &iv_offset, &iv_tmp[0], buf_in, buf_out);
|
||||
|
||||
if (iv_out)
|
||||
std::memcpy(iv_out, &iv_tmp[0], 16);
|
||||
}
|
||||
|
||||
} // namespace Common::AES
|
586
pr_agent/static_analysis/tests/example_files/calc.java
Normal file
586
pr_agent/static_analysis/tests/example_files/calc.java
Normal file
@ -0,0 +1,586 @@
|
||||
package com.houarizegai.calculator.ui;
|
||||
|
||||
import com.houarizegai.calculator.theme.properties.Theme;
|
||||
import com.houarizegai.calculator.theme.ThemeLoader;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.awt.Color;
|
||||
import javax.swing.*;
|
||||
|
||||
import static com.houarizegai.calculator.util.ColorUtil.hex2Color;
|
||||
|
||||
public class CalculatorUI {
|
||||
|
||||
private static final String FONT_NAME = "Comic Sans MS";
|
||||
private static final String DOUBLE_OR_NUMBER_REGEX = "([-]?\\d+[.]\\d*)|(\\d+)|(-\\d+)";
|
||||
private static final String APPLICATION_TITLE = "Calculator";
|
||||
private static final int WINDOW_WIDTH = 410;
|
||||
private static final int WINDOW_HEIGHT = 600;
|
||||
private static final int BUTTON_WIDTH = 80;
|
||||
private static final int BUTTON_HEIGHT = 70;
|
||||
private static final int MARGIN_X = 20;
|
||||
private static final int MARGIN_Y = 60;
|
||||
|
||||
private final JFrame window;
|
||||
private JComboBox<String> comboCalculatorType;
|
||||
private JComboBox<String> comboTheme;
|
||||
private JTextField inputScreen;
|
||||
private JButton btnC;
|
||||
private JButton btnBack;
|
||||
private JButton btnMod;
|
||||
private JButton btnDiv;
|
||||
private JButton btnMul;
|
||||
private JButton btnSub;
|
||||
private JButton btnAdd;
|
||||
private JButton btn0;
|
||||
private JButton btn1;
|
||||
private JButton btn2;
|
||||
private JButton btn3;
|
||||
private JButton btn4;
|
||||
private JButton btn5;
|
||||
private JButton btn6;
|
||||
private JButton btn7;
|
||||
private JButton btn8;
|
||||
private JButton btn9;
|
||||
private JButton btnPoint;
|
||||
private JButton btnEqual;
|
||||
private JButton btnRoot;
|
||||
private JButton btnPower;
|
||||
private JButton btnLog;
|
||||
|
||||
private char selectedOperator = ' ';
|
||||
private boolean go = true; // For calculate with Opt != (=)
|
||||
private boolean addToDisplay = true; // Connect numbers in display
|
||||
private double typedValue = 0;
|
||||
|
||||
private final Map<String, Theme> themesMap;
|
||||
|
||||
public CalculatorUI() {
|
||||
themesMap = ThemeLoader.loadThemes();
|
||||
|
||||
window = new JFrame(APPLICATION_TITLE);
|
||||
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
window.setLocationRelativeTo(null);
|
||||
|
||||
int[] columns = {MARGIN_X, MARGIN_X + 90, MARGIN_X + 90 * 2, MARGIN_X + 90 * 3, MARGIN_X + 90 * 4};
|
||||
int[] rows = {MARGIN_Y, MARGIN_Y + 100, MARGIN_Y + 100 + 80, MARGIN_Y + 100 + 80 * 2, MARGIN_Y + 100 + 80 * 3, MARGIN_Y + 100 + 80 * 4};
|
||||
|
||||
initInputScreen(columns, rows);
|
||||
initButtons(columns, rows);
|
||||
initCalculatorTypeSelector();
|
||||
|
||||
initThemeSelector();
|
||||
|
||||
window.setLayout(null);
|
||||
window.setResizable(false);
|
||||
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
window.setVisible(true);
|
||||
}
|
||||
|
||||
public double calculate(double firstNumber, double secondNumber, char operator) {
|
||||
switch (operator) {
|
||||
case '+':
|
||||
return firstNumber + secondNumber;
|
||||
case '-':
|
||||
return firstNumber - secondNumber;
|
||||
case '*':
|
||||
return firstNumber * secondNumber;
|
||||
case '/':
|
||||
return firstNumber / secondNumber;
|
||||
case '%':
|
||||
return firstNumber % secondNumber;
|
||||
case '^':
|
||||
return Math.pow(firstNumber, secondNumber);
|
||||
default:
|
||||
return secondNumber;
|
||||
}
|
||||
}
|
||||
|
||||
private void initThemeSelector() {
|
||||
comboTheme = createComboBox(themesMap.keySet().toArray(new String[0]), 230, 30, "Theme");
|
||||
comboTheme.addItemListener(event -> {
|
||||
if (event.getStateChange() != ItemEvent.SELECTED)
|
||||
return;
|
||||
|
||||
String selectedTheme = (String) event.getItem();
|
||||
applyTheme(themesMap.get(selectedTheme));
|
||||
});
|
||||
|
||||
if (themesMap.entrySet().iterator().hasNext()) {
|
||||
applyTheme(themesMap.entrySet().iterator().next().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void initInputScreen(int[] columns, int[] rows) {
|
||||
inputScreen = new JTextField("0");
|
||||
inputScreen.setBounds(columns[0], rows[0], 350, 70);
|
||||
inputScreen.setEditable(false);
|
||||
inputScreen.setBackground(Color.WHITE);
|
||||
inputScreen.setFont(new Font(FONT_NAME, Font.PLAIN, 33));
|
||||
window.add(inputScreen);
|
||||
}
|
||||
|
||||
private void initCalculatorTypeSelector() {
|
||||
comboCalculatorType = createComboBox(new String[]{"Standard", "Scientific"}, 20, 30, "Calculator type");
|
||||
comboCalculatorType.addItemListener(event -> {
|
||||
if (event.getStateChange() != ItemEvent.SELECTED)
|
||||
return;
|
||||
|
||||
String selectedItem = (String) event.getItem();
|
||||
switch (selectedItem) {
|
||||
case "Standard":
|
||||
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
btnRoot.setVisible(false);
|
||||
btnPower.setVisible(false);
|
||||
btnLog.setVisible(false);
|
||||
break;
|
||||
case "Scientific":
|
||||
window.setSize(WINDOW_WIDTH + 80, WINDOW_HEIGHT);
|
||||
btnRoot.setVisible(true);
|
||||
btnPower.setVisible(true);
|
||||
btnLog.setVisible(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initButtons(int[] columns, int[] rows) {
|
||||
btnC = createButton("C", columns[0], rows[1]);
|
||||
btnC.addActionListener(event -> {
|
||||
inputScreen.setText("0");
|
||||
selectedOperator = ' ';
|
||||
typedValue = 0;
|
||||
});
|
||||
|
||||
btnBack = createButton("<-", columns[1], rows[1]);
|
||||
btnBack.addActionListener(event -> {
|
||||
String str = inputScreen.getText();
|
||||
StringBuilder str2 = new StringBuilder();
|
||||
for (int i = 0; i < (str.length() - 1); i++) {
|
||||
str2.append(str.charAt(i));
|
||||
}
|
||||
if (str2.toString().equals("")) {
|
||||
inputScreen.setText("0");
|
||||
} else {
|
||||
inputScreen.setText(str2.toString());
|
||||
}
|
||||
});
|
||||
|
||||
btnMod = createButton("%", columns[2], rows[1]);
|
||||
btnMod.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()) || !go)
|
||||
return;
|
||||
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '%';
|
||||
go = false;
|
||||
addToDisplay = false;
|
||||
});
|
||||
|
||||
btnDiv = createButton("/", columns[3], rows[1]);
|
||||
btnDiv.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '/';
|
||||
go = false;
|
||||
addToDisplay = false;
|
||||
} else {
|
||||
selectedOperator = '/';
|
||||
}
|
||||
});
|
||||
|
||||
btn7 = createButton("7", columns[0], rows[2]);
|
||||
btn7.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("7");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "7");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("7");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn8 = createButton("8", columns[1], rows[2]);
|
||||
btn8.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("8");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "8");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("8");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn9 = createButton("9", columns[2], rows[2]);
|
||||
btn9.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("9");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "9");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("9");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btnMul = createButton("*", columns[3], rows[2]);
|
||||
btnMul.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '*';
|
||||
go = false;
|
||||
addToDisplay = false;
|
||||
} else {
|
||||
selectedOperator = '*';
|
||||
}
|
||||
});
|
||||
|
||||
btn4 = createButton("4", columns[0], rows[3]);
|
||||
btn4.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("4");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "4");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("4");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn5 = createButton("5", columns[1], rows[3]);
|
||||
btn5.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("5");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "5");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("5");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn6 = createButton("6", columns[2], rows[3]);
|
||||
btn6.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("6");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "6");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("6");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btnSub = createButton("-", columns[3], rows[3]);
|
||||
btnSub.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
|
||||
selectedOperator = '-';
|
||||
go = false;
|
||||
addToDisplay = false;
|
||||
} else {
|
||||
selectedOperator = '-';
|
||||
}
|
||||
});
|
||||
|
||||
btn1 = createButton("1", columns[0], rows[4]);
|
||||
btn1.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("1");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "1");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("1");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn2 = createButton("2", columns[1], rows[4]);
|
||||
btn2.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("2");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "2");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("2");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn3 = createButton("3", columns[2], rows[4]);
|
||||
btn3.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("3");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "3");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("3");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btnAdd = createButton("+", columns[3], rows[4]);
|
||||
btnAdd.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '+';
|
||||
go = false;
|
||||
addToDisplay = false;
|
||||
} else {
|
||||
selectedOperator = '+';
|
||||
}
|
||||
});
|
||||
|
||||
btnPoint = createButton(".", columns[0], rows[5]);
|
||||
btnPoint.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (!inputScreen.getText().contains(".")) {
|
||||
inputScreen.setText(inputScreen.getText() + ".");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("0.");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btn0 = createButton("0", columns[1], rows[5]);
|
||||
btn0.addActionListener(event -> {
|
||||
if (addToDisplay) {
|
||||
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||
inputScreen.setText("0");
|
||||
} else {
|
||||
inputScreen.setText(inputScreen.getText() + "0");
|
||||
}
|
||||
} else {
|
||||
inputScreen.setText("0");
|
||||
addToDisplay = true;
|
||||
}
|
||||
go = true;
|
||||
});
|
||||
|
||||
btnEqual = createButton("=", columns[2], rows[5]);
|
||||
btnEqual.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '=';
|
||||
addToDisplay = false;
|
||||
}
|
||||
});
|
||||
btnEqual.setSize(2 * BUTTON_WIDTH + 10, BUTTON_HEIGHT);
|
||||
|
||||
btnRoot = createButton("√", columns[4], rows[1]);
|
||||
btnRoot.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = Math.sqrt(Double.parseDouble(inputScreen.getText()));
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '√';
|
||||
addToDisplay = false;
|
||||
}
|
||||
});
|
||||
btnRoot.setVisible(false);
|
||||
|
||||
btnPower = createButton("pow", columns[4], rows[2]);
|
||||
btnPower.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = '^';
|
||||
go = false;
|
||||
addToDisplay = false;
|
||||
} else {
|
||||
selectedOperator = '^';
|
||||
}
|
||||
});
|
||||
btnPower.setFont(new Font("Comic Sans MS", Font.PLAIN, 24));
|
||||
btnPower.setVisible(false);
|
||||
|
||||
btnLog = createButton("ln", columns[4], rows[3]);
|
||||
btnLog.addActionListener(event -> {
|
||||
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||
return;
|
||||
|
||||
if (go) {
|
||||
typedValue = Math.log(Double.parseDouble(inputScreen.getText()));
|
||||
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||
inputScreen.setText(String.valueOf((int) typedValue));
|
||||
} else {
|
||||
inputScreen.setText(String.valueOf(typedValue));
|
||||
}
|
||||
selectedOperator = 'l';
|
||||
addToDisplay = false;
|
||||
}
|
||||
});
|
||||
btnLog.setVisible(false);
|
||||
}
|
||||
|
||||
private JComboBox<String> createComboBox(String[] items, int x, int y, String toolTip) {
|
||||
JComboBox<String> combo = new JComboBox<>(items);
|
||||
combo.setBounds(x, y, 140, 25);
|
||||
combo.setToolTipText(toolTip);
|
||||
combo.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
window.add(combo);
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
private JButton createButton(String label, int x, int y) {
|
||||
JButton btn = new JButton(label);
|
||||
btn.setBounds(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
btn.setFont(new Font("Comic Sans MS", Font.PLAIN, 28));
|
||||
btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
btn.setFocusable(false);
|
||||
window.add(btn);
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
private void applyTheme(Theme theme) {
|
||||
window.getContentPane().setBackground(hex2Color(theme.getApplicationBackground()));
|
||||
|
||||
comboCalculatorType.setForeground(hex2Color(theme.getTextColor()));
|
||||
comboTheme.setForeground(hex2Color(theme.getTextColor()));
|
||||
inputScreen.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn0.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn1.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn2.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn3.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn4.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn5.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn6.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn7.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn8.setForeground(hex2Color(theme.getTextColor()));
|
||||
btn9.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnPoint.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnC.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnBack.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnMod.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnDiv.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnMul.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnSub.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnAdd.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnRoot.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnLog.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnPower.setForeground(hex2Color(theme.getTextColor()));
|
||||
btnEqual.setForeground(hex2Color(theme.getBtnEqualTextColor()));
|
||||
|
||||
comboCalculatorType.setBackground(hex2Color(theme.getApplicationBackground()));
|
||||
comboTheme.setBackground(hex2Color(theme.getApplicationBackground()));
|
||||
inputScreen.setBackground(hex2Color(theme.getApplicationBackground()));
|
||||
btn0.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn1.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn2.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn3.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn4.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn5.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn6.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn7.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn8.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btn9.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btnPoint.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||
btnC.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnBack.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnMod.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnDiv.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnMul.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnSub.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnAdd.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnRoot.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnLog.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnPower.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||
btnEqual.setBackground(hex2Color(theme.getBtnEqualBackground()));
|
||||
}
|
||||
}
|
138
pr_agent/static_analysis/tests/example_files/match.ts
Normal file
138
pr_agent/static_analysis/tests/example_files/match.ts
Normal file
@ -0,0 +1,138 @@
|
||||
// @ts-ignore
|
||||
import { Pattern } from './types/Pattern'; // @ts-ignore
|
||||
import { Match } from './types/Match'; // @ts-ignore
|
||||
import * as symbols from './internals/symbols'; // @ts-ignore
|
||||
import { matchPattern } from './internals/helpers'; // @ts-ignore
|
||||
|
||||
type MatchState<output> =
|
||||
| { matched: true; value: output }
|
||||
| { matched: false; value: undefined };
|
||||
|
||||
const unmatched: MatchState<never> = {
|
||||
matched: false,
|
||||
value: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* `match` creates a **pattern matching expression**.
|
||||
* * Use `.with(pattern, handler)` to pattern match on the input.
|
||||
* * Use `.exhaustive()` or `.otherwise(() => defaultValue)` to end the expression and get the result.
|
||||
*
|
||||
* [Read the documentation for `match` on GitHub](https://github.com/gvergnaud/ts-pattern#match)
|
||||
*
|
||||
* @example
|
||||
* declare let input: "A" | "B";
|
||||
*
|
||||
* return match(input)
|
||||
* .with("A", () => "It's an A!")
|
||||
* .with("B", () => "It's a B!")
|
||||
* .exhaustive();
|
||||
*
|
||||
*/
|
||||
export function match<const input, output = symbols.unset>(
|
||||
value: input
|
||||
): Match<input, output> {
|
||||
return new MatchExpression(value, unmatched) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents a match expression. It follows the
|
||||
* builder pattern, we chain methods to add features to the expression
|
||||
* until we call `.exhaustive`, `.otherwise` or the unsafe `.run`
|
||||
* method to execute it.
|
||||
*
|
||||
* The types of this class aren't public, the public type definition
|
||||
* can be found in src/types/Match.ts.
|
||||
*/
|
||||
class MatchExpression<input, output> {
|
||||
constructor(private input: input, private state: MatchState<output>) {}
|
||||
|
||||
with(...args: any[]): MatchExpression<input, output> {
|
||||
if (this.state.matched) return this;
|
||||
|
||||
const handler: (selection: unknown, value: input) => output =
|
||||
args[args.length - 1];
|
||||
|
||||
const patterns: Pattern<input>[] = [args[0]];
|
||||
let predicate: ((value: input) => unknown) | undefined = undefined;
|
||||
|
||||
if (args.length === 3 && typeof args[1] === 'function') {
|
||||
// case with guard as second argument
|
||||
patterns.push(args[0]);
|
||||
predicate = args[1];
|
||||
} else if (args.length > 2) {
|
||||
// case with several patterns
|
||||
patterns.push(...args.slice(1, args.length - 1));
|
||||
}
|
||||
|
||||
let hasSelections = false;
|
||||
let selected: Record<string, unknown> = {};
|
||||
const select = (key: string, value: unknown) => {
|
||||
hasSelections = true;
|
||||
selected[key] = value;
|
||||
};
|
||||
|
||||
const matched =
|
||||
patterns.some((pattern) => matchPattern(pattern, this.input, select)) &&
|
||||
(predicate ? Boolean(predicate(this.input)) : true);
|
||||
|
||||
const selections = hasSelections
|
||||
? symbols.anonymousSelectKey in selected
|
||||
? selected[symbols.anonymousSelectKey]
|
||||
: selected
|
||||
: this.input;
|
||||
|
||||
const state = matched
|
||||
? {
|
||||
matched: true as const,
|
||||
value: handler(selections, this.input),
|
||||
}
|
||||
: unmatched;
|
||||
|
||||
return new MatchExpression(this.input, state);
|
||||
}
|
||||
|
||||
when(
|
||||
predicate: (value: input) => unknown,
|
||||
handler: (selection: input, value: input) => output
|
||||
): MatchExpression<input, output> {
|
||||
if (this.state.matched) return this;
|
||||
|
||||
const matched = Boolean(predicate(this.input));
|
||||
|
||||
return new MatchExpression<input, output>(
|
||||
this.input,
|
||||
matched
|
||||
? { matched: true, value: handler(this.input, this.input) }
|
||||
: unmatched
|
||||
);
|
||||
}
|
||||
|
||||
otherwise(handler: (value: input) => output): output {
|
||||
if (this.state.matched) return this.state.value;
|
||||
return handler(this.input);
|
||||
}
|
||||
|
||||
exhaustive(): output {
|
||||
return this.run();
|
||||
}
|
||||
|
||||
run(): output {
|
||||
if (this.state.matched) return this.state.value;
|
||||
|
||||
let displayedValue;
|
||||
try {
|
||||
displayedValue = JSON.stringify(this.input);
|
||||
} catch (e) {
|
||||
displayedValue = this.input;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Pattern matching error: no pattern matches value ${displayedValue}`
|
||||
);
|
||||
}
|
||||
|
||||
returnType() {
|
||||
return this;
|
||||
}
|
||||
}
|
43
pr_agent/static_analysis/tests/test_file_summary.py
Normal file
43
pr_agent/static_analysis/tests/test_file_summary.py
Normal file
@ -0,0 +1,43 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from pr_agent.static_analysis.src.file_summary import FileSummary
|
||||
|
||||
|
||||
class TestFileSummary:
|
||||
def setup_method(self):
|
||||
self.base_path = Path(__file__).parent
|
||||
self.project_base_path = Path(__file__).parent.parent.parent.parent
|
||||
|
||||
def test_file_summary_cpp(self):
|
||||
fname = os.path.join(self.base_path, 'example_files/AES.cpp')
|
||||
if not os.path.exists(fname):
|
||||
print(f"File {fname} does not exist")
|
||||
return False
|
||||
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
|
||||
header_max=0)
|
||||
output = fname_summary.summarize()
|
||||
expected_output = '\npr_agent/static_analysis/tests/example_files/AES.cpp:\n...⋮...\n 32│namespace Common::AES\n 33│{\n...⋮...\n 36│template <Mode AesMode>\n 37│class ContextGeneric final : public Context\n 38│{\n 39│public:\n 40│ ContextGeneric(const u8* key)\n...⋮...\n 49│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n 70│#if defined(_M_X86_64)\n 71│\n...⋮...\n 84│template <Mode AesMode>\n 85│class ContextAESNI final : public Context\n 86│{\n 87│ static inline __m128i Aes128KeygenAssistFinish(__m128i key, __m128i kga)\n...⋮...\n103│ inline constexpr void StoreRoundKey(__m128i rk)\n...⋮...\n119│ inline constexpr __m128i Aes128Keygen(__m128i rk)\n...⋮...\n127│ ContextAESNI(const u8* key)\n...⋮...\n144│ inline void CryptBlock(__m128i* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n178│ inline void DecryptPipelined(__m128i* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n209│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n259│#if defined(_M_ARM_64)\n260│\n261│template <Mode AesMode>\n262│class ContextNeon final : public Context\n263│{\n264│public:\n265│ template <size_t RoundIdx>\n266│ inline constexpr void StoreRoundKey(const u32* rk)\n...⋮...\n281│ ContextNeon(const u8* key)\n...⋮...\n322│ inline void CryptBlock(uint8x16_t* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n353│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n381│template <Mode AesMode>\n382│std::unique_ptr<Context> CreateContext(const u8* key)\n...⋮...\n402│std::unique_ptr<Context> CreateContextEncrypt(const u8* key)\n...⋮...\n407│std::unique_ptr<Context> CreateContextDecrypt(const u8* key)\n...⋮...\n413│void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)\n...⋮...\n'
|
||||
assert output == expected_output
|
||||
|
||||
def test_file_typescript(self):
|
||||
fname = os.path.join(self.base_path, 'example_files/match.ts')
|
||||
if not os.path.exists(fname):
|
||||
print(f"File {fname} does not exist")
|
||||
return False
|
||||
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
|
||||
header_max=0)
|
||||
output = fname_summary.summarize()
|
||||
expected_output = '\npr_agent/static_analysis/tests/example_files/match.ts:\n...⋮...\n 6│type MatchState<output> =\n...⋮...\n 31│export function match<const input, output = symbols.unset>(\n...⋮...\n 46│class MatchExpression<input, output> {\n 47│ constructor(private input: input, private state: MatchState<output>) {}\n 48│\n 49│ with(...args: any[]): MatchExpression<input, output> {\n...⋮...\n 94│ when(\n...⋮...\n110│ otherwise(handler: (value: input) => output): output {\n...⋮...\n115│ exhaustive(): output {\n...⋮...\n119│ run(): output {\n...⋮...\n134│ returnType() {\n...⋮...\n'
|
||||
assert output == expected_output
|
||||
|
||||
def test_file_java(self):
|
||||
fname = os.path.join(self.base_path, 'example_files/calc.java')
|
||||
if not os.path.exists(fname):
|
||||
print(f"File {fname} does not exist")
|
||||
return False
|
||||
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
|
||||
header_max=0)
|
||||
output = fname_summary.summarize()
|
||||
expected_output = '\npr_agent/static_analysis/tests/example_files/calc.java:\n...⋮...\n 16│public class CalculatorUI {\n 17│\n...⋮...\n 84│ public double calculate(double firstNumber, double secondNumber, char operator) {\n...⋮...\n103│ private void initThemeSelector() {\n...⋮...\n118│ private void initInputScreen(int[] columns, int[] rows) {\n...⋮...\n127│ private void initCalculatorTypeSelector() {\n...⋮...\n151│ private void initButtons(int[] columns, int[] rows) {\n...⋮...\n510│ private JComboBox<String> createComboBox(String[] items, int x, int y, String toolTip) {\n...⋮...\n520│ private JButton createButton(String label, int x, int y) {\n...⋮...\n531│ private void applyTheme(Theme theme) {\n...⋮...\n'
|
||||
assert output == expected_output
|
@ -44,10 +44,8 @@ class PRCodeSuggestions:
|
||||
self.is_extended = self._get_is_extended(args or [])
|
||||
except:
|
||||
self.is_extended = False
|
||||
if self.is_extended:
|
||||
num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions_per_chunk
|
||||
else:
|
||||
num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions
|
||||
num_code_suggestions = get_settings().pr_code_suggestions.num_code_suggestions_per_chunk
|
||||
|
||||
|
||||
self.ai_handler = ai_handler()
|
||||
self.ai_handler.main_pr_language = self.main_language
|
||||
@ -77,11 +75,7 @@ class PRCodeSuggestions:
|
||||
"relevant_best_practices": "",
|
||||
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
|
||||
}
|
||||
if 'claude' in get_settings().config.model:
|
||||
# prompt for Claude, with minor adjustments
|
||||
self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt_claude.system
|
||||
else:
|
||||
self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt.system
|
||||
self.pr_code_suggestions_prompt_system = get_settings().pr_code_suggestions_prompt.system
|
||||
|
||||
self.token_handler = TokenHandler(self.git_provider.pr,
|
||||
self.vars,
|
||||
@ -149,6 +143,9 @@ class PRCodeSuggestions:
|
||||
pr_body += ' <!-- approve pr self-review -->'
|
||||
|
||||
# add usage guide
|
||||
if (get_settings().pr_code_suggestions.enable_chat_text and get_settings().config.is_auto_command
|
||||
and isinstance(self.git_provider, GithubProvider)):
|
||||
pr_body += "\n\n>💡 Need additional feedback ? start a [PR chat](https://chromewebstore.google.com/detail/ephlnjeghhogofkifjloamocljapahnl) \n\n"
|
||||
if get_settings().pr_code_suggestions.enable_help_text:
|
||||
pr_body += "<hr>\n\n<details> <summary><strong>💡 Tool usage guide:</strong></summary><hr> \n\n"
|
||||
pr_body += HelpMessage.get_improve_usage_guide()
|
||||
@ -158,6 +155,7 @@ class PRCodeSuggestions:
|
||||
if get_settings().get('config', {}).get('output_relevant_configurations', False):
|
||||
pr_body += show_relevant_configurations(relevant_section='pr_code_suggestions')
|
||||
|
||||
# publish the PR comment
|
||||
if get_settings().pr_code_suggestions.persistent_comment:
|
||||
final_update_message = False
|
||||
self.publish_persistent_comment_with_history(pr_body,
|
||||
@ -173,10 +171,28 @@ class PRCodeSuggestions:
|
||||
else:
|
||||
self.git_provider.publish_comment(pr_body)
|
||||
|
||||
# dual publishing mode
|
||||
if int(get_settings().pr_code_suggestions.dual_publishing_score_threshold) > 0:
|
||||
data_above_threshold = {'code_suggestions': []}
|
||||
try:
|
||||
for suggestion in data['code_suggestions']:
|
||||
if int(suggestion.get('score', 0)) >= int(get_settings().pr_code_suggestions.dual_publishing_score_threshold) \
|
||||
and suggestion.get('improved_code'):
|
||||
data_above_threshold['code_suggestions'].append(suggestion)
|
||||
if not data_above_threshold['code_suggestions'][-1]['existing_code']:
|
||||
get_logger().info(f'Identical existing and improved code for dual publishing found')
|
||||
data_above_threshold['code_suggestions'][-1]['existing_code'] = suggestion[
|
||||
'improved_code']
|
||||
if data_above_threshold['code_suggestions']:
|
||||
get_logger().info(
|
||||
f"Publishing {len(data_above_threshold['code_suggestions'])} suggestions in dual publishing mode")
|
||||
self.push_inline_code_suggestions(data_above_threshold)
|
||||
except Exception as e:
|
||||
get_logger().error(f"Failed to publish dual publishing suggestions, error: {e}")
|
||||
else:
|
||||
self.push_inline_code_suggestions(data)
|
||||
if self.progress_response:
|
||||
self.progress_response.delete()
|
||||
self.git_provider.remove_comment(self.progress_response)
|
||||
else:
|
||||
get_logger().info('Code suggestions generated for PR, but not published since publish_output is False.')
|
||||
except Exception as e:
|
||||
@ -601,7 +617,6 @@ class PRCodeSuggestions:
|
||||
if get_settings().pr_code_suggestions.final_clip_factor != 1:
|
||||
max_len = max(
|
||||
len(data_sorted),
|
||||
get_settings().pr_code_suggestions.num_code_suggestions,
|
||||
get_settings().pr_code_suggestions.num_code_suggestions_per_chunk,
|
||||
)
|
||||
new_len = int(0.5 + max_len * get_settings().pr_code_suggestions.final_clip_factor)
|
||||
@ -622,14 +637,15 @@ class PRCodeSuggestions:
|
||||
pr_body += "No suggestions found to improve this PR."
|
||||
return pr_body
|
||||
|
||||
if get_settings().pr_code_suggestions.enable_intro_text and get_settings().config.is_auto_command:
|
||||
pr_body += "Explore these optional code suggestions:\n\n"
|
||||
|
||||
language_extension_map_org = get_settings().language_extension_map_org
|
||||
extension_to_language = {}
|
||||
for language, extensions in language_extension_map_org.items():
|
||||
for ext in extensions:
|
||||
extension_to_language[ext] = language
|
||||
|
||||
pr_body = "## PR Code Suggestions ✨\n\n"
|
||||
|
||||
pr_body += "<table>"
|
||||
header = f"Suggestion"
|
||||
delta = 66
|
||||
@ -690,7 +706,7 @@ class PRCodeSuggestions:
|
||||
patch = "\n".join(patch_orig.splitlines()[5:]).strip('\n')
|
||||
|
||||
example_code = ""
|
||||
example_code += f"```diff\n{patch}\n```\n"
|
||||
example_code += f"```diff\n{patch.rstrip()}\n```\n"
|
||||
if i == 0:
|
||||
pr_body += f"""<td>\n\n"""
|
||||
else:
|
||||
@ -746,7 +762,8 @@ class PRCodeSuggestions:
|
||||
variables = {'suggestion_list': suggestion_list,
|
||||
'suggestion_str': suggestion_str,
|
||||
"diff": patches_diff,
|
||||
'num_code_suggestions': len(suggestion_list)}
|
||||
'num_code_suggestions': len(suggestion_list),
|
||||
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False)}
|
||||
environment = Environment(undefined=StrictUndefined)
|
||||
system_prompt_reflect = environment.from_string(
|
||||
get_settings().pr_code_suggestions_reflect_prompt.system).render(
|
||||
|
@ -117,9 +117,8 @@ class PRDescription:
|
||||
pr_body += "<hr>\n\n<details> <summary><strong>✨ Describe tool usage guide:</strong></summary><hr> \n\n"
|
||||
pr_body += HelpMessage.get_describe_usage_guide()
|
||||
pr_body += "\n</details>\n"
|
||||
elif self.git_provider.is_supported("gfm_markdown") and get_settings().pr_description.enable_help_comment:
|
||||
pr_body += "\n\n___\n\n> 💡 **PR-Agent usage**:"
|
||||
pr_body += "\n>Comment `/help` on the PR to get a list of all available PR-Agent tools and their descriptions\n\n"
|
||||
elif get_settings().pr_description.enable_help_comment:
|
||||
pr_body += '\n\n___\n\n> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull request to receive relevant information'
|
||||
|
||||
# Output the relevant configurations if enabled
|
||||
if get_settings().get('config', {}).get('output_relevant_configurations', False):
|
||||
|
@ -1,106 +1,360 @@
|
||||
import os
|
||||
import traceback
|
||||
import zipfile
|
||||
import tempfile
|
||||
import copy
|
||||
from functools import partial
|
||||
|
||||
from jinja2 import Environment, StrictUndefined
|
||||
|
||||
from pr_agent.algo.ai_handlers.base_ai_handler import BaseAiHandler
|
||||
from pr_agent.algo.ai_handlers.litellm_ai_handler import LiteLLMAIHandler
|
||||
from pr_agent.algo.pr_processing import retry_with_fallback_models
|
||||
from pr_agent.algo.token_handler import TokenHandler
|
||||
from pr_agent.algo.utils import ModelType, load_yaml
|
||||
from pr_agent.config_loader import get_settings
|
||||
from pr_agent.git_providers import get_git_provider, GithubProvider
|
||||
from pr_agent.git_providers import get_git_provider, GithubProvider, BitbucketServerProvider, \
|
||||
get_git_provider_with_context
|
||||
from pr_agent.log import get_logger
|
||||
|
||||
|
||||
def extract_header(snippet):
|
||||
res = ''
|
||||
lines = snippet.split('===Snippet content===')[0].split('\n')
|
||||
highest_header = ''
|
||||
highest_level = float('inf')
|
||||
for line in lines[::-1]:
|
||||
line = line.strip()
|
||||
if line.startswith('Header '):
|
||||
highest_header = line.split(': ')[1]
|
||||
if highest_header:
|
||||
res = f"#{highest_header.lower().replace(' ', '-')}"
|
||||
return res
|
||||
|
||||
class PRHelpMessage:
|
||||
def __init__(self, pr_url: str, args=None, ai_handler=None):
|
||||
self.git_provider = get_git_provider()(pr_url)
|
||||
def __init__(self, pr_url: str, args=None, ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler):
|
||||
self.git_provider = get_git_provider_with_context(pr_url)
|
||||
self.ai_handler = ai_handler()
|
||||
self.question_str = self.parse_args(args)
|
||||
self.num_retrieved_snippets = get_settings().get('pr_help.num_retrieved_snippets', 5)
|
||||
if self.question_str:
|
||||
self.vars = {
|
||||
"question": self.question_str,
|
||||
"snippets": "",
|
||||
}
|
||||
self.token_handler = TokenHandler(None,
|
||||
self.vars,
|
||||
get_settings().pr_help_prompts.system,
|
||||
get_settings().pr_help_prompts.user)
|
||||
|
||||
async def _prepare_prediction(self, model: str):
|
||||
try:
|
||||
variables = copy.deepcopy(self.vars)
|
||||
environment = Environment(undefined=StrictUndefined)
|
||||
system_prompt = environment.from_string(get_settings().pr_help_prompts.system).render(variables)
|
||||
user_prompt = environment.from_string(get_settings().pr_help_prompts.user).render(variables)
|
||||
response, finish_reason = await self.ai_handler.chat_completion(
|
||||
model=model, temperature=get_settings().config.temperature, system=system_prompt, user=user_prompt)
|
||||
return response
|
||||
except Exception as e:
|
||||
get_logger().error(f"Error while preparing prediction: {e}")
|
||||
return ""
|
||||
|
||||
def parse_args(self, args):
|
||||
if args and len(args) > 0:
|
||||
question_str = " ".join(args)
|
||||
else:
|
||||
question_str = ""
|
||||
return question_str
|
||||
|
||||
def get_sim_results_from_s3_db(self, embeddings):
|
||||
get_logger().info("Loading the S3 index...")
|
||||
sim_results = []
|
||||
try:
|
||||
from langchain_chroma import Chroma
|
||||
from urllib import request
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Define the local file path within the temporary directory
|
||||
local_file_path = os.path.join(temp_dir, 'chroma_db.zip')
|
||||
|
||||
bucket = 'pr-agent'
|
||||
file_name = 'chroma_db.zip'
|
||||
s3_url = f'https://{bucket}.s3.amazonaws.com/{file_name}'
|
||||
request.urlretrieve(s3_url, local_file_path)
|
||||
|
||||
# # Download the file from S3 to the temporary directory
|
||||
# s3 = boto3.client('s3')
|
||||
# s3.download_file(bucket, file_name, local_file_path)
|
||||
|
||||
# Extract the contents of the zip file
|
||||
with zipfile.ZipFile(local_file_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(temp_dir)
|
||||
|
||||
vectorstore = Chroma(persist_directory=temp_dir + "/chroma_db",
|
||||
embedding_function=embeddings)
|
||||
sim_results = vectorstore.similarity_search_with_score(self.question_str, k=self.num_retrieved_snippets)
|
||||
except Exception as e:
|
||||
get_logger().error(f"Error while getting sim from S3: {e}",
|
||||
artifact={"traceback": traceback.format_exc()})
|
||||
return sim_results
|
||||
|
||||
def get_sim_results_from_local_db(self, embeddings):
|
||||
get_logger().info("Loading the local index...")
|
||||
sim_results = []
|
||||
try:
|
||||
from langchain_chroma import Chroma
|
||||
get_logger().info("Loading the Chroma index...")
|
||||
db_path = "./docs/chroma_db.zip"
|
||||
if not os.path.exists(db_path):
|
||||
db_path= "/app/docs/chroma_db.zip"
|
||||
if not os.path.exists(db_path):
|
||||
get_logger().error("Local db not found")
|
||||
return sim_results
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
|
||||
# Extract the ZIP file
|
||||
with zipfile.ZipFile(db_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(temp_dir)
|
||||
|
||||
vectorstore = Chroma(persist_directory=temp_dir + "/chroma_db",
|
||||
embedding_function=embeddings)
|
||||
|
||||
# Do similarity search
|
||||
sim_results = vectorstore.similarity_search_with_score(self.question_str, k=self.num_retrieved_snippets)
|
||||
except Exception as e:
|
||||
get_logger().error(f"Error while getting sim from local db: {e}",
|
||||
artifact={"traceback": traceback.format_exc()})
|
||||
return sim_results
|
||||
|
||||
def get_sim_results_from_pinecone_db(self, embeddings):
|
||||
get_logger().info("Loading the Pinecone index...")
|
||||
sim_results = []
|
||||
try:
|
||||
from langchain_pinecone import PineconeVectorStore
|
||||
INDEX_NAME = "pr-agent-docs"
|
||||
vectorstore = PineconeVectorStore(
|
||||
index_name=INDEX_NAME, embedding=embeddings,
|
||||
pinecone_api_key=get_settings().pinecone.api_key
|
||||
)
|
||||
|
||||
# Do similarity search
|
||||
sim_results = vectorstore.similarity_search_with_score(self.question_str, k=self.num_retrieved_snippets)
|
||||
except Exception as e:
|
||||
get_logger().error(f"Error while getting sim from Pinecone db: {e}",
|
||||
artifact={"traceback": traceback.format_exc()})
|
||||
return sim_results
|
||||
|
||||
async def run(self):
|
||||
try:
|
||||
if not self.git_provider.is_supported("gfm_markdown"):
|
||||
self.git_provider.publish_comment(
|
||||
"The `Help` tool requires gfm markdown, which is not supported by your code platform.")
|
||||
return
|
||||
if self.question_str:
|
||||
get_logger().info(f'Answering a PR question about the PR {self.git_provider.pr_url} ')
|
||||
|
||||
get_logger().info('Getting PR Help Message...')
|
||||
relevant_configs = {'pr_help': dict(get_settings().pr_help),
|
||||
'config': dict(get_settings().config)}
|
||||
get_logger().debug("Relevant configs", artifacts=relevant_configs)
|
||||
pr_comment = "## PR Agent Walkthrough 🤖\n\n"
|
||||
pr_comment += "Welcome to the PR Agent, an AI-powered tool for automated pull request analysis, feedback, suggestions and more."""
|
||||
pr_comment += "\n\nHere is a list of tools you can use to interact with the PR Agent:\n"
|
||||
base_path = "https://pr-agent-docs.codium.ai/tools"
|
||||
if not get_settings().get('openai.key'):
|
||||
if get_settings().config.publish_output:
|
||||
self.git_provider.publish_comment(
|
||||
"The `Help` tool chat feature requires an OpenAI API key for calculating embeddings")
|
||||
else:
|
||||
get_logger().error("The `Help` tool chat feature requires an OpenAI API key for calculating embeddings")
|
||||
return
|
||||
|
||||
tool_names = []
|
||||
tool_names.append(f"[DESCRIBE]({base_path}/describe/)")
|
||||
tool_names.append(f"[REVIEW]({base_path}/review/)")
|
||||
tool_names.append(f"[IMPROVE]({base_path}/improve/)")
|
||||
tool_names.append(f"[UPDATE CHANGELOG]({base_path}/update_changelog/)")
|
||||
tool_names.append(f"[ADD DOCS]({base_path}/documentation/) 💎")
|
||||
tool_names.append(f"[TEST]({base_path}/test/) 💎")
|
||||
tool_names.append(f"[IMPROVE COMPONENT]({base_path}/improve_component/) 💎")
|
||||
tool_names.append(f"[ANALYZE]({base_path}/analyze/) 💎")
|
||||
tool_names.append(f"[ASK]({base_path}/ask/)")
|
||||
tool_names.append(f"[GENERATE CUSTOM LABELS]({base_path}/custom_labels/) 💎")
|
||||
tool_names.append(f"[CI FEEDBACK]({base_path}/ci_feedback/) 💎")
|
||||
tool_names.append(f"[CUSTOM PROMPT]({base_path}/custom_prompt/) 💎")
|
||||
tool_names.append(f"[SIMILAR ISSUE]({base_path}/similar_issues/)")
|
||||
# Initialize embeddings
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
embeddings = OpenAIEmbeddings(model="text-embedding-3-small",
|
||||
api_key=get_settings().openai.key)
|
||||
|
||||
descriptions = []
|
||||
descriptions.append("Generates PR description - title, type, summary, code walkthrough and labels")
|
||||
descriptions.append("Adjustable feedback about the PR, possible issues, security concerns, review effort and more")
|
||||
descriptions.append("Code suggestions for improving the PR")
|
||||
descriptions.append("Automatically updates the changelog")
|
||||
descriptions.append("Generates documentation to methods/functions/classes that changed in the PR")
|
||||
descriptions.append("Generates unit tests for a specific component, based on the PR code change")
|
||||
descriptions.append("Code suggestions for a specific component that changed in the PR")
|
||||
descriptions.append("Identifies code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component")
|
||||
descriptions.append("Answering free-text questions about the PR")
|
||||
descriptions.append("Generates custom labels for the PR, based on specific guidelines defined by the user")
|
||||
descriptions.append("Generates feedback and analysis for a failed CI job")
|
||||
descriptions.append("Generates custom suggestions for improving the PR code, derived only from a specific guidelines prompt defined by the user")
|
||||
descriptions.append("Automatically retrieves and presents similar issues")
|
||||
# Get similar snippets via similarity search
|
||||
if get_settings().pr_help.force_local_db:
|
||||
sim_results = self.get_sim_results_from_local_db(embeddings)
|
||||
elif get_settings().get('pinecone.api_key'):
|
||||
sim_results = self.get_sim_results_from_pinecone_db(embeddings)
|
||||
else:
|
||||
sim_results = self.get_sim_results_from_s3_db(embeddings)
|
||||
if not sim_results:
|
||||
get_logger().info("Failed to load the S3 index. Loading the local index...")
|
||||
sim_results = self.get_sim_results_from_local_db(embeddings)
|
||||
if not sim_results:
|
||||
get_logger().error("Failed to retrieve similar snippets. Exiting...")
|
||||
return
|
||||
|
||||
commands =[]
|
||||
commands.append("`/describe`")
|
||||
commands.append("`/review`")
|
||||
commands.append("`/improve`")
|
||||
commands.append("`/update_changelog`")
|
||||
commands.append("`/add_docs`")
|
||||
commands.append("`/test`")
|
||||
commands.append("`/improve_component`")
|
||||
commands.append("`/analyze`")
|
||||
commands.append("`/ask`")
|
||||
commands.append("`/generate_labels`")
|
||||
commands.append("`/checks`")
|
||||
commands.append("`/custom_prompt`")
|
||||
commands.append("`/similar_issue`")
|
||||
# Prepare relevant snippets
|
||||
relevant_pages_full, relevant_snippets_full_header, relevant_snippets_str =\
|
||||
await self.prepare_relevant_snippets(sim_results)
|
||||
self.vars['snippets'] = relevant_snippets_str.strip()
|
||||
|
||||
checkbox_list = []
|
||||
checkbox_list.append(" - [ ] Run <!-- /describe -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /review -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /improve -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /update_changelog -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /add_docs -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /test -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /improve_component -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /analyze -->")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
# run the AI model
|
||||
response = await retry_with_fallback_models(self._prepare_prediction, model_type=ModelType.REGULAR)
|
||||
response_yaml = load_yaml(response)
|
||||
response_str = response_yaml.get('response')
|
||||
relevant_snippets_numbers = response_yaml.get('relevant_snippets')
|
||||
|
||||
if isinstance(self.git_provider, GithubProvider) and not get_settings().config.get('disable_checkboxes', False):
|
||||
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Description</th><th align='left'>Trigger Interactively :gem:</th></tr>"
|
||||
for i in range(len(tool_names)):
|
||||
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td>\n<td>{descriptions[i]}</td>\n<td>\n\n{checkbox_list[i]}\n</td></tr>"
|
||||
pr_comment += "</table>\n\n"
|
||||
pr_comment += f"""\n\n(1) Note that each tool be [triggered automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-app-automatic-tools-when-a-new-pr-is-opened) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
|
||||
pr_comment += f"""\n\n(2) Tools marked with [*] require additional parameters to be passed. For example, to invoke the `/ask` tool, you need to comment on a PR: `/ask "<question content>"`. See the relevant documentation for each tool for more details."""
|
||||
if not relevant_snippets_numbers:
|
||||
get_logger().info(f"Could not find relevant snippets for the question: {self.question_str}")
|
||||
if get_settings().config.publish_output:
|
||||
answer_str = f"### Question: \n{self.question_str}\n\n"
|
||||
answer_str += f"### Answer:\n\n"
|
||||
answer_str += f"Could not find relevant information to answer the question. Please provide more details and try again."
|
||||
self.git_provider.publish_comment(answer_str)
|
||||
return ""
|
||||
|
||||
# prepare the answer
|
||||
answer_str = ""
|
||||
if response_str:
|
||||
answer_str += f"### Question: \n{self.question_str}\n\n"
|
||||
answer_str += f"### Answer:\n{response_str.strip()}\n\n"
|
||||
answer_str += f"#### Relevant Sources:\n\n"
|
||||
paged_published = []
|
||||
for page in relevant_snippets_numbers:
|
||||
page = int(page - 1)
|
||||
if page < len(relevant_pages_full) and page >= 0:
|
||||
if relevant_pages_full[page] in paged_published:
|
||||
continue
|
||||
link = f"{relevant_pages_full[page]}{relevant_snippets_full_header[page]}"
|
||||
# answer_str += f"> - [{relevant_pages_full[page]}]({link})\n"
|
||||
answer_str += f"> - {link}\n"
|
||||
paged_published.append(relevant_pages_full[page])
|
||||
|
||||
# publish the answer
|
||||
if get_settings().config.publish_output:
|
||||
self.git_provider.publish_comment(answer_str)
|
||||
else:
|
||||
get_logger().info(f"Answer:\n{answer_str}")
|
||||
else:
|
||||
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Command</th><th align='left'>Description</th></tr>"
|
||||
for i in range(len(tool_names)):
|
||||
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td><td>{commands[i]}</td><td>{descriptions[i]}</td></tr>"
|
||||
pr_comment += "</table>\n\n"
|
||||
pr_comment += f"""\n\nNote that each tool be [invoked automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
|
||||
if get_settings().config.publish_output:
|
||||
self.git_provider.publish_comment(pr_comment)
|
||||
if not isinstance(self.git_provider, BitbucketServerProvider) and not self.git_provider.is_supported("gfm_markdown"):
|
||||
self.git_provider.publish_comment(
|
||||
"The `Help` tool requires gfm markdown, which is not supported by your code platform.")
|
||||
return
|
||||
|
||||
get_logger().info('Getting PR Help Message...')
|
||||
relevant_configs = {'pr_help': dict(get_settings().pr_help),
|
||||
'config': dict(get_settings().config)}
|
||||
get_logger().debug("Relevant configs", artifacts=relevant_configs)
|
||||
pr_comment = "## PR Agent Walkthrough 🤖\n\n"
|
||||
pr_comment += "Welcome to the PR Agent, an AI-powered tool for automated pull request analysis, feedback, suggestions and more."""
|
||||
pr_comment += "\n\nHere is a list of tools you can use to interact with the PR Agent:\n"
|
||||
base_path = "https://pr-agent-docs.codium.ai/tools"
|
||||
|
||||
tool_names = []
|
||||
tool_names.append(f"[DESCRIBE]({base_path}/describe/)")
|
||||
tool_names.append(f"[REVIEW]({base_path}/review/)")
|
||||
tool_names.append(f"[IMPROVE]({base_path}/improve/)")
|
||||
tool_names.append(f"[UPDATE CHANGELOG]({base_path}/update_changelog/)")
|
||||
tool_names.append(f"[ADD DOCS]({base_path}/documentation/) 💎")
|
||||
tool_names.append(f"[TEST]({base_path}/test/) 💎")
|
||||
tool_names.append(f"[IMPROVE COMPONENT]({base_path}/improve_component/) 💎")
|
||||
tool_names.append(f"[ANALYZE]({base_path}/analyze/) 💎")
|
||||
tool_names.append(f"[ASK]({base_path}/ask/)")
|
||||
tool_names.append(f"[GENERATE CUSTOM LABELS]({base_path}/custom_labels/) 💎")
|
||||
tool_names.append(f"[CI FEEDBACK]({base_path}/ci_feedback/) 💎")
|
||||
tool_names.append(f"[CUSTOM PROMPT]({base_path}/custom_prompt/) 💎")
|
||||
tool_names.append(f"[SIMILAR ISSUE]({base_path}/similar_issues/)")
|
||||
|
||||
descriptions = []
|
||||
descriptions.append("Generates PR description - title, type, summary, code walkthrough and labels")
|
||||
descriptions.append("Adjustable feedback about the PR, possible issues, security concerns, review effort and more")
|
||||
descriptions.append("Code suggestions for improving the PR")
|
||||
descriptions.append("Automatically updates the changelog")
|
||||
descriptions.append("Generates documentation to methods/functions/classes that changed in the PR")
|
||||
descriptions.append("Generates unit tests for a specific component, based on the PR code change")
|
||||
descriptions.append("Code suggestions for a specific component that changed in the PR")
|
||||
descriptions.append("Identifies code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component")
|
||||
descriptions.append("Answering free-text questions about the PR")
|
||||
descriptions.append("Generates custom labels for the PR, based on specific guidelines defined by the user")
|
||||
descriptions.append("Generates feedback and analysis for a failed CI job")
|
||||
descriptions.append("Generates custom suggestions for improving the PR code, derived only from a specific guidelines prompt defined by the user")
|
||||
descriptions.append("Automatically retrieves and presents similar issues")
|
||||
|
||||
commands =[]
|
||||
commands.append("`/describe`")
|
||||
commands.append("`/review`")
|
||||
commands.append("`/improve`")
|
||||
commands.append("`/update_changelog`")
|
||||
commands.append("`/add_docs`")
|
||||
commands.append("`/test`")
|
||||
commands.append("`/improve_component`")
|
||||
commands.append("`/analyze`")
|
||||
commands.append("`/ask`")
|
||||
commands.append("`/generate_labels`")
|
||||
commands.append("`/checks`")
|
||||
commands.append("`/custom_prompt`")
|
||||
commands.append("`/similar_issue`")
|
||||
|
||||
checkbox_list = []
|
||||
checkbox_list.append(" - [ ] Run <!-- /describe -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /review -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /improve -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /update_changelog -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /add_docs -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /test -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /improve_component -->")
|
||||
checkbox_list.append(" - [ ] Run <!-- /analyze -->")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
checkbox_list.append("[*]")
|
||||
|
||||
if isinstance(self.git_provider, GithubProvider) and not get_settings().config.get('disable_checkboxes', False):
|
||||
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Description</th><th align='left'>Trigger Interactively :gem:</th></tr>"
|
||||
for i in range(len(tool_names)):
|
||||
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td>\n<td>{descriptions[i]}</td>\n<td>\n\n{checkbox_list[i]}\n</td></tr>"
|
||||
pr_comment += "</table>\n\n"
|
||||
pr_comment += f"""\n\n(1) Note that each tool be [triggered automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-app-automatic-tools-when-a-new-pr-is-opened) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
|
||||
pr_comment += f"""\n\n(2) Tools marked with [*] require additional parameters to be passed. For example, to invoke the `/ask` tool, you need to comment on a PR: `/ask "<question content>"`. See the relevant documentation for each tool for more details."""
|
||||
elif isinstance(self.git_provider, BitbucketServerProvider):
|
||||
# only support basic commands in BBDC
|
||||
pr_comment = generate_bbdc_table(tool_names[:4], descriptions[:4])
|
||||
else:
|
||||
pr_comment += f"<table><tr align='left'><th align='left'>Tool</th><th align='left'>Command</th><th align='left'>Description</th></tr>"
|
||||
for i in range(len(tool_names)):
|
||||
pr_comment += f"\n<tr><td align='left'>\n\n<strong>{tool_names[i]}</strong></td><td>{commands[i]}</td><td>{descriptions[i]}</td></tr>"
|
||||
pr_comment += "</table>\n\n"
|
||||
pr_comment += f"""\n\nNote that each tool be [invoked automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/) when a new PR is opened, or called manually by [commenting on a PR](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#online-usage)."""
|
||||
|
||||
if get_settings().config.publish_output:
|
||||
self.git_provider.publish_comment(pr_comment)
|
||||
except Exception as e:
|
||||
get_logger().error(f"Error while running PRHelpMessage: {e}")
|
||||
return ""
|
||||
get_logger().exception(f"Error while running PRHelpMessage: {e}")
|
||||
return ""
|
||||
|
||||
async def prepare_relevant_snippets(self, sim_results):
|
||||
# Get relevant snippets
|
||||
relevant_snippets_full = []
|
||||
relevant_pages_full = []
|
||||
relevant_snippets_full_header = []
|
||||
th = 0.75
|
||||
for s in sim_results:
|
||||
page = s[0].metadata['source']
|
||||
content = s[0].page_content
|
||||
score = s[1]
|
||||
relevant_snippets_full.append(content)
|
||||
relevant_snippets_full_header.append(extract_header(content))
|
||||
relevant_pages_full.append(page)
|
||||
# build the snippets string
|
||||
relevant_snippets_str = ""
|
||||
for i, s in enumerate(relevant_snippets_full):
|
||||
relevant_snippets_str += f"Snippet {i+1}:\n\n{s}\n\n"
|
||||
relevant_snippets_str += "-------------------\n\n"
|
||||
return relevant_pages_full, relevant_snippets_full_header, relevant_snippets_str
|
||||
|
||||
|
||||
def generate_bbdc_table(column_arr_1, column_arr_2):
|
||||
# Generating header row
|
||||
header_row = "| Tool | Description | \n"
|
||||
|
||||
# Generating separator row
|
||||
separator_row = "|--|--|\n"
|
||||
|
||||
# Generating data rows
|
||||
data_rows = ""
|
||||
max_len = max(len(column_arr_1), len(column_arr_2))
|
||||
for i in range(max_len):
|
||||
col1 = column_arr_1[i] if i < len(column_arr_1) else ""
|
||||
col2 = column_arr_2[i] if i < len(column_arr_2) else ""
|
||||
data_rows += f"| {col1} | {col2} |\n"
|
||||
|
||||
# Combine all parts to form the complete table
|
||||
markdown_table = header_row + separator_row + data_rows
|
||||
return markdown_table
|
||||
|
@ -1,4 +1,4 @@
|
||||
aiohttp==3.9.4
|
||||
aiohttp==3.9.5
|
||||
anthropic[vertex]==0.21.3
|
||||
atlassian-python-api==3.41.4
|
||||
azure-devops==7.1.0b3
|
||||
@ -13,7 +13,7 @@ Jinja2==3.1.2
|
||||
litellm==1.43.13
|
||||
loguru==0.7.2
|
||||
msrest==0.7.1
|
||||
openai==1.40.6
|
||||
openai==1.46.0
|
||||
pytest==7.4.0
|
||||
PyGithub==1.59.*
|
||||
PyYAML==6.0.1
|
||||
@ -28,6 +28,18 @@ gunicorn==22.0.0
|
||||
pytest-cov==5.0.0
|
||||
pydantic==2.8.2
|
||||
html2text==2024.2.26
|
||||
# help bot
|
||||
langchain==0.3.0
|
||||
langchain-openai==0.2.0
|
||||
langchain-pinecone==0.2.0
|
||||
langchain-chroma==0.1.4
|
||||
chromadb==0.5.7
|
||||
#
|
||||
tree_sitter==0.21.3
|
||||
tree_sitter_languages==1.10.2
|
||||
grep_ast==0.3.3
|
||||
#Pygments==2.18.0
|
||||
|
||||
# Uncomment the following lines to enable the 'similar issue' tool
|
||||
# pinecone-client
|
||||
# pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main
|
||||
|
@ -53,7 +53,7 @@ class TestConvertToMarkdown:
|
||||
'relevant_line': '[return ""](https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199)'}]}
|
||||
|
||||
|
||||
expected_output = f'{PRReviewHeader.REGULAR.value} 🔍\n\n<table>\n<tr><td>⏱️ <strong>Estimated effort to review</strong>: 1 🔵⚪⚪⚪⚪</td></tr>\n<tr><td>🧪 <strong>No relevant tests</strong></td></tr>\n<tr><td>⚡ <strong>Possible issues</strong>: No\n</td></tr>\n<tr><td>🔒 <strong>No security concerns identified</strong></td></tr>\n</table>\n\n\n<details><summary> <strong>Code feedback:</strong></summary>\n\n<hr><table><tr><td>relevant file</td><td>pr_agent/git_providers/git_provider.py\n</td></tr><tr><td>suggestion </td><td>\n\n<strong>\n\nConsider raising an exception or logging a warning when \'pr_url\' attribute is not found. This can help in debugging issues related to the absence of \'pr_url\' in instances where it\'s expected. [important]\n\n</strong>\n</td></tr><tr><td>relevant line</td><td><a href=\'https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199\'>return ""</a></td></tr></table><hr>\n\n</details>'
|
||||
expected_output = f'{PRReviewHeader.REGULAR.value} 🔍\n\nHere are some key observations to aid the review process:\n\n<table>\n<tr><td>⏱️ <strong>Estimated effort to review</strong>: 1 🔵⚪⚪⚪⚪</td></tr>\n<tr><td>🧪 <strong>No relevant tests</strong></td></tr>\n<tr><td> <strong>Possible issues</strong>: No\n</td></tr>\n<tr><td>🔒 <strong>No security concerns identified</strong></td></tr>\n</table>\n\n\n<details><summary> <strong>Code feedback:</strong></summary>\n\n<hr><table><tr><td>relevant file</td><td>pr_agent/git_providers/git_provider.py\n</td></tr><tr><td>suggestion </td><td>\n\n<strong>\n\nConsider raising an exception or logging a warning when \'pr_url\' attribute is not found. This can help in debugging issues related to the absence of \'pr_url\' in instances where it\'s expected. [important]\n\n</strong>\n</td></tr><tr><td>relevant line</td><td><a href=\'https://github.com/Codium-ai/pr-agent-pro/pull/102/files#diff-52d45f12b836f77ed1aef86e972e65404634ea4e2a6083fb71a9b0f9bb9e062fR199\'>return ""</a></td></tr></table><hr>\n\n</details>'
|
||||
|
||||
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()
|
||||
|
||||
|
Reference in New Issue
Block a user