mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 21:00:40 +08:00
Compare commits
221 Commits
v0.26
...
ofir-frd-p
Author | SHA1 | Date | |
---|---|---|---|
661a4571f9 | |||
52883fb1b5 | |||
adfc2a6b69 | |||
c4aa13e798 | |||
90575e3f0d | |||
fcbe986ec7 | |||
061fec0d36 | |||
778d00d1a0 | |||
cc8d5a6c50 | |||
62c47f9cb5 | |||
bb31b0c66b | |||
359c963ad1 | |||
130b1ff4fb | |||
605a4b99ad | |||
b989f41b96 | |||
26168a605b | |||
2c37b02aa0 | |||
a2550870c2 | |||
279c6ead8f | |||
c9500cf796 | |||
77204faa51 | |||
43fb8ff433 | |||
cd129d8b27 | |||
04aff0d3b2 | |||
be1dd4bd20 | |||
b3b89e7138 | |||
9045723084 | |||
34e22a2c8e | |||
1d784c60cb | |||
deffdbbb89 | |||
b29a19957c | |||
f209bc5323 | |||
32890fec20 | |||
9ddd7c967a | |||
245c3ad523 | |||
43decd9ff2 | |||
3af84aab5b | |||
3633863e90 | |||
69f19f1abd | |||
400146985a | |||
24bf875db6 | |||
9687b4df70 | |||
d8fba02b48 | |||
a6482c37ce | |||
83582bc935 | |||
4ac1e15bae | |||
a48686bde9 | |||
7168d16386 | |||
dc21f71ee2 | |||
7127a030b2 | |||
8f340bce67 | |||
48377e3c81 | |||
7eb26b3220 | |||
32ccb25575 | |||
9aafe18f01 | |||
4df9e03c4c | |||
136c75a5ac | |||
91b0f11cf2 | |||
50740f080b | |||
ad5308c0a3 | |||
f383709629 | |||
4d7fe07c16 | |||
456d5aa233 | |||
d50bfa4b06 | |||
7393887381 | |||
9da4c9d776 | |||
251b4a6395 | |||
d85725c636 | |||
6ef586a617 | |||
43991df2c4 | |||
231d5c20d5 | |||
9052cec391 | |||
33ed6927fc | |||
62aaeb267a | |||
a7bea3b166 | |||
b81d686561 | |||
e5e30f7bd3 | |||
4bfd845877 | |||
e8a80264ca | |||
75f4c7f681 | |||
2277a31661 | |||
805d9cac69 | |||
beffa8dfe4 | |||
a42c5f4f93 | |||
63c98d30d9 | |||
50c52e32c9 | |||
f48c95d113 | |||
2ead9fe4df | |||
4d52715d25 | |||
84d81deac0 | |||
83baac975d | |||
3f6fa5cccb | |||
a7fbd694cc | |||
78b11fca4c | |||
640c1d8dda | |||
dfa98cdfa3 | |||
5518f1ca26 | |||
c4a70f4852 | |||
363ea3eec8 | |||
97cbfe1c2b | |||
68f2198549 | |||
20bbe4187a | |||
2f69c8989c | |||
ed102dc730 | |||
c2bad8ab29 | |||
e9c1c91a4b | |||
eba116fedd | |||
94616a3429 | |||
c1fa22d068 | |||
4f1e4073e4 | |||
b320767c97 | |||
cd5bdf9e59 | |||
e8b8909ab7 | |||
ee8cdcf2b2 | |||
1cb21c6615 | |||
b5f52c5fea | |||
4e481c5088 | |||
7367c00c3d | |||
fb3aa8c96c | |||
983ce131f2 | |||
e571841b5c | |||
c537e9ff66 | |||
fc5454630a | |||
c2ca79da0d | |||
63f1d449ce | |||
0adaddccdf | |||
8a1f07dd6b | |||
8e5d2a0f4d | |||
4e1cae3869 | |||
7be26b665e | |||
664f1938c9 | |||
e0b6db9bec | |||
2f2cdd787d | |||
2b25053de8 | |||
054957fcfe | |||
0075084a22 | |||
e62db20c1e | |||
67d4c96166 | |||
b335cacffd | |||
87a5a7e156 | |||
24aa15f074 | |||
ad4a96caf1 | |||
e7f874a4b2 | |||
4ab9392042 | |||
536d97b9da | |||
cea1b58714 | |||
5ed260d885 | |||
e58a535594 | |||
d949f440a8 | |||
4923c8d810 | |||
fe6540275c | |||
1997da3aac | |||
d0c442b74b | |||
1f86cbc942 | |||
633a1c7bd0 | |||
2d9141adad | |||
95d0d4d71d | |||
5daf8e043c | |||
bd611bc1c2 | |||
4bb04e37c2 | |||
b3f116bb35 | |||
d15d08bb3b | |||
445a7fc015 | |||
c1c5c353e5 | |||
a74fca7b7d | |||
7479ae3224 | |||
6bb5ce58f2 | |||
2783f9b1bb | |||
f4b895d870 | |||
07d40e2c05 | |||
6e1178b168 | |||
c889e566e8 | |||
d9540d3b43 | |||
793f76fec5 | |||
5adc246040 | |||
d4d58babd5 | |||
2df4bc8b53 | |||
e431979b8b | |||
bde594c9e8 | |||
b570c758aa | |||
f6b80174b5 | |||
833ae67820 | |||
ee913336ad | |||
79d589e145 | |||
2d4cd3e270 | |||
7f950a3aa9 | |||
379fa957ea | |||
a1a7c8e44c | |||
6d0ed06fc4 | |||
e695af6917 | |||
5318047202 | |||
5bf5f63c78 | |||
5971a06d73 | |||
71e477a993 | |||
efc621a58b | |||
951fa3385a | |||
56e15c0348 | |||
4c82b8a43e | |||
2d5daf4364 | |||
aa95d5fb68 | |||
f6b470bf5e | |||
36df75ce14 | |||
e2be1f1cee | |||
d1caa0f15f | |||
2c2af93eed | |||
04197a9271 | |||
9faf1521b4 | |||
8819293770 | |||
0ec4491542 | |||
4fd121d34a | |||
6e80f5fcce | |||
4a1b042152 | |||
6fbd95e1a9 | |||
fd6e81978f | |||
467136a48a | |||
3b14d3a3c2 | |||
0f973681ea | |||
19f6078ed0 | |||
3994a2ba60 | |||
796b36f0d1 | |||
4688b20284 |
38
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: "\U0001FAB2 Bug Report"
|
||||||
|
description: Submit a bug report
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: information-git-provider
|
||||||
|
attributes:
|
||||||
|
label: Git provider
|
||||||
|
description: 'The problem arises when using:'
|
||||||
|
options:
|
||||||
|
- "Github Cloud"
|
||||||
|
- "Github Enterprise"
|
||||||
|
- "Gitlab"
|
||||||
|
- "Bitbucket Cloud"
|
||||||
|
- "Bitbucket Server"
|
||||||
|
- "Azure"
|
||||||
|
- "Other"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: system-info
|
||||||
|
attributes:
|
||||||
|
label: System Info
|
||||||
|
description: Please share your system info with us.
|
||||||
|
placeholder: model used, deployment type (action/app/cli/...), etc...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: bug-details
|
||||||
|
attributes:
|
||||||
|
label: Bug details
|
||||||
|
description: Please describe the problem.
|
||||||
|
placeholder: Describe the problem
|
||||||
|
validations:
|
||||||
|
required: true
|
10
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
10
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
version: 0.1
|
||||||
|
contact_links:
|
||||||
|
- name: Discussions
|
||||||
|
url: https://github.com/qodo-ai/pr-agent/discussions
|
||||||
|
about: GitHub Discussions
|
||||||
|
|
||||||
|
- name: Discord community
|
||||||
|
url: https://discord.com/channels/1057273017547378788/1126104260430528613
|
||||||
|
about: Join our discord community
|
21
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
21
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: "\U0001F4A1 Feature request"
|
||||||
|
description: Submit a proposal/request for a new PR-Agent feature
|
||||||
|
labels: ["feature"]
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: feature-request
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Feature request
|
||||||
|
description: |
|
||||||
|
Description of the feature proposal.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: motivation
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Motivation
|
||||||
|
description: |
|
||||||
|
Outline the motivation for the proposal.
|
36
.github/ISSUE_TEMPLATE/miscellaneous.yml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/miscellaneous.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: "❔ General Issue"
|
||||||
|
description: Submit a general issue
|
||||||
|
labels: ["general"]
|
||||||
|
body:
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: information-git-provider
|
||||||
|
attributes:
|
||||||
|
label: Git provider (optional)
|
||||||
|
description: 'Git Provider:'
|
||||||
|
options:
|
||||||
|
- "Github Cloud"
|
||||||
|
- "Github Enterprise"
|
||||||
|
- "Gitlab"
|
||||||
|
- "Bitbucket Cloud"
|
||||||
|
- "Bitbucket Server"
|
||||||
|
- "Azure"
|
||||||
|
- "Other"
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: system-info
|
||||||
|
attributes:
|
||||||
|
label: System Info (optional)
|
||||||
|
description: Please share your system info with us.
|
||||||
|
placeholder: model used, deployment type (action/app/cli/...), etc...
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: issues-details
|
||||||
|
attributes:
|
||||||
|
label: Issues details
|
||||||
|
description: Please share the issues details.
|
||||||
|
placeholder: Describe the issue
|
||||||
|
validations:
|
||||||
|
required: true
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ dist/
|
|||||||
build/
|
build/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
docs/.cache/
|
docs/.cache/
|
||||||
|
.qodo
|
||||||
|
45
CODE_OF_CONDUCT.md
Normal file
45
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Contributor Code of Conduct
|
||||||
|
|
||||||
|
As contributors and maintainers of this project, and in the interest of fostering an open
|
||||||
|
and welcoming community, we pledge to respect all people who contribute through reporting
|
||||||
|
issues, posting feature requests, updating documentation, submitting pull requests or
|
||||||
|
patches, and other activities.
|
||||||
|
|
||||||
|
We are committed to making participation in this project a harassment-free experience for
|
||||||
|
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||||
|
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||||
|
religion, or nationality.
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery
|
||||||
|
* Personal attacks
|
||||||
|
* Trolling or insulting/derogatory comments
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing other's private information, such as physical or electronic addresses,
|
||||||
|
without explicit permission
|
||||||
|
* Other unethical or unprofessional conduct
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments,
|
||||||
|
commits, code, wiki edits, issues, and other contributions that are not aligned to this
|
||||||
|
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
|
||||||
|
that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
|
||||||
|
consistently applying these principles to every aspect of managing this project. Project
|
||||||
|
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
|
||||||
|
from the project team.
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an
|
||||||
|
individual is representing the project or its community.
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
|
||||||
|
contacting a project maintainer at tal.r@qodo.ai . All complaints will
|
||||||
|
be reviewed and investigated and will result in a response that is deemed necessary and
|
||||||
|
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
|
||||||
|
with regard to the reporter of an incident.
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the
|
||||||
|
[Contributor Covenant](https://contributor-covenant.org), version 1.3.0, available at
|
||||||
|
[contributor-covenant.org/version/1/3/0/](https://contributor-covenant.org/version/1/3/0/)
|
||||||
|
|
38
CONTRIBUTING.md
Normal file
38
CONTRIBUTING.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Contributing to PR-Agent
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to the PR-Agent project!
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
1. Fork the repository and clone your fork
|
||||||
|
2. Install Python 3.10 or higher
|
||||||
|
3. Install dependencies (`requirements.txt` and `requirements-dev.txt`)
|
||||||
|
4. Create a new branch for your contribution:
|
||||||
|
- For new features: `git checkout -b feature/your-feature-name`
|
||||||
|
- For bug fixes: `git checkout -b fix/issue-description`
|
||||||
|
5. Make your changes
|
||||||
|
6. Write or update tests as needed
|
||||||
|
7. Run tests locally to ensure everything passes
|
||||||
|
8. Commit your changes using conventional commit messages
|
||||||
|
9. Push to your fork and submit a pull request
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
- Keep pull requests focused on a single feature or fix
|
||||||
|
- Follow the existing code style and formatting conventions
|
||||||
|
- Add unit tests for any new functionality using pytest
|
||||||
|
- Ensure test coverage for your changes
|
||||||
|
- Update documentation as needed
|
||||||
|
|
||||||
|
## Pull Request Process
|
||||||
|
|
||||||
|
1. Ensure your PR includes a clear description of the changes
|
||||||
|
2. Link any related issues
|
||||||
|
3. Update the README.md if needed
|
||||||
|
4. Wait for review from maintainers
|
||||||
|
|
||||||
|
## Questions or Need Help?
|
||||||
|
|
||||||
|
- Join our [Discord community](https://discord.com/channels/1057273017547378788/1126104260430528613) for questions and discussions
|
||||||
|
- Check the [documentation](https://qodo-merge-docs.qodo.ai/) for detailed information
|
||||||
|
- Report bugs or request features through [GitHub Issues](https://github.com/qodo-ai/pr-agent/issues)
|
@ -3,7 +3,7 @@ FROM python:3.12 as base
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ADD pyproject.toml .
|
ADD pyproject.toml .
|
||||||
ADD requirements.txt .
|
ADD requirements.txt .
|
||||||
RUN pip install . && rm pyproject.toml requirements.txt
|
RUN pip install --no-cache-dir . && rm pyproject.toml requirements.txt
|
||||||
ENV PYTHONPATH=/app
|
ENV PYTHONPATH=/app
|
||||||
ADD docs docs
|
ADD docs docs
|
||||||
ADD pr_agent pr_agent
|
ADD pr_agent pr_agent
|
||||||
|
170
README.md
170
README.md
@ -10,10 +10,16 @@
|
|||||||
|
|
||||||
</picture>
|
</picture>
|
||||||
<br/>
|
<br/>
|
||||||
Qode Merge PR-Agent aims to help efficiently review and handle pull requests, by providing AI feedback and suggestions
|
|
||||||
|
[Installation Guide](https://qodo-merge-docs.qodo.ai/installation/) |
|
||||||
|
[Usage Guide](https://qodo-merge-docs.qodo.ai/usage-guide/) |
|
||||||
|
[Tools Guide](https://qodo-merge-docs.qodo.ai/tools/) |
|
||||||
|
[Qodo Merge](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) 💎
|
||||||
|
|
||||||
|
PR-Agent aims to help efficiently review and handle pull requests, by providing AI feedback and suggestions
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
[](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl)
|
[](https://chromewebstore.google.com/detail/qodo-merge-ai-powered-cod/ephlnjeghhogofkifjloamocljapahnl)
|
||||||
[](https://github.com/apps/qodo-merge-pro/)
|
[](https://github.com/apps/qodo-merge-pro/)
|
||||||
[](https://github.com/apps/qodo-merge-pro-for-open-source/)
|
[](https://github.com/apps/qodo-merge-pro-for-open-source/)
|
||||||
[](https://discord.com/channels/1057273017547378788/1126104260430528613)
|
[](https://discord.com/channels/1057273017547378788/1126104260430528613)
|
||||||
@ -22,63 +28,62 @@ Qode Merge PR-Agent aims to help efficiently review and handle pull requests, by
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### [Documentation](https://pr-agent-docs.codium.ai/)
|
[//]: # (### [Documentation](https://qodo-merge-docs.qodo.ai/))
|
||||||
- See the [Installation Guide](https://qodo-merge-docs.qodo.ai/installation/) for instructions on installing Qode Merge PR-Agent on different platforms.
|
|
||||||
|
|
||||||
- See the [Usage Guide](https://qodo-merge-docs.qodo.ai/usage-guide/) for instructions on running Qode Merge PR-Agent tools via different interfaces, such as CLI, PR Comments, or by automatically triggering them when a new PR is opened.
|
[//]: # ()
|
||||||
|
[//]: # (- See the [Installation Guide](https://qodo-merge-docs.qodo.ai/installation/) for instructions on installing PR-Agent on different platforms.)
|
||||||
|
|
||||||
- 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.
|
[//]: # ()
|
||||||
|
[//]: # (- 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://qodo-merge-docs.qodo.ai/tools/) for a detailed description of the different tools, and the available configurations for each tool.)
|
||||||
|
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [News and Updates](#news-and-updates)
|
- [News and Updates](#news-and-updates)
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
- [Example results](#example-results)
|
- [Example results](#example-results)
|
||||||
- [Try it now](#try-it-now)
|
- [Try it now](#try-it-now)
|
||||||
- [PR-Agent Pro 💎](https://pr-agent-docs.codium.ai/overview/pr_agent_pro/)
|
- [Qodo Merge](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/)
|
||||||
- [How it works](#how-it-works)
|
- [How it works](#how-it-works)
|
||||||
- [Why use PR-Agent?](#why-use-pr-agent)
|
- [Why use PR-Agent?](#why-use-pr-agent)
|
||||||
|
|
||||||
## News and Updates
|
## News and Updates
|
||||||
|
|
||||||
### December 25, 2024
|
### Feb 6, 2025
|
||||||
|
New design for the `/improve` tool:
|
||||||
|
|
||||||
The `review` tool previously included a legacy feature for providing code suggestions (controlled by '--pr_reviewer.num_code_suggestion'). This functionality has been deprecated. Use instead the [`improve`](https://qodo-merge-docs.qodo.ai/tools/improve/) tool, which offers higher quality and more actionable code suggestions.
|
<kbd><img src="https://github.com/user-attachments/assets/26506430-550e-469a-adaa-af0a09b70c6d" width="512"></kbd>
|
||||||
|
|
||||||
### December 2, 2024
|
### Jan 25, 2025
|
||||||
|
|
||||||
Open-source repositories can now freely use Qodo Merge Pro, and enjoy easy one-click installation using a marketplace [app](https://github.com/apps/qodo-merge-pro-for-open-source).
|
The open-source GitHub organization was updated:
|
||||||
|
`https://github.com/codium-ai/pr-agent` →
|
||||||
|
`https://github.com/qodo-ai/pr-agent`
|
||||||
|
|
||||||
<kbd><img src="https://github.com/user-attachments/assets/b0838724-87b9-43b0-ab62-73739a3a855c" width="512"></kbd>
|
The docker should be redirected automatically to the new location.
|
||||||
|
However, if you have any issues, please update the GitHub action docker image from
|
||||||
See [here](https://qodo-merge-docs.qodo.ai/installation/pr_agent_pro/) for more details about installing Qodo Merge Pro for private repositories.
|
`uses: Codium-ai/pr-agent@main`
|
||||||
|
to
|
||||||
|
`uses: qodo-ai/pr-agent@main`
|
||||||
|
|
||||||
|
|
||||||
### November 18, 2024
|
### Jan 2, 2025
|
||||||
|
|
||||||
A new mode was enabled by default for code suggestions - `--pr_code_suggestions.focus_only_on_problems=true`:
|
New tool [/Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) (💎), which converts human code review discussions and feedback into ready-to-commit code changes.
|
||||||
|
|
||||||
- This option reduces the number of code suggestions received
|
<kbd><img src="https://www.qodo.ai/images/pr_agent/implement1.png" width="512"></kbd>
|
||||||
- The suggestions will focus more on identifying and fixing code problems, rather than style considerations like best practices, maintainability, or readability.
|
|
||||||
- The suggestions will be categorized into just two groups: "Possible Issues" and "General".
|
|
||||||
|
|
||||||
Still, if you prefer the previous mode, you can set `--pr_code_suggestions.focus_only_on_problems=false` in the [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/).
|
|
||||||
|
|
||||||
**Example results:**
|
|
||||||
|
|
||||||
Original mode
|
|
||||||
|
|
||||||
<kbd><img src="https://qodo.ai/images/pr_agent/code_suggestions_original_mode.png" width="512"></kbd>
|
|
||||||
|
|
||||||
Focused mode
|
|
||||||
|
|
||||||
<kbd><img src="https://qodo.ai/images/pr_agent/code_suggestions_focused_mode.png" width="512"></kbd>
|
|
||||||
|
|
||||||
|
|
||||||
### November 4, 2024
|
### Jan 1, 2025
|
||||||
|
|
||||||
Qodo Merge PR Agent will now leverage context from Jira or GitHub tickets to enhance the PR Feedback. Read more about this feature
|
Update logic and [documentation](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/#ollama) for running local models via Ollama.
|
||||||
[here](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/)
|
|
||||||
|
### December 30, 2024
|
||||||
|
|
||||||
|
Following feedback from the community, we have addressed two vulnerabilities identified in the open-source PR-Agent project. The [fixes](https://github.com/qodo-ai/pr-agent/pull/1425) are now included in the newly released version (v0.26), available as of today.
|
||||||
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@ -92,19 +97,20 @@ Supported commands per platform:
|
|||||||
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | ⮑ [Ask on code lines](https://pr-agent-docs.codium.ai/tools/ask#ask-lines) | ✅ | ✅ | | |
|
| | ⮑ [Ask on code lines](https://qodo-merge-docs.qodo.ai/tools/ask/#ask-lines) | ✅ | ✅ | | |
|
||||||
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Ticket Context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Ticket Context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| | [Utilizing Best Practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) 💎 | ✅ | ✅ | ✅ | |
|
| | [Utilizing Best Practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| | [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) 💎 | ✅ | | | |
|
| | [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) 💎 | ✅ | | | |
|
||||||
| | [Suggestion Tracking](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking) 💎 | ✅ | ✅ | | |
|
| | [Suggestion Tracking](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking) 💎 | ✅ | ✅ | | |
|
||||||
| | [CI Feedback](https://pr-agent-docs.codium.ai/tools/ci_feedback/) 💎 | ✅ | | | |
|
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | |
|
||||||
| | [PR Documentation](https://pr-agent-docs.codium.ai/tools/documentation/) 💎 | ✅ | ✅ | | |
|
| | [PR Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | |
|
||||||
| | [Custom Labels](https://pr-agent-docs.codium.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | |
|
| | [Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | |
|
||||||
| | [Analyze](https://pr-agent-docs.codium.ai/tools/analyze/) 💎 | ✅ | ✅ | | |
|
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | |
|
||||||
| | [Similar Code](https://pr-agent-docs.codium.ai/tools/similar_code/) 💎 | ✅ | | | |
|
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | |
|
||||||
| | [Custom Prompt](https://pr-agent-docs.codium.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| | [Test](https://pr-agent-docs.codium.ai/tools/test/) 💎 | ✅ | ✅ | | |
|
| | [Test](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | |
|
||||||
|
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| | | | | | |
|
| | | | | | |
|
||||||
| USAGE | [CLI](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#local-repo-cli) | ✅ | ✅ | ✅ | ✅ |
|
| USAGE | [CLI](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#local-repo-cli) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [App / webhook](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-app) | ✅ | ✅ | ✅ | ✅ |
|
| | [App / webhook](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-app) | ✅ | ✅ | ✅ | ✅ |
|
||||||
@ -118,39 +124,43 @@ Supported commands per platform:
|
|||||||
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| | [Global and wiki configurations](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Global and wiki configurations](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| | [PR interactive actions](https://www.codium.ai/images/pr_agent/pr-actions.mp4) 💎 | ✅ | ✅ | | |
|
| | [PR interactive actions](https://www.qodo.ai/images/pr_agent/pr-actions.mp4) 💎 | ✅ | ✅ | | |
|
||||||
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | |
|
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | |
|
||||||
- 💎 means this feature is available only in [PR-Agent Pro](https://www.codium.ai/pricing/)
|
- 💎 means this feature is available only in [Qodo-Merge](https://www.qodo.ai/pricing/)
|
||||||
|
|
||||||
[//]: # (- Support for additional git providers is described in [here](./docs/Full_environments.md))
|
[//]: # (- Support for additional git providers is described in [here](./docs/Full_environments.md))
|
||||||
___
|
___
|
||||||
|
|
||||||
‣ **Auto Description ([`/describe`](https://pr-agent-docs.codium.ai/tools/describe/))**: Automatically generating PR description - title, type, summary, code walkthrough and labels.
|
‣ **Auto Description ([`/describe`](https://qodo-merge-docs.qodo.ai/tools/describe/))**: Automatically generating PR description - title, type, summary, code walkthrough and labels.
|
||||||
\
|
\
|
||||||
‣ **Auto Review ([`/review`](https://pr-agent-docs.codium.ai/tools/review/))**: Adjustable feedback about the PR, possible issues, security concerns, review effort and more.
|
‣ **Auto Review ([`/review`](https://qodo-merge-docs.qodo.ai/tools/review/))**: Adjustable feedback about the PR, possible issues, security concerns, review effort and more.
|
||||||
\
|
\
|
||||||
‣ **Code Suggestions ([`/improve`](https://pr-agent-docs.codium.ai/tools/improve/))**: Code suggestions for improving the PR.
|
‣ **Code Suggestions ([`/improve`](https://qodo-merge-docs.qodo.ai/tools/improve/))**: Code suggestions for improving the PR.
|
||||||
\
|
\
|
||||||
‣ **Question Answering ([`/ask ...`](https://pr-agent-docs.codium.ai/tools/ask/))**: Answering free-text questions about the PR.
|
‣ **Question Answering ([`/ask ...`](https://qodo-merge-docs.qodo.ai/tools/ask/))**: Answering free-text questions about the PR.
|
||||||
\
|
\
|
||||||
‣ **Update Changelog ([`/update_changelog`](https://pr-agent-docs.codium.ai/tools/update_changelog/))**: Automatically updating the CHANGELOG.md file with the PR changes.
|
‣ **Update Changelog ([`/update_changelog`](https://qodo-merge-docs.qodo.ai/tools/update_changelog/))**: Automatically updating the CHANGELOG.md file with the PR changes.
|
||||||
\
|
\
|
||||||
‣ **Find Similar Issue ([`/similar_issue`](https://pr-agent-docs.codium.ai/tools/similar_issues/))**: Automatically retrieves and presents similar issues.
|
‣ **Find Similar Issue ([`/similar_issue`](https://qodo-merge-docs.qodo.ai/tools/similar_issues/))**: Automatically retrieves and presents similar issues.
|
||||||
\
|
\
|
||||||
‣ **Add Documentation 💎 ([`/add_docs`](https://pr-agent-docs.codium.ai/tools/documentation/))**: Generates documentation to methods/functions/classes that changed in the PR.
|
‣ **Add Documentation 💎 ([`/add_docs`](https://qodo-merge-docs.qodo.ai/tools/documentation/))**: Generates documentation to methods/functions/classes that changed in the PR.
|
||||||
\
|
\
|
||||||
‣ **Generate Custom Labels 💎 ([`/generate_labels`](https://pr-agent-docs.codium.ai/tools/custom_labels/))**: Generates custom labels for the PR, based on specific guidelines defined by the user.
|
‣ **Generate Custom Labels 💎 ([`/generate_labels`](https://qodo-merge-docs.qodo.ai/tools/custom_labels/))**: Generates custom labels for the PR, based on specific guidelines defined by the user.
|
||||||
\
|
\
|
||||||
‣ **Analyze 💎 ([`/analyze`](https://pr-agent-docs.codium.ai/tools/analyze/))**: Identify code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component.
|
‣ **Analyze 💎 ([`/analyze`](https://qodo-merge-docs.qodo.ai/tools/analyze/))**: Identify code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component.
|
||||||
\
|
\
|
||||||
‣ **Custom Prompt 💎 ([`/custom_prompt`](https://pr-agent-docs.codium.ai/tools/custom_prompt/))**: Automatically generates custom suggestions for improving the PR code, based on specific guidelines defined by the user.
|
‣ **Test 💎 ([`/test`](https://qodo-merge-docs.qodo.ai/tools/test/))**: Generate tests for a selected component, based on the PR code changes.
|
||||||
\
|
\
|
||||||
‣ **Generate Tests 💎 ([`/test component_name`](https://pr-agent-docs.codium.ai/tools/test/))**: Generates unit tests for a selected component, based on the PR code changes.
|
‣ **Custom Prompt 💎 ([`/custom_prompt`](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/))**: Automatically generates custom suggestions for improving the PR code, based on specific guidelines defined by the user.
|
||||||
\
|
\
|
||||||
‣ **CI Feedback 💎 ([`/checks ci_job`](https://pr-agent-docs.codium.ai/tools/ci_feedback/))**: Automatically generates feedback and analysis for a failed CI job.
|
‣ **Generate Tests 💎 ([`/test component_name`](https://qodo-merge-docs.qodo.ai/tools/test/))**: Generates unit tests for a selected component, based on the PR code changes.
|
||||||
\
|
\
|
||||||
‣ **Similar Code 💎 ([`/find_similar_component`](https://pr-agent-docs.codium.ai/tools/similar_code/))**: Retrieves the most similar code components from inside the organization's codebase, or from open-source code.
|
‣ **CI Feedback 💎 ([`/checks ci_job`](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/))**: Automatically generates feedback and analysis for a failed CI job.
|
||||||
|
\
|
||||||
|
‣ **Similar Code 💎 ([`/find_similar_component`](https://qodo-merge-docs.qodo.ai/tools/similar_code/))**: Retrieves the most similar code components from inside the organization's codebase, or from open-source code.
|
||||||
|
\
|
||||||
|
‣ **Implement 💎 ([`/implement`](https://qodo-merge-docs.qodo.ai/tools/implement/))**: Generates implementation code from review suggestions.
|
||||||
___
|
___
|
||||||
|
|
||||||
## Example results
|
## Example results
|
||||||
@ -206,19 +216,19 @@ It does not have 'edit' access to your repo, for example, so it cannot update th
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
To set up your own PR-Agent, see the [Installation](https://pr-agent-docs.codium.ai/installation/) section below.
|
To set up your own PR-Agent, see the [Installation](https://qodo-merge-docs.qodo.ai/installation/) section below.
|
||||||
Note that when you set your own PR-Agent or use CodiumAI hosted PR-Agent, there is no need to mention `@CodiumAI-Agent ...`. Instead, directly start with the command, e.g., `/ask ...`.
|
Note that when you set your own PR-Agent or use Qodo hosted PR-Agent, there is no need to mention `@CodiumAI-Agent ...`. Instead, directly start with the command, e.g., `/ask ...`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
## PR-Agent Pro 💎
|
## Qodo Merge 💎
|
||||||
[PR-Agent Pro](https://www.codium.ai/pricing/) is a hosted version of PR-Agent, provided by CodiumAI. It is available for a monthly fee, and provides the following benefits:
|
[Qodo Merge](https://www.qodo.ai/pricing/) is a hosted version of PR-Agent, provided by Qodo. It is available for a monthly fee, and 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 account with zero data retention.
|
2. **Improved privacy** - No data will be stored or used to train models. Qodo Merge 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.
|
3. **Improved support** - Qodo Merge 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.
|
4. **Extra features** -In addition to the benefits listed above, Qodo Merge will emphasize more customization, and the usage of static code analysis, in addition to LLM logic, to improve results.
|
||||||
See [here](https://qodo-merge-docs.qodo.ai/overview/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 Qodo Merge.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -226,9 +236,9 @@ See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for a list of
|
|||||||
|
|
||||||
The following diagram illustrates PR-Agent tools and their flow:
|
The following diagram illustrates PR-Agent tools and their flow:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Check out the [PR Compression strategy](https://pr-agent-docs.codium.ai/core-abilities/#pr-compression-strategy) page for more details on how we convert a code diff to a manageable LLM prompt
|
Check out the [PR Compression strategy](https://qodo-merge-docs.qodo.ai/core-abilities/#pr-compression-strategy) page for more details on how we convert a code diff to a manageable LLM prompt
|
||||||
|
|
||||||
## Why use PR-Agent?
|
## Why use PR-Agent?
|
||||||
|
|
||||||
@ -237,7 +247,7 @@ A reasonable question that can be asked is: `"Why use PR-Agent? What makes it st
|
|||||||
Here are some advantages of PR-Agent:
|
Here are some advantages of PR-Agent:
|
||||||
|
|
||||||
- We emphasize **real-life practical usage**. Each tool (review, improve, ask, ...) has a single GPT-4 call, no more. We feel that this is critical for realistic team usage - obtaining an answer quickly (~30 seconds) and affordably.
|
- We emphasize **real-life practical usage**. Each tool (review, improve, ask, ...) has a single GPT-4 call, no more. We feel that this is critical for realistic team usage - obtaining an answer quickly (~30 seconds) and affordably.
|
||||||
- Our [PR Compression strategy](https://pr-agent-docs.codium.ai/core-abilities/#pr-compression-strategy) is a core ability that enables to effectively tackle both short and long PRs.
|
- Our [PR Compression strategy](https://qodo-merge-docs.qodo.ai/core-abilities/#pr-compression-strategy) is a core ability that enables to effectively tackle both short and long PRs.
|
||||||
- Our JSON prompting strategy enables to have **modular, customizable tools**. For example, the '/review' tool categories can be controlled via the [configuration](pr_agent/settings/configuration.toml) file. Adding additional categories is easy and accessible.
|
- Our JSON prompting strategy enables to have **modular, customizable tools**. For example, the '/review' tool categories can be controlled via the [configuration](pr_agent/settings/configuration.toml) file. Adding additional categories is easy and accessible.
|
||||||
- We support **multiple git providers** (GitHub, Gitlab, Bitbucket), **multiple ways** to use the tool (CLI, GitHub Action, GitHub App, Docker, ...), and **multiple models** (GPT-4, GPT-3.5, Anthropic, Cohere, Llama2).
|
- We support **multiple git providers** (GitHub, Gitlab, Bitbucket), **multiple ways** to use the tool (CLI, GitHub Action, GitHub App, Docker, ...), and **multiple models** (GPT-4, GPT-3.5, Anthropic, Cohere, Llama2).
|
||||||
|
|
||||||
@ -249,24 +259,24 @@ Here are some advantages of PR-Agent:
|
|||||||
- If you host PR-Agent with your OpenAI API key, it is between you and OpenAI. You can read their API data privacy policy here:
|
- If you host PR-Agent with your OpenAI API key, it is between you and OpenAI. You can read their API data privacy policy here:
|
||||||
https://openai.com/enterprise-privacy
|
https://openai.com/enterprise-privacy
|
||||||
|
|
||||||
### CodiumAI-hosted PR-Agent Pro 💎
|
### Qodo-hosted Qodo Merge 💎
|
||||||
|
|
||||||
- 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 💎, hosted by Qodo, 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, Qodo-hosted Qodo Merge will use Qodo’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) serves solely to modify the visual appearance of a GitHub PR screen. It does not transmit any user's repo or pull request code. Code is only sent for processing when a user submits a GitHub comment that activates a PR-Agent tool, in accordance with the standard privacy policy of PR-Agent.
|
- The [Qodo Merge Chrome extension](https://chromewebstore.google.com/detail/qodo-merge-ai-powered-cod/ephlnjeghhogofkifjloamocljapahnl) serves solely to modify the visual appearance of a GitHub PR screen. It does not transmit any user's repo or pull request code. Code is only sent for processing when a user submits a GitHub comment that activates a PR-Agent tool, in accordance with the standard privacy policy of Qodo-Merge.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
[](https://discord.gg/kG35uSHDBc)
|
[](https://discord.gg/kG35uSHDBc)
|
||||||
|
|
||||||
- Discord community: https://discord.gg/kG35uSHDBc
|
- Discord community: https://discord.gg/kG35uSHDBc
|
||||||
- CodiumAI site: https://codium.ai
|
- Qodo site: https://www.qodo.ai/
|
||||||
- Blog: https://www.codium.ai/blog/
|
- Blog: https://www.qodo.ai/blog/
|
||||||
- Troubleshooting: https://www.codium.ai/blog/technical-faq-and-troubleshooting/
|
- Troubleshooting: https://www.qodo.ai/blog/technical-faq-and-troubleshooting/
|
||||||
- Support: support@codium.ai
|
- Support: support@qodo.ai
|
||||||
|
62
SECURITY.md
Normal file
62
SECURITY.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
PR-Agent is an open-source tool to help efficiently review and handle pull requests. Qodo Merge is a paid version of PR-Agent, designed for companies and teams that require additional features and capabilities.
|
||||||
|
|
||||||
|
This document describes the security policy of PR-Agent. For Qodo Merge's security policy, see [here](https://qodo-merge-docs.qodo.ai/overview/data_privacy/#qodo-merge).
|
||||||
|
|
||||||
|
## PR-Agent Self-Hosted Solutions
|
||||||
|
|
||||||
|
When using PR-Agent with your OpenAI (or other LLM provider) API key, the security relationship is directly between you and the provider. We do not send your code to Qodo servers.
|
||||||
|
|
||||||
|
Types of [self-hosted solutions](https://qodo-merge-docs.qodo.ai/installation):
|
||||||
|
- Locally
|
||||||
|
- GitHub integration
|
||||||
|
- GitLab integration
|
||||||
|
- BitBucket integration
|
||||||
|
- Azure DevOps integration
|
||||||
|
|
||||||
|
|
||||||
|
## PR-Agent Supported Versions
|
||||||
|
|
||||||
|
This section outlines which versions of PR-Agent are currently supported with security updates.
|
||||||
|
|
||||||
|
### Docker Deployment Options
|
||||||
|
|
||||||
|
#### Latest Version
|
||||||
|
|
||||||
|
For the most recent updates, use our latest Docker image which is automatically built nightly:
|
||||||
|
```yaml
|
||||||
|
uses: qodo-ai/pr-agent@main
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Specific Release Version
|
||||||
|
|
||||||
|
For a fixed version, you can pin your action to a specific release version. Browse available releases at:
|
||||||
|
[PR-Agent Releases](https://github.com/qodo-ai/pr-agent/releases)
|
||||||
|
|
||||||
|
For example, to github action:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: PR Agent action step
|
||||||
|
id: pragent
|
||||||
|
uses: docker://codiumai/pr-agent:0.26-github_action
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Enhanced Security with Docker Digest
|
||||||
|
|
||||||
|
For maximum security, you can specify the Docker image using its digest:
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: PR Agent action step
|
||||||
|
id: pragent
|
||||||
|
uses: docker://codiumai/pr-agent@sha256:14165e525678ace7d9b51cda8652c2d74abb4e1d76b57c4a6ccaeba84663cc64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
We take the security of PR-Agent seriously. If you discover a security vulnerability, please report it immediately to:
|
||||||
|
|
||||||
|
Email: tal.r@qodo.ai
|
||||||
|
|
||||||
|
Please include a description of the vulnerability, steps to reproduce, and the affected PR-Agent version.
|
@ -4,7 +4,7 @@ WORKDIR /app
|
|||||||
ADD pyproject.toml .
|
ADD pyproject.toml .
|
||||||
ADD requirements.txt .
|
ADD requirements.txt .
|
||||||
ADD docs docs
|
ADD docs docs
|
||||||
RUN pip install . && rm pyproject.toml requirements.txt
|
RUN pip install --no-cache-dir . && rm pyproject.toml requirements.txt
|
||||||
ENV PYTHONPATH=/app
|
ENV PYTHONPATH=/app
|
||||||
|
|
||||||
FROM base AS github_app
|
FROM base AS github_app
|
||||||
@ -33,7 +33,7 @@ CMD ["python", "pr_agent/servers/azuredevops_server_webhook.py"]
|
|||||||
|
|
||||||
FROM base AS test
|
FROM base AS test
|
||||||
ADD requirements-dev.txt .
|
ADD requirements-dev.txt .
|
||||||
RUN pip install -r requirements-dev.txt && rm requirements-dev.txt
|
RUN pip install --no-cache-dir -r requirements-dev.txt && rm requirements-dev.txt
|
||||||
ADD pr_agent pr_agent
|
ADD pr_agent pr_agent
|
||||||
ADD tests tests
|
ADD tests tests
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ RUN yum update -y && \
|
|||||||
yum clean all
|
yum clean all
|
||||||
|
|
||||||
ADD pyproject.toml requirements.txt .
|
ADD pyproject.toml requirements.txt .
|
||||||
RUN pip install . && rm pyproject.toml
|
RUN pip install --no-cache-dir . && rm pyproject.toml
|
||||||
RUN pip install mangum==0.17.0
|
RUN pip install --no-cache-dir mangum==0.17.0
|
||||||
COPY pr_agent/ ${LAMBDA_TASK_ROOT}/pr_agent/
|
COPY pr_agent/ ${LAMBDA_TASK_ROOT}/pr_agent/
|
||||||
|
|
||||||
CMD ["pr_agent.servers.serverless.serverless"]
|
CMD ["pr_agent.servers.serverless.serverless"]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
We take your code's security and privacy seriously:
|
We take your code's security and privacy seriously:
|
||||||
|
|
||||||
- The Chrome extension will not send your code to any external servers.
|
- 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 Qodo Merge 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 integration.
|
||||||
|
@ -8,7 +8,7 @@ To enable private chat, simply install the Qodo Merge Chrome extension. After in
|
|||||||
This chat session is **private**, and won't be visible to other users.
|
This chat session is **private**, and won't be visible to other users.
|
||||||
|
|
||||||
All open-source repositories are supported.
|
All open-source repositories are supported.
|
||||||
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.
|
For private repositories, you will also need to install Qodo Merge. 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
|
#### Context-aware PR chat
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
[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.
|
[Qodo Merge Chrome extension](https://chromewebstore.google.com/detail/pr-agent-chrome-extension/ephlnjeghhogofkifjloamocljapahnl){:target="_blank"} 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, Qodo Merge 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.
|
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 [Qodo Merge Pro](https://github.com/apps/qodo-merge-pro) in addition to the extension (Quick GitHub app setup with a 14-day free trial. No credit card needed).
|
For private repositories, you will need to install [Qodo Merge](https://github.com/apps/qodo-merge-pro){:target="_blank"} 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).
|
For a demonstration of how to install Qodo Merge 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){:target="_blank"}.
|
||||||
|
|
||||||
<img src="https://codium.ai/images/pr_agent/PR-AgentChat.gif" width="768">
|
<img src="https://codium.ai/images/pr_agent/PR-AgentChat.gif" width="768">
|
||||||
|
|
||||||
|
69
docs/docs/core-abilities/auto_best_practices.md
Normal file
69
docs/docs/core-abilities/auto_best_practices.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# Auto Best Practices 💎
|
||||||
|
`Supported Git Platforms: GitHub`
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
{width=684}
|
||||||
|
|
||||||
|
> Note - enabling a [Wiki](https://qodo-merge-docs.qodo.ai/usage-guide/enabling_a_wiki/) is required for this feature.
|
||||||
|
|
||||||
|
### Finding Code Problems - Exploration Phase
|
||||||
|
|
||||||
|
The `improve` tool identifies potential issues, problems and bugs in Pull Request (PR) code changes.
|
||||||
|
Rather than focusing on minor issues like code style or formatting, the tool intelligently analyzes code to detect meaningful problems.
|
||||||
|
|
||||||
|
The analysis intentionally takes a flexible, _exploratory_ approach to identify meaningful potential issues, allowing the tool to surface relevant code suggestions without being constrained by predefined categories.
|
||||||
|
|
||||||
|
### Tracking Implemented Suggestions
|
||||||
|
|
||||||
|
Qodo Merge features a novel [tracking system](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking) that automatically detects when PR authors implement AI-generated code suggestions.
|
||||||
|
All accepted suggestions are aggregated in a repository-specific wiki page called [`.pr_agent_accepted_suggestions`](https://github.com/qodo-ai/pr-agent/wiki/.pr_agent_accepted_suggestions)
|
||||||
|
|
||||||
|
|
||||||
|
### Learning and Applying Auto Best Practices
|
||||||
|
|
||||||
|
Monthly, Qodo Merge analyzes the collection of accepted suggestions to generate repository-specific best practices, stored in [`.pr_agent_auto_best_practices`](https://github.com/qodo-ai/pr-agent/wiki/.pr_agent_auto_best_practices) wiki file.
|
||||||
|
These best practices reflect recurring patterns in accepted code improvements.
|
||||||
|
|
||||||
|
The `improve` tool will incorporate these best practices as an additional analysis layer, checking PR code changes against known patterns of previously accepted improvements.
|
||||||
|
This creates a two-phase analysis:
|
||||||
|
|
||||||
|
1. Open exploration for general code issues
|
||||||
|
2. Targeted checking against established best practices - exploiting the knowledge gained from past suggestions
|
||||||
|
|
||||||
|
By keeping these phases decoupled, the tool remains free to discover new or unseen issues and problems, while also learning from past experiences.
|
||||||
|
|
||||||
|
|
||||||
|
When presenting the suggestions generated by the `improve` tool, Qodo Merge will add a dedicated label for each suggestion generated from the auto best practices - 'Learned best practice':
|
||||||
|
|
||||||
|
{width=684}
|
||||||
|
|
||||||
|
|
||||||
|
## Auto Best Practices vs Custom Best Practices
|
||||||
|
|
||||||
|
Teams and companies can also manually define their own [custom best practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) in Qodo Merge.
|
||||||
|
|
||||||
|
When custom best practices exist, Qodo Merge will still generate an 'auto best practices' wiki file, though it won't be used by the `improve` tool.
|
||||||
|
However, this auto-generated file can still serve two valuable purposes:
|
||||||
|
|
||||||
|
1. It can help enhance your custom best practices with additional insights derived from suggestions your team found valuable enough to implement
|
||||||
|
2. It demonstrates effective patterns for writing AI-friendly best practices
|
||||||
|
|
||||||
|
Even when using custom best practices, we recommend regularly reviewing the auto best practices file to refine your custom rules.
|
||||||
|
|
||||||
|
## Relevant configurations
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auto_best_practices]
|
||||||
|
# Disable all auto best practices usage or generation
|
||||||
|
enable_auto_best_practices = true
|
||||||
|
|
||||||
|
# Disable usage of auto best practices file in the 'improve' tool
|
||||||
|
utilize_auto_best_practices = true
|
||||||
|
|
||||||
|
# Extra instructions to the auto best practices generation prompt
|
||||||
|
extra_instructions = ""
|
||||||
|
|
||||||
|
# Max number of patterns to be detected
|
||||||
|
max_patterns = 5
|
||||||
|
```
|
@ -120,9 +120,45 @@ jira_api_email = "YOUR_EMAIL"
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Jira Server/Data Center 💎
|
#### Jira Data Center/Server 💎
|
||||||
|
|
||||||
Currently, we only support the Personal Access Token (PAT) Authentication method.
|
##### Local App Authentication (For Qodo Merge On-Premise Customers)
|
||||||
|
|
||||||
|
##### 1. Step 1: Set up an application link in Jira Data Center/Server
|
||||||
|
* Go to Jira Administration > Applications > Application Links > Click on `Create link`
|
||||||
|
|
||||||
|
{width=384}
|
||||||
|
* Choose `External application` and set the direction to `Incoming` and then click `Continue`
|
||||||
|
|
||||||
|
{width=256}
|
||||||
|
* In the following screen, enter the following details:
|
||||||
|
* Name: `Qodo Merge`
|
||||||
|
* Redirect URL: Enter your Qodo Merge URL followed `https://{QODO_MERGE_ENDPOINT}/register_ticket_provider`
|
||||||
|
* Permission: Select `Read`
|
||||||
|
* Click `Save`
|
||||||
|
|
||||||
|
{width=384}
|
||||||
|
* Copy the `Client ID` and `Client secret` and set them in your `.secrets` file:
|
||||||
|
|
||||||
|
{width=256}
|
||||||
|
```toml
|
||||||
|
[jira]
|
||||||
|
jira_app_secret = "..."
|
||||||
|
jira_client_id = "..."
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 2. Step 2: Authenticate with Jira Data Center/Server
|
||||||
|
* Open this URL in your browser: `https://{QODO_MERGE_ENDPOINT}/jira_auth`
|
||||||
|
* Click on link
|
||||||
|
|
||||||
|
{width=384}
|
||||||
|
|
||||||
|
* You will be redirected to Jira Data Center/Server, click `Allow`
|
||||||
|
* You will be redirected back to Qodo Merge PR Agent and you will see a success message.
|
||||||
|
|
||||||
|
|
||||||
|
##### Personal Access Token (PAT) Authentication
|
||||||
|
We also support Personal Access Token (PAT) Authentication method.
|
||||||
|
|
||||||
1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account
|
1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account
|
||||||
2. In your Configuration file/Environment variables/Secrets file, add the following lines:
|
2. In your Configuration file/Environment variables/Secrets file, add the following lines:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
Qodo Merge 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:
|
||||||
|
|
||||||
- [Fetching ticket context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/)
|
- [Fetching ticket context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/)
|
||||||
|
- [Auto best practices](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices/)
|
||||||
- [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/)
|
- [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/)
|
- [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/)
|
||||||
- [Self-reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/)
|
- [Self-reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/)
|
||||||
@ -18,6 +19,7 @@ Here are some additional technical blogs from Qodo, that delve deeper into the c
|
|||||||
These resources provide more comprehensive insights into leveraging LLMs for software development.
|
These resources provide more comprehensive insights into leveraging LLMs for software development.
|
||||||
|
|
||||||
### Code Generation and LLMs
|
### Code Generation and LLMs
|
||||||
|
- [Effective AI code suggestions: less is more](https://www.qodo.ai/blog/effective-code-suggestions-llms-less-is-more/)
|
||||||
- [State-of-the-art Code Generation with AlphaCodium – From Prompt Engineering to Flow Engineering](https://www.qodo.ai/blog/qodoflow-state-of-the-art-code-generation-for-code-contests/)
|
- [State-of-the-art Code Generation with AlphaCodium – From Prompt Engineering to Flow Engineering](https://www.qodo.ai/blog/qodoflow-state-of-the-art-code-generation-for-code-contests/)
|
||||||
- [RAG for a Codebase with 10k Repos](https://www.qodo.ai/blog/rag-for-large-scale-code-repos/)
|
- [RAG for a Codebase with 10k Repos](https://www.qodo.ai/blog/rag-for-large-scale-code-repos/)
|
||||||
|
|
||||||
|
@ -32,14 +32,14 @@ For example, when generating code suggestions for different files, Qodo Merge ca
|
|||||||
|
|
||||||
@@ ... @@ def func1():
|
@@ ... @@ def func1():
|
||||||
__new hunk__
|
__new hunk__
|
||||||
11 unchanged code line0 in the PR
|
11 unchanged code line0
|
||||||
12 unchanged code line1 in the PR
|
12 unchanged code line1
|
||||||
13 +new code line2 added in the PR
|
13 +new code line2 added
|
||||||
14 unchanged code line3 in the PR
|
14 unchanged code line3
|
||||||
__old hunk__
|
__old hunk__
|
||||||
unchanged code line0
|
unchanged code line0
|
||||||
unchanged code line1
|
unchanged code line1
|
||||||
-old code line2 removed in the PR
|
-old code line2 removed
|
||||||
unchanged code line3
|
unchanged code line3
|
||||||
|
|
||||||
@@ ... @@ def func2():
|
@@ ... @@ def func2():
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
??? note "Question: Can Qodo Merge serve as a substitute for a human reviewer?"
|
??? note "Q: Can Qodo Merge serve as a substitute for a human reviewer?"
|
||||||
#### Answer:<span style="display:none;">1</span>
|
#### Answer:<span style="display:none;">1</span>
|
||||||
|
|
||||||
Qodo Merge is designed to assist, not replace, human reviewers.
|
Qodo Merge is designed to assist, not replace, human reviewers.
|
||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
1. Preserves user's original PR header
|
1. Preserves user's original PR header
|
||||||
2. Places user's description above the AI-generated PR description
|
2. Places user's description above the AI-generated PR description
|
||||||
3. Cannot approve PRs; approval remains reviewer's responsibility
|
3. Won't approve PRs; approval remains reviewer's responsibility
|
||||||
4. The code suggestions are optional, and aim to:
|
4. The code suggestions are optional, and aim to:
|
||||||
- Encourage self-review and self-reflection
|
- Encourage self-review and self-reflection
|
||||||
- Highlight potential bugs or oversights
|
- Highlight potential bugs or oversights
|
||||||
@ -22,15 +22,15 @@
|
|||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
??? note "Question: I received an incorrect or irrelevant suggestion. Why?"
|
??? note "Q: I received an incorrect or irrelevant suggestion. Why?"
|
||||||
|
|
||||||
#### Answer:<span style="display:none;">2</span>
|
#### Answer:<span style="display:none;">2</span>
|
||||||
|
|
||||||
- Modern AI models, like Claude 3.5 Sonnet and GPT-4, are improving rapidly but remain imperfect. Users should critically evaluate all suggestions rather than accepting them automatically.
|
- Modern AI models, like Claude 3.5 Sonnet and GPT-4, are improving rapidly but remain imperfect. Users should critically evaluate all suggestions rather than accepting them automatically.
|
||||||
- AI errors are rare, but possible. A main value from reviewing the code suggestions lies in their high probability of catching **mistakes or bugs made by the PR author**. We believe it's worth spending 30-60 seconds reviewing suggestions, even if some aren't relevant, as this practice can enhances code quality and prevent bugs in production.
|
- AI errors are rare, but possible. A main value from reviewing the code suggestions lies in their high probability of catching **mistakes or bugs made by the PR author**. We believe it's worth spending 30-60 seconds reviewing suggestions, even if some aren't relevant, as this practice can enhance code quality and prevent bugs in production.
|
||||||
|
|
||||||
|
|
||||||
- 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:
|
- The hierarchical structure of the suggestions is designed to help the user _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 `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.
|
- 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.
|
||||||
@ -40,14 +40,14 @@ ___
|
|||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
??? note "Question: How can I get more tailored suggestions?"
|
??? note "Q: How can I get more tailored suggestions?"
|
||||||
#### Answer:<span style="display:none;">3</span>
|
#### Answer:<span style="display:none;">3</span>
|
||||||
|
|
||||||
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.
|
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?"
|
??? note "Q: Will you store my code? Are you using my code to train models?"
|
||||||
#### Answer:<span style="display:none;">4</span>
|
#### Answer:<span style="display:none;">4</span>
|
||||||
|
|
||||||
No. Qodo Merge 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.
|
||||||
@ -56,12 +56,35 @@ ___
|
|||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
??? note "Question: Can I use my own LLM keys with Qodo Merge?"
|
??? note "Q: Can I use my own LLM keys with Qodo Merge?"
|
||||||
#### Answer:<span style="display:none;">5</span>
|
#### Answer:<span style="display:none;">5</span>
|
||||||
|
|
||||||
When you self-host, you use your own keys.
|
When you self-host the [open-source](https://github.com/Codium-ai/pr-agent) version, you use your own keys.
|
||||||
|
|
||||||
Qodo Merge Pro with SaaS deployment is a hosted version of Qodo Merge, where Qodo manages the infrastructure and the keys.
|
Qodo Merge 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.
|
For enterprise customers, on-prem deployment is also available. [Contact us](https://www.codium.ai/contact/#pricing) for more information.
|
||||||
|
___
|
||||||
|
|
||||||
|
??? note "Q: Can Qodo Merge review draft/offline PRs?"
|
||||||
|
#### Answer:<span style="display:none;">5</span>
|
||||||
|
|
||||||
|
Yes. While Qodo Merge won't automatically review draft PRs, you can still get feedback by manually requesting it through [online commenting](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#online-usage).
|
||||||
|
|
||||||
|
For active PRs, you can customize the automatic feedback settings [here](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#qodo-merge-automatic-feedback) to match your team's workflow.
|
||||||
|
___
|
||||||
|
|
||||||
|
??? note "Q: Can the 'Review effort' feedback be calibrated or customized?"
|
||||||
|
#### Answer:<span style="display:none;">5</span>
|
||||||
|
|
||||||
|
Yes, you can customize review effort estimates using the `extra_instructions` configuration option (see [documentation](https://qodo-merge-docs.qodo.ai/tools/review/#configuration-options)).
|
||||||
|
|
||||||
|
Example mapping:
|
||||||
|
|
||||||
|
- Effort 1: < 30 minutes review time
|
||||||
|
- Effort 2: 30-60 minutes review time
|
||||||
|
- Effort 3: 60-90 minutes review time
|
||||||
|
- ...
|
||||||
|
|
||||||
|
Note: The effort levels (1-5) are primarily meant for _comparative_ purposes, helping teams prioritize reviewing smaller PRs first. The actual review duration may vary, as the focus is on providing consistent relative effort estimates.
|
||||||
|
|
||||||
___
|
___
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
Qodo Merge is an open-source tool to help efficiently review and handle pull requests.
|
[PR-Agent](https://github.com/Codium-ai/pr-agent) is an open-source tool to help efficiently review and handle pull requests.
|
||||||
|
Qodo Merge is a hosted version of PR-Agent, designed for companies and teams that require additional features and capabilities
|
||||||
|
|
||||||
- See the [Installation Guide](./installation/index.md) for instructions on installing and running the tool on different git platforms.
|
- 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 Qodo Merge 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 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.
|
- See the [Tools Guide](./tools/index.md) for a detailed description of the different tools.
|
||||||
|
|
||||||
|
|
||||||
## Qodo Merge Docs Smart Search
|
## Docs Smart Search
|
||||||
|
|
||||||
To search the documentation site using natural language:
|
To search the documentation site using natural language:
|
||||||
|
|
||||||
@ -18,50 +19,45 @@ To search the documentation site using natural language:
|
|||||||
- A pull request where Qodo Merge is installed
|
- A pull request where Qodo Merge is installed
|
||||||
- A [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat)
|
- 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.
|
2) The bot 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 Features
|
||||||
|
|
||||||
Qodo Merge offers extensive pull request functionalities across various git providers.
|
Qodo Merge offers extensive pull request functionalities across various git providers:
|
||||||
|
|
||||||
| | | GitHub | GitLab | Bitbucket | Azure DevOps |
|
| | | GitHub | Gitlab | Bitbucket | Azure DevOps |
|
||||||
|-------|---------------------------------------------------------------------------------------------------------|:--------------------:|:--------------------:|:--------------------:|:------------:|
|
|-------|-----------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|
|
||||||
| TOOLS | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ |
|
| TOOLS | Review | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ |
|
| | ⮑ Incremental | ✅ | | | |
|
||||||
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ |
|
| | Ask | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ |
|
| | Describe | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | ⮑ [Ask on code lines](https://pr-agent-docs.codium.ai/tools/ask#ask-lines) | ✅ | ✅ | | |
|
| | ⮑ [Inline file summary](https://qodo-merge-docs.qodo.ai/tools/describe/#inline-file-summary){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
||||||
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | ✅ |
|
| | Improve | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Ticket Context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) 💎 | ✅ | ✅ | ✅ | |
|
| | ⮑ Extended | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Utilizing Best Practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) 💎 | ✅ | ✅ | ✅ | |
|
| | [Custom Prompt](./tools/custom_prompt.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) 💎 | ✅ | | | |
|
| | Reflect and Review | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Suggestion Tracking](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking) 💎 | ✅ | ✅ | | |
|
| | Update CHANGELOG.md | ✅ | ✅ | ✅ | ️ |
|
||||||
| | [CI Feedback](https://pr-agent-docs.codium.ai/tools/ci_feedback/) 💎 | ✅ | | | |
|
| | Find Similar Issue | ✅ | | | ️ |
|
||||||
| | [PR Documentation](https://pr-agent-docs.codium.ai/tools/documentation/) 💎 | ✅ | ✅ | | |
|
| | [Add PR Documentation](./tools/documentation.md){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
||||||
| | [Custom Labels](https://pr-agent-docs.codium.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | |
|
| | [Generate Custom Labels](./tools/describe.md#handle-custom-labels-from-the-repos-labels-page-💎){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
||||||
| | [Analyze](https://pr-agent-docs.codium.ai/tools/analyze/) 💎 | ✅ | ✅ | | |
|
| | [Analyze PR Components](./tools/analyze.md){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
||||||
| | [Similar Code](https://pr-agent-docs.codium.ai/tools/similar_code/) 💎 | ✅ | | | |
|
|
||||||
| | [Custom Prompt](https://pr-agent-docs.codium.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | ✅ | |
|
|
||||||
| | [Test](https://pr-agent-docs.codium.ai/tools/test/) 💎 | ✅ | ✅ | | |
|
| | [Test](https://pr-agent-docs.codium.ai/tools/test/) 💎 | ✅ | ✅ | | |
|
||||||
| | | | | | |
|
| | [Implement](https://pr-agent-docs.codium.ai/tools/implement/) 💎 | ✅ | ✅ | ✅ | |
|
||||||
| USAGE | [CLI](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#local-repo-cli) | ✅ | ✅ | ✅ | ✅ |
|
| | | | | | ️ |
|
||||||
| | [App / webhook](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-app) | ✅ | ✅ | ✅ | ✅ |
|
| USAGE | CLI | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Tagging bot](https://github.com/Codium-ai/pr-agent#try-it-now) | ✅ | | | |
|
| | App / webhook | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Actions](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) | ✅ |✅| ✅ |✅|
|
| | Actions | ✅ | | | ️ |
|
||||||
| | | | | | |
|
| | | | | |
|
||||||
| CORE | [PR compression](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ |
|
| CORE | PR compression | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| | Repo language prioritization | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | Adaptive and token-aware file patch fitting | ✅ | ✅ | ✅ | ✅ |
|
| | Adaptive and token-aware file patch fitting | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | ✅ | ✅ | ✅ |
|
| | Multiple models support | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ |
|
| | Incremental PR review | ✅ | | | |
|
||||||
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | ✅ | |
|
|
||||||
| | [Global and wiki configurations](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | ✅ | |
|
|
||||||
| | [PR interactive actions](https://www.codium.ai/images/pr_agent/pr-actions.mp4) 💎 | ✅ | ✅ | | |
|
|
||||||
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | |
|
|
||||||
|
|
||||||
💎 marks a feature available only in [Qodo Merge Pro](https://www.qodo.ai/pricing/){:target="_blank"}
|
💎 marks a feature available only in [Qodo Merge](https://www.codium.ai/pricing/){:target="_blank"}, and not in the open-source version.
|
||||||
|
|
||||||
|
|
||||||
## Example Results
|
## Example Results
|
||||||
@ -97,4 +93,4 @@ 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 Qodo Merge.
|
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,5 +1,5 @@
|
|||||||
## Azure DevOps Pipeline
|
## Azure DevOps Pipeline
|
||||||
You can use a pre-built Action Docker image to run Qodo Merge as an Azure devops pipeline.
|
You can use a pre-built Action Docker image to run PR-Agent as an Azure devops pipeline.
|
||||||
add the following file to your repository under `azure-pipelines.yml`:
|
add the following file to your repository under `azure-pipelines.yml`:
|
||||||
```yaml
|
```yaml
|
||||||
# Opt out of CI triggers
|
# Opt out of CI triggers
|
||||||
@ -52,7 +52,7 @@ stages:
|
|||||||
This script will run Qodo Merge 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):
|
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.
|
Make sure to give pipeline permissions to the `pr_agent` variable group.
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ org = "https://dev.azure.com/YOUR_ORGANIZATION/"
|
|||||||
# pat = "YOUR_PAT_TOKEN" needed only if using PAT for authentication
|
# pat = "YOUR_PAT_TOKEN" needed only if using PAT for authentication
|
||||||
```
|
```
|
||||||
|
|
||||||
### Azure DevOps Webhook
|
## Azure DevOps Webhook
|
||||||
|
|
||||||
To trigger from an Azure webhook, you need to manually [add a webhook](https://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops).
|
To trigger from an Azure webhook, you need to manually [add a webhook](https://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops).
|
||||||
Use the "Pull request created" type to trigger a review, or "Pull request commented on" to trigger any supported comment with /<command> <args> comment on the relevant PR. Note that for the "Pull request commented on" trigger, only API v2.0 is supported.
|
Use the "Pull request created" type to trigger a review, or "Pull request commented on" to trigger any supported comment with /<command> <args> comment on the relevant PR. Note that for the "Pull request commented on" trigger, only API v2.0 is supported.
|
||||||
|
@ -27,10 +27,6 @@ You can get a Bitbucket token for your repository by following Repository Settin
|
|||||||
Note that comments on a PR are not supported in Bitbucket Pipeline.
|
Note that comments on a PR are not supported in Bitbucket Pipeline.
|
||||||
|
|
||||||
|
|
||||||
## Run using CodiumAI-hosted Bitbucket app 💎
|
|
||||||
|
|
||||||
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
|
## Bitbucket Server and Data Center
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
## Run as a GitHub Action
|
## Run as a GitHub Action
|
||||||
|
|
||||||
You can use our pre-built Github Action Docker image to run Qodo Merge as a Github Action.
|
You can use our pre-built Github Action Docker image to run PR-Agent as a Github Action.
|
||||||
|
|
||||||
1) Add the following file to your repository under `.github/workflows/pr_agent.yml`:
|
1) Add the following file to your repository under `.github/workflows/pr_agent.yml`:
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: PR Agent action step
|
- name: PR Agent action step
|
||||||
id: pragent
|
id: pragent
|
||||||
uses: Codium-ai/pr-agent@main
|
uses: qodo-ai/pr-agent@main
|
||||||
env:
|
env:
|
||||||
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
|
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
## Run as a GitLab Pipeline
|
## Run as a GitLab Pipeline
|
||||||
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.
|
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 Qodo Merge without setting up your own server.
|
||||||
|
|
||||||
(1) Add the following file to your repository under `.gitlab-ci.yml`:
|
(1) Add the following file to your repository under `.gitlab-ci.yml`:
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
## Self-hosted Qodo Merge
|
## Self-hosted PR-Agent
|
||||||
If you choose to host your 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://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/), if you prefer).
|
There are several ways to use self-hosted PR-Agent:
|
||||||
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 Qodo Merge:
|
|
||||||
|
|
||||||
- [Locally](./locally.md)
|
- [Locally](./locally.md)
|
||||||
- [GitHub](./github.md)
|
- [GitHub integration](./github.md)
|
||||||
- [GitLab](./gitlab.md)
|
- [GitLab integration](./gitlab.md)
|
||||||
- [BitBucket](./bitbucket.md)
|
- [BitBucket integration](./bitbucket.md)
|
||||||
- [Azure DevOps](./azure.md)
|
- [Azure DevOps integration](./azure.md)
|
||||||
|
|
||||||
## Qodo Merge Pro 💎
|
## Qodo Merge 💎
|
||||||
Qodo Merge Pro, an app hosted by CodiumAI for GitHub\GitLab\BitBucket, is also available.
|
Qodo Merge, an app hosted by QodoAI for GitHub\GitLab\BitBucket, is also available.
|
||||||
<br>
|
<br>
|
||||||
With Qodo Merge Pro, installation is as simple as signing up and adding the Qodo Merge app to your relevant repo.
|
With Qodo Merge, installation is as simple as adding the Qodo Merge app to your relevant repositories.
|
||||||
See [here](https://qodo-merge-docs.qodo.ai/installation/pr_agent_pro/) for more details.
|
See [here](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/) for more details.
|
||||||
|
@ -1,3 +1,77 @@
|
|||||||
|
To run PR-Agent locally, you first need to acquire two keys:
|
||||||
|
|
||||||
|
1. An OpenAI key from [here](https://platform.openai.com/api-keys){:target="_blank"}, 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 personal access token from your Git platform (GitHub, GitLab, BitBucket) with repo scope. GitHub token, for example, can be issued from [here](https://github.com/settings/tokens){:target="_blank"}
|
||||||
|
|
||||||
|
|
||||||
|
## Using Docker image
|
||||||
|
|
||||||
|
A list of the relevant tools can be found in the [tools guide](../tools/ask.md).
|
||||||
|
|
||||||
|
To invoke a tool (for example `review`), you can run PR-Agent directly from the Docker image. Here's how:
|
||||||
|
|
||||||
|
- For GitHub:
|
||||||
|
```
|
||||||
|
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
||||||
|
```
|
||||||
|
If you are using GitHub enterprise server, you need to specify the custom url as variable.
|
||||||
|
For example, if your GitHub server is at `https://github.mycompany.com`, add the following to the command:
|
||||||
|
```
|
||||||
|
-e GITHUB.BASE_URL=https://github.mycompany.com/api/v3
|
||||||
|
```
|
||||||
|
|
||||||
|
- For GitLab:
|
||||||
|
```
|
||||||
|
docker run --rm -it -e OPENAI.KEY=<your key> -e CONFIG.GIT_PROVIDER=gitlab -e GITLAB.PERSONAL_ACCESS_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have a dedicated GitLab instance, you need to specify the custom url as variable:
|
||||||
|
```
|
||||||
|
-e GITLAB.URL=<your gitlab instance url>
|
||||||
|
```
|
||||||
|
|
||||||
|
- For BitBucket:
|
||||||
|
```
|
||||||
|
docker run --rm -it -e CONFIG.GIT_PROVIDER=bitbucket -e OPENAI.KEY=$OPENAI_API_KEY -e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN codiumai/pr-agent:latest --pr_url=<pr_url> review
|
||||||
|
```
|
||||||
|
|
||||||
|
For other git providers, update `CONFIG.GIT_PROVIDER` accordingly and check the [`pr_agent/settings/.secrets_template.toml`](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/.secrets_template.toml) file for environment variables expected names and values.
|
||||||
|
|
||||||
|
### Utilizing environment variables
|
||||||
|
|
||||||
|
It is also possible to provide or override the configuration by setting the corresponding environment variables.
|
||||||
|
You can define the corresponding environment variables by following this convention: `<TABLE>__<KEY>=<VALUE>` or `<TABLE>.<KEY>=<VALUE>`.
|
||||||
|
The `<TABLE>` refers to a table/section in a configuration file and `<KEY>=<VALUE>` refers to the key/value pair of a setting in the configuration file.
|
||||||
|
|
||||||
|
For example, suppose you want to run `pr_agent` that connects to a self-hosted GitLab instance similar to an example above.
|
||||||
|
You can define the environment variables in a plain text file named `.env` with the following content:
|
||||||
|
|
||||||
|
```
|
||||||
|
CONFIG__GIT_PROVIDER="gitlab"
|
||||||
|
GITLAB__URL="<your url>"
|
||||||
|
GITLAB__PERSONAL_ACCESS_TOKEN="<your token>"
|
||||||
|
OPENAI__KEY="<your key>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you can run `pr_agent` using Docker with the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run --rm -it --env-file .env codiumai/pr-agent:latest <tool> <tool parameter>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### I get an error when running the Docker image. What should I do?
|
||||||
|
|
||||||
|
If you encounter an error when running the Docker image, it is almost always due to a misconfiguration of api keys or tokens.
|
||||||
|
|
||||||
|
Note that litellm, which is used by pr-agent, sometimes returns non-informative error messages such as `APIError: OpenAIException - Connection error.`
|
||||||
|
Carefully check the api keys and tokens you provided and make sure they are correct.
|
||||||
|
Adjustments may be needed depending on your llm provider.
|
||||||
|
|
||||||
|
For example, for Azure OpenAI, additional keys are [needed](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/#azure).
|
||||||
|
Same goes for other providers, make sure to check the [documentation](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/#changing-a-model)
|
||||||
|
|
||||||
## Using pip package
|
## Using pip package
|
||||||
|
|
||||||
Install the package:
|
Install the package:
|
||||||
@ -35,63 +109,6 @@ if __name__ == '__main__':
|
|||||||
main()
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
## Using Docker image
|
|
||||||
|
|
||||||
A list of the relevant tools can be found in the [tools guide](../tools/ask.md).
|
|
||||||
|
|
||||||
To invoke a tool (for example `review`), you can run directly from the Docker image. Here's how:
|
|
||||||
|
|
||||||
- For GitHub:
|
|
||||||
```
|
|
||||||
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
|
||||||
```
|
|
||||||
If you are using GitHub enterprise server, you need to specify the custom url as variable.
|
|
||||||
For example, if your GitHub server is at `https://github.mycompany.com`, add the following to the command:
|
|
||||||
```
|
|
||||||
-e GITHUB.BASE_URL=https://github.mycompany.com/api/v3
|
|
||||||
```
|
|
||||||
|
|
||||||
- For GitLab:
|
|
||||||
```
|
|
||||||
docker run --rm -it -e OPENAI.KEY=<your key> -e CONFIG.GIT_PROVIDER=gitlab -e GITLAB.PERSONAL_ACCESS_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
|
||||||
```
|
|
||||||
|
|
||||||
If you have a dedicated GitLab instance, you need to specify the custom url as variable:
|
|
||||||
```
|
|
||||||
-e GITLAB.URL=<your gitlab instance url>
|
|
||||||
```
|
|
||||||
|
|
||||||
- For BitBucket:
|
|
||||||
```
|
|
||||||
docker run --rm -it -e CONFIG.GIT_PROVIDER=bitbucket -e OPENAI.KEY=$OPENAI_API_KEY -e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN codiumai/pr-agent:latest --pr_url=<pr_url> review
|
|
||||||
```
|
|
||||||
|
|
||||||
For other git providers, update `CONFIG.GIT_PROVIDER` accordingly and check the `pr_agent/settings/.secrets_template.toml` file for environment variables expected names and values.
|
|
||||||
The `pr_agent` uses [Dynaconf](https://www.dynaconf.com/) to load settings from configuration files.
|
|
||||||
|
|
||||||
It is also possible to provide or override the configuration by setting the corresponding environment variables.
|
|
||||||
You can define the corresponding environment variables by following this convention: `<TABLE>__<KEY>=<VALUE>` or `<TABLE>.<KEY>=<VALUE>`.
|
|
||||||
The `<TABLE>` refers to a table/section in a configuration file and `<KEY>=<VALUE>` refers to the key/value pair of a setting in the configuration file.
|
|
||||||
|
|
||||||
For example, suppose you want to run `pr_agent` that connects to a self-hosted GitLab instance similar to an example above.
|
|
||||||
You can define the environment variables in a plain text file named `.env` with the following content:
|
|
||||||
|
|
||||||
> Warning: Never commit the `.env` file to version control system as it might contains sensitive credentials!
|
|
||||||
|
|
||||||
```
|
|
||||||
CONFIG__GIT_PROVIDER="gitlab"
|
|
||||||
GITLAB__URL="<your url>"
|
|
||||||
GITLAB__PERSONAL_ACCESS_TOKEN="<your token>"
|
|
||||||
OPENAI__KEY="<your key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, you can run `pr_agent` using Docker with the following command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run --rm -it --env-file .env codiumai/pr-agent:latest <tool> <tool parameter>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Run from source
|
## Run from source
|
||||||
|
|
||||||
|
49
docs/docs/installation/pr_agent.md
Normal file
49
docs/docs/installation/pr_agent.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# PR-Agent Installation Guide
|
||||||
|
|
||||||
|
PR-Agent can be deployed in various environments and platforms. Choose the installation method that best suits your needs:
|
||||||
|
|
||||||
|
## 🖥️ Local Installation
|
||||||
|
|
||||||
|
Learn how to run PR-Agent locally using:
|
||||||
|
|
||||||
|
- Docker image
|
||||||
|
- pip package
|
||||||
|
- CLI from source code
|
||||||
|
|
||||||
|
[View Local Installation Guide →](https://qodo-merge-docs.qodo.ai/installation/locally/)
|
||||||
|
|
||||||
|
## 🐙 GitHub Integration
|
||||||
|
|
||||||
|
Set up PR-Agent with GitHub as:
|
||||||
|
|
||||||
|
- GitHub Action
|
||||||
|
- Local GitHub App
|
||||||
|
|
||||||
|
[View GitHub Integration Guide →](https://qodo-merge-docs.qodo.ai/installation/github/)
|
||||||
|
|
||||||
|
## 🦊 GitLab Integration
|
||||||
|
|
||||||
|
Deploy PR-Agent on GitLab as:
|
||||||
|
|
||||||
|
- GitLab pipeline job
|
||||||
|
- Local GitLab webhook server
|
||||||
|
|
||||||
|
[View GitLab Integration Guide →](https://qodo-merge-docs.qodo.ai/installation/gitlab/)
|
||||||
|
|
||||||
|
## 🟦 BitBucket Integration
|
||||||
|
|
||||||
|
Implement PR-Agent in BitBucket as:
|
||||||
|
|
||||||
|
- BitBucket pipeline job
|
||||||
|
- Local BitBucket server
|
||||||
|
|
||||||
|
[View BitBucket Integration Guide →](https://qodo-merge-docs.qodo.ai/installation/bitbucket/)
|
||||||
|
|
||||||
|
## 🔷 Azure DevOps Integration
|
||||||
|
|
||||||
|
Configure PR-Agent with Azure DevOps as:
|
||||||
|
|
||||||
|
- Azure DevOps pipeline job
|
||||||
|
- Local Azure DevOps webhook
|
||||||
|
|
||||||
|
[View Azure DevOps Integration Guide →](https://qodo-merge-docs.qodo.ai/installation/azure/)
|
@ -1,42 +1,44 @@
|
|||||||
Qodo Merge Pro is a versatile application compatible with GitHub, GitLab, and BitBucket, hosted by QodoAI.
|
Qodo Merge is a versatile application compatible with GitHub, GitLab, and BitBucket, hosted by QodoAI.
|
||||||
See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for more details about the benefits of using Qodo Merge Pro.
|
See [here](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/) for more details about the benefits of using Qodo Merge.
|
||||||
|
|
||||||
A complimentary two-week trial is provided to all new users. Following the trial period, user licenses (seats) are required for continued access.
|
A complimentary two-week trial is provided to all new users. Following the trial period, user licenses (seats) are required for continued access.
|
||||||
To purchase user licenses, please visit our [pricing page](https://www.qodo.ai/pricing/).
|
To purchase user licenses, please visit our [pricing page](https://www.qodo.ai/pricing/).
|
||||||
Once subscribed, users can seamlessly deploy the application across any of their code repositories.
|
Once subscribed, users can seamlessly deploy the application across any of their code repositories.
|
||||||
|
|
||||||
## Install Qodo Merge Pro for GitHub
|
## Install Qodo Merge for GitHub
|
||||||
|
|
||||||
### GitHub Cloud
|
### GitHub Cloud
|
||||||
|
|
||||||
Qodo Merge Pro for GitHub cloud is available for installation through the [GitHub Marketplace](https://github.com/apps/qodo-merge-pro).
|
Qodo Merge for GitHub cloud is available for installation through the [GitHub Marketplace](https://github.com/apps/qodo-merge-pro).
|
||||||
|
|
||||||
{width=468}
|
{width=468}
|
||||||
|
|
||||||
### GitHub Enterprise Server
|
### GitHub Enterprise Server
|
||||||
|
|
||||||
To use Qodo Merge Pro application on your private GitHub Enterprise Server, you will need to contact us for starting an [Enterprise](https://www.codium.ai/pricing/) trial.
|
To use Qodo Merge application on your private GitHub Enterprise Server, you will need to [contact](https://www.qodo.ai/contact/#pricing) Qodo for starting an Enterprise trial.
|
||||||
|
|
||||||
### GitHub Open Source Projects
|
### GitHub Open Source Projects
|
||||||
|
|
||||||
For open-source projects, Qodo Merge Pro is available for free usage. To install Qodo Merge Pro for your open-source repositories, use the following marketplace [link](https://github.com/apps/qodo-merge-pro-for-open-source).
|
For open-source projects, Qodo Merge is available for free usage. To install Qodo Merge for your open-source repositories, use the following marketplace [link](https://github.com/apps/qodo-merge-pro-for-open-source).
|
||||||
|
|
||||||
## Install Qodo Merge Pro for Bitbucket
|
## Install Qodo Merge for Bitbucket
|
||||||
|
|
||||||
### Bitbucket Cloud
|
### Bitbucket Cloud
|
||||||
|
|
||||||
Qodo Merge Pro for Bitbucket Cloud is available for installation through the following [link](https://bitbucket.org/site/addons/authorize?addon_key=d6df813252c37258)
|
Qodo Merge for Bitbucket Cloud is available for installation through the following [link](https://bitbucket.org/site/addons/authorize?addon_key=d6df813252c37258)
|
||||||
|
|
||||||
{width=468}
|
{width=468}
|
||||||
|
|
||||||
### Bitbucket Server
|
### Bitbucket Server
|
||||||
|
|
||||||
To use Qodo Merge Pro application on your private Bitbucket Server, you will need to contact us for starting an [Enterprise](https://www.codium.ai/pricing/) trial.
|
To use Qodo Merge application on your private Bitbucket Server, you will need to contact us for starting an [Enterprise](https://www.qodo.ai/pricing/) trial.
|
||||||
|
|
||||||
|
|
||||||
## Install Qodo Merge Pro for GitLab (Teams & Enterprise)
|
## Install Qodo Merge for GitLab
|
||||||
|
|
||||||
Since GitLab platform does not support apps, installing Qodo Merge Pro for GitLab is a bit more involved, and requires the following steps:
|
### GitLab Cloud
|
||||||
|
|
||||||
|
Since GitLab platform does not support apps, installing Qodo Merge for GitLab is a bit more involved, and requires the following steps:
|
||||||
|
|
||||||
#### Step 1
|
#### Step 1
|
||||||
|
|
||||||
@ -79,3 +81,7 @@ Enable SSL verification: Check the box.
|
|||||||
You’re all set!
|
You’re all set!
|
||||||
|
|
||||||
Open a new merge request or add a MR comment with one of Qodo Merge’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.
|
||||||
|
|
||||||
|
### GitLab Server
|
||||||
|
|
||||||
|
For a trial period of two weeks on your private GitLab Server, the same [installation steps](#gitlab-cloud) as for GitLab Cloud apply. After the trial period, you will need to [contact](https://www.qodo.ai/contact/#pricing) Qodo for moving to an Enterprise account.
|
@ -1,12 +1,12 @@
|
|||||||
## Self-hosted Qodo Merge
|
## Self-hosted PR-Agent
|
||||||
|
|
||||||
- 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.
|
- 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 Qodo servers.
|
||||||
|
|
||||||
## Qodo Merge Pro 💎
|
## Qodo Merge 💎
|
||||||
|
|
||||||
- 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.
|
- When using Qodo Merge💎, hosted by Qodo, 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 Qodo Merge Pro will use CodiumAI’s proprietary models. If this is the case, you will be notified.
|
- For certain clients, Qodo Merge will use Qodo’s proprietary models. If this is the case, you will be notified.
|
||||||
|
|
||||||
- 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.
|
- 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.
|
||||||
|
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
# Overview
|
|
||||||
|
|
||||||
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 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.
|
|
||||||
|
|
||||||
|
|
||||||
## 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 | ✅ | | | |
|
|
||||||
| | Ask | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Describe | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | ⮑ [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"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Reflect and Review | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Update CHANGELOG.md | ✅ | ✅ | ✅ | ️ |
|
|
||||||
| | Find Similar Issue | ✅ | | | ️ |
|
|
||||||
| | [Add PR Documentation](./tools/documentation.md){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
|
||||||
| | [Generate Custom Labels](./tools/describe.md#handle-custom-labels-from-the-repos-labels-page-💎){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
|
||||||
| | [Analyze PR Components](./tools/analyze.md){:target="_blank"} 💎 | ✅ | ✅ | | ✅ |
|
|
||||||
| | | | | | ️ |
|
|
||||||
| USAGE | CLI | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | App / webhook | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Actions | ✅ | | | ️ |
|
|
||||||
| | | | | |
|
|
||||||
| CORE | PR compression | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Repo language prioritization | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Adaptive and token-aware file patch fitting | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Multiple models support | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | Incremental PR review | ✅ | | | |
|
|
||||||
| | [Static code analysis](./tools/analyze.md/){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| | [Multiple configuration options](./usage-guide/configuration_options.md){:target="_blank"} 💎 | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
|
|
||||||
💎 marks a feature available only in [Qodo Merge Pro](https://www.codium.ai/pricing/){:target="_blank"}
|
|
||||||
|
|
||||||
|
|
||||||
## Example Results
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
#### [/describe](https://github.com/Codium-ai/pr-agent/pull/530)
|
|
||||||
<figure markdown="1">
|
|
||||||
{width=512}
|
|
||||||
</figure>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
#### [/review](https://github.com/Codium-ai/pr-agent/pull/732#issuecomment-1975099151)
|
|
||||||
<figure markdown="1">
|
|
||||||
{width=512}
|
|
||||||
</figure>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
#### [/improve](https://github.com/Codium-ai/pr-agent/pull/732#issuecomment-1975099159)
|
|
||||||
<figure markdown="1">
|
|
||||||
{width=512}
|
|
||||||
</figure>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
#### [/generate_labels](https://github.com/Codium-ai/pr-agent/pull/530)
|
|
||||||
<figure markdown="1">
|
|
||||||
{width=300}
|
|
||||||
</figure>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
## How it Works
|
|
||||||
|
|
||||||
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,21 +1,21 @@
|
|||||||
### Overview
|
### Overview
|
||||||
|
|
||||||
[Qodo Merge Pro](https://www.codium.ai/pricing/) is a hosted version of open-source [Qodo Merge (PR-Agent)](https://github.com/Codium-ai/pr-agent). A complimentary two-week trial is offered, followed by a monthly subscription fee.
|
[Qodo Merge](https://www.codium.ai/pricing/){:target="_blank"} is a paid, hosted version of open-source [PR-Agent](https://github.com/Codium-ai/pr-agent){:target="_blank"}. 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:
|
Qodo Merge 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 Qodo Merge 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. Qodo Merge 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 will employ zero data retention, and will use an OpenAI and Claude accounts with zero data retention.
|
||||||
|
|
||||||
3. **Improved support** - Qodo Merge Pro users will receive priority support, and will be able to request new features and capabilities.
|
3. **Improved support** - Qodo Merge users will receive priority support, and will be able to request new features and capabilities.
|
||||||
|
|
||||||
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/).
|
4. **Supporting self-hosted git servers** - Qodo Merge 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** - 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.
|
5. **PR Chat** - Qodo Merge 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
|
### Additional features
|
||||||
|
|
||||||
Here are some of the additional features and capabilities that Qodo Merge Pro offers:
|
Here are some of the additional features and capabilities that Qodo Merge offers:
|
||||||
|
|
||||||
| Feature | Description |
|
| Feature | Description |
|
||||||
|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
@ -24,28 +24,29 @@ Here are some of the additional features and capabilities that Qodo Merge Pro of
|
|||||||
| [**Apply suggestions**](https://qodo-merge-docs.qodo.ai/tools/improve/#overview) | Generate committable code from the relevant suggestions interactively by clicking on a checkbox |
|
| [**Apply suggestions**](https://qodo-merge-docs.qodo.ai/tools/improve/#overview) | Generate committable 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 |
|
| [**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 |
|
| [**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 |
|
| [**Advanced usage statistics**](https://www.codium.ai/contact/#/) | Qodo Merge 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 |
|
| [**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 |
|
| [**Interactive triggering**](https://qodo-merge-docs.qodo.ai/tools/analyze/#example-usage) | Interactively apply different tools via the `analyze` command |
|
||||||
| [**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 |
|
| [**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
|
### Additional tools
|
||||||
|
|
||||||
Here are additional tools that are available only for Qodo Merge Pro users:
|
Here are additional tools that are available only for Qodo Merge users:
|
||||||
|
|
||||||
| Feature | Description |
|
| Feature | Description |
|
||||||
|---------|-------------|
|
|---------------------------------------------------------------------------------------|-------------|
|
||||||
| [**Custom Prompt Suggestions**](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) | Generate code suggestions based on custom prompts from the user |
|
| [**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 |
|
| [**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 |
|
| [**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 |
|
| [**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 |
|
| [**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 |
|
| [**Similar code search**](https://qodo-merge-docs.qodo.ai/tools/similar_code/) | Search for similar code in the repository, organization, or entire GitHub |
|
||||||
|
| [**Code implementation**](https://qodo-merge-docs.qodo.ai/tools/implement/) | Generates implementation code from review suggestions |
|
||||||
|
|
||||||
|
|
||||||
### Supported languages
|
### Supported languages
|
||||||
|
|
||||||
Qodo Merge Pro leverages the world's leading code models - Claude 3.5 Sonnet and GPT-4.
|
Qodo Merge 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.
|
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, 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).
|
For specialized commands that require static code analysis, Qodo Merge 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 your repository.
|
To enable custom labels, you need to apply the [configuration changes](#configuration-options) to the local `.pr_agent.toml` file in your repository.
|
||||||
|
|
||||||
#### 3. Handle custom labels from the Repo's labels page 💎
|
#### 3. Handle custom labels from the Repo's labels page 💎
|
||||||
> This feature is available only in Qodo Merge Pro
|
> This feature is available only in Qodo Merge
|
||||||
|
|
||||||
* GitHub : `https://github.com/{owner}/{repo}/labels`, or click on the "Labels" tab in the issues or PRs page.
|
* 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.
|
* GitLab : `https://gitlab.com/{owner}/{repo}/-/labels`, or click on "Manage" -> "Labels" on the left menu.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
## Overview
|
## Overview
|
||||||
The `help` tool provides a list of all the available tools and their descriptions.
|
The `help` tool provides a list of all the available tools and their descriptions.
|
||||||
For Qodo Merge Pro users, it also enables to trigger each tool by checking the relevant box.
|
For Qodo Merge users, it also enables to trigger each tool by checking the relevant box.
|
||||||
|
|
||||||
It can be invoked manually by commenting on any PR:
|
It can be invoked manually by commenting on any PR:
|
||||||
```
|
```
|
||||||
|
52
docs/docs/tools/implement.md
Normal file
52
docs/docs/tools/implement.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
`Platforms supported: GitHub, GitLab, Bitbucket`
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `implement` tool converts human code review discussions and feedback into ready-to-commit code changes.
|
||||||
|
It leverages LLM technology to transform PR comments and review suggestions into concrete implementation code, helping developers quickly turn feedback into working solutions.
|
||||||
|
|
||||||
|
## Usage Scenarios
|
||||||
|
|
||||||
|
|
||||||
|
### For Reviewers
|
||||||
|
|
||||||
|
Reviewers can request code changes by: <br>
|
||||||
|
1. Selecting the code block to be modified. <br>
|
||||||
|
2. Adding a comment with the syntax:
|
||||||
|
```
|
||||||
|
/implement <code-change-description>
|
||||||
|
```
|
||||||
|
|
||||||
|
{width=640}
|
||||||
|
|
||||||
|
|
||||||
|
### For PR Authors
|
||||||
|
|
||||||
|
PR authors can implement suggested changes by replying to a review comment using either: <br>
|
||||||
|
1. Add specific implementation details as described above
|
||||||
|
```
|
||||||
|
/implement <code-change-description>
|
||||||
|
```
|
||||||
|
2. Use the original review comment as instructions
|
||||||
|
```
|
||||||
|
/implement
|
||||||
|
```
|
||||||
|
|
||||||
|
{width=640}
|
||||||
|
|
||||||
|
### For Referencing Comments
|
||||||
|
|
||||||
|
You can reference and implement changes from any comment by:
|
||||||
|
```
|
||||||
|
/implement <link-to-review-comment>
|
||||||
|
```
|
||||||
|
|
||||||
|
{width=640}
|
||||||
|
|
||||||
|
Note that the implementation will occur within the review discussion thread.
|
||||||
|
|
||||||
|
|
||||||
|
**Configuration options** <br>
|
||||||
|
- Use `/implement` to implement code change within and based on the review discussion. <br>
|
||||||
|
- Use `/implement <code-change-description>` inside a review discussion to implement specific instructions. <br>
|
||||||
|
- Use `/implement <link-to-review-comment>` to indirectly call the tool from any comment. <br>
|
@ -9,7 +9,7 @@ The tool can be triggered automatically every time a new PR is [opened](../usage
|
|||||||
|
|
||||||
{width=512}
|
{width=512}
|
||||||
|
|
||||||
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.
|
Note that the `Apply this suggestion` checkbox, which interactively converts a suggestion into a commitable code comment, is available only for Qodo Merge💎 users.
|
||||||
|
|
||||||
|
|
||||||
## Example usage
|
## Example usage
|
||||||
@ -54,7 +54,7 @@ num_code_suggestions_per_chunk = ...
|
|||||||
|
|
||||||
### Assessing Impact 💎
|
### Assessing Impact 💎
|
||||||
|
|
||||||
Note that Qodo Merge pro tracks two types of implementations:
|
Note that Qodo Merge tracks two types of implementations:
|
||||||
|
|
||||||
- Direct implementation - when the user directly applies the suggestion by clicking the `Apply` checkbox.
|
- 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, Qodo Merge 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.
|
||||||
@ -70,7 +70,7 @@ In post-process, Qodo Merge counts the number of suggestions that were implement
|
|||||||
## Suggestion tracking 💎
|
## Suggestion tracking 💎
|
||||||
`Platforms supported: GitHub, GitLab`
|
`Platforms supported: GitHub, GitLab`
|
||||||
|
|
||||||
Qodo Merge employs an novel detection system to automatically [identify](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) AI code suggestions that PR authors have accepted and implemented.
|
Qodo Merge employs a novel detection system to automatically [identify](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) AI code suggestions that PR authors have accepted and implemented.
|
||||||
|
|
||||||
Accepted suggestions are also automatically documented in a dedicated wiki page called `.pr_agent_accepted_suggestions`, allowing users to track historical changes, assess the tool's effectiveness, and learn from previously implemented recommendations in the repository.
|
Accepted suggestions are also automatically documented in a dedicated wiki page called `.pr_agent_accepted_suggestions`, allowing users to track historical changes, assess the tool's effectiveness, and learn from previously implemented recommendations in the repository.
|
||||||
An example [result](https://github.com/Codium-ai/pr-agent/wiki/.pr_agent_accepted_suggestions):
|
An example [result](https://github.com/Codium-ai/pr-agent/wiki/.pr_agent_accepted_suggestions):
|
||||||
@ -122,7 +122,7 @@ Use triple quotes to write multi-line instructions. Use bullet points or numbers
|
|||||||
|
|
||||||
>`Platforms supported: GitHub, GitLab, Bitbucket`
|
>`Platforms supported: GitHub, GitLab, Bitbucket`
|
||||||
|
|
||||||
Another option to give additional guidance to the AI model is by creating a dedicated [**wiki page**](https://github.com/Codium-ai/pr-agent/wiki) called `best_practices.md`.
|
Another option to give additional guidance to the AI model is by creating a `best_practices.md` file, either in your repository's root directory or as a [**wiki page**](https://github.com/Codium-ai/pr-agent/wiki) (we recommend the wiki page, as editing and maintaining it over time is easier).
|
||||||
This page can contain a list of best practices, coding standards, and guidelines that are specific to your repo/organization.
|
This page can contain a list of best practices, coding standards, and guidelines that are specific to your repo/organization.
|
||||||
|
|
||||||
The AI model will use this wiki page as a reference, and in case the PR code violates any of the guidelines, it will create additional suggestions, with a dedicated label: `Organization
|
The AI model will use this wiki page as a reference, and in case the PR code violates any of the guidelines, it will create additional suggestions, with a dedicated label: `Organization
|
||||||
@ -191,8 +191,44 @@ And the label will be: `{organization_name} best practice`.
|
|||||||
|
|
||||||
{width=512}
|
{width=512}
|
||||||
|
|
||||||
|
### Auto best practices 💎
|
||||||
|
|
||||||
### How to combine `extra instructions` and `best practices`
|
>`Platforms supported: GitHub`
|
||||||
|
|
||||||
|
'Auto best practices' is a novel Qodo Merge capability that:
|
||||||
|
|
||||||
|
1. Identifies recurring patterns from accepted suggestions
|
||||||
|
2. **Automatically** generates [best practices page](https://github.com/qodo-ai/pr-agent/wiki/.pr_agent_auto_best_practices) based on what your team consistently values
|
||||||
|
3. Applies these learned patterns to future code reviews
|
||||||
|
|
||||||
|
This creates an automatic feedback loop where the system continuously learns from your team's choices to provide increasingly relevant suggestions.
|
||||||
|
The system maintains two analysis phases:
|
||||||
|
|
||||||
|
- Open exploration for new issues
|
||||||
|
- Targeted checking against established best practices
|
||||||
|
|
||||||
|
Note that when a [custom best practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) exist, Qodo Merge will still generate an 'auto best practices' wiki file, though it won't use it in the `improve` tool.
|
||||||
|
Learn more about utilizing 'auto best practices' in our [detailed guide](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices/).
|
||||||
|
|
||||||
|
#### Relevant configurations
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auto_best_practices]
|
||||||
|
# Disable all auto best practices usage or generation
|
||||||
|
enable_auto_best_practices = true
|
||||||
|
|
||||||
|
# Disable usage of auto best practices file in the 'improve' tool
|
||||||
|
utilize_auto_best_practices = true
|
||||||
|
|
||||||
|
# Extra instructions to the auto best practices generation prompt
|
||||||
|
extra_instructions = ""
|
||||||
|
|
||||||
|
# Max number of patterns to be detected
|
||||||
|
max_patterns = 5
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Combining `extra instructions` and `best practices` 💎
|
||||||
|
|
||||||
The `extra instructions` configuration is more related to the `improve` tool prompt. It can be used, for example, to avoid specific suggestions ("Don't suggest to add try-except block", "Ignore changes in toml files", ...) or to emphasize specific aspects or formats ("Answer in Japanese", "Give only short suggestions", ...)
|
The `extra instructions` configuration is more related to the `improve` tool prompt. It can be used, for example, to avoid specific suggestions ("Don't suggest to add try-except block", "Ignore changes in toml files", ...) or to emphasize specific aspects or formats ("Answer in Japanese", "Give only short suggestions", ...)
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Here is a list of Qodo Merge 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 |
|
| Tool | Description |
|
||||||
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **[PR Description (`/describe`](./describe.md))** | Automatically generating PR description - title, type, summary, code walkthrough and labels |
|
| **[PR Description (`/describe`](./describe.md))** | Automatically generating PR description - title, type, summary, code walkthrough and labels |
|
||||||
| **[PR Review (`/review`](./review.md))** | Adjustable feedback about the PR, possible issues, security concerns, review effort and more |
|
| **[PR Review (`/review`](./review.md))** | Adjustable feedback about the PR, possible issues, security concerns, review effort and more |
|
||||||
| **[Code Suggestions (`/improve`](./improve.md))** | Code suggestions for improving the PR |
|
| **[Code Suggestions (`/improve`](./improve.md))** | Code suggestions for improving the PR |
|
||||||
@ -14,9 +14,10 @@ Here is a list of Qodo Merge tools, each with a dedicated page that explains how
|
|||||||
| **💎 [Add Documentation (`/add_docs`](./documentation.md))** | Generates documentation to methods/functions/classes that changed in the PR |
|
| **💎 [Add Documentation (`/add_docs`](./documentation.md))** | Generates documentation to methods/functions/classes that changed in the PR |
|
||||||
| **💎 [Generate Custom Labels (`/generate_labels`](./custom_labels.md))** | Generates custom labels for the PR, based on specific guidelines defined by the user |
|
| **💎 [Generate Custom Labels (`/generate_labels`](./custom_labels.md))** | Generates custom labels for the PR, based on specific guidelines defined by the user |
|
||||||
| **💎 [Analyze (`/analyze`](./analyze.md))** | Identify code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component|
|
| **💎 [Analyze (`/analyze`](./analyze.md))** | Identify code components that changed in the PR, and enables to interactively generate tests, docs, and code suggestions for each component|
|
||||||
|
| **💎 [Test (`/test`](./test.md))** | generate tests for a selected component, based on the PR code changes |
|
||||||
| **💎 [Custom Prompt (`/custom_prompt`](./custom_prompt.md))** | Automatically generates custom suggestions for improving the PR code, based on specific guidelines defined by the user |
|
| **💎 [Custom Prompt (`/custom_prompt`](./custom_prompt.md))** | Automatically generates custom suggestions for improving the PR code, based on specific guidelines defined by the user |
|
||||||
| **💎 [Generate Tests (`/test component_name`](./test.md))** | Automatically generates unit tests for a selected component, based on the PR code changes |
|
| **💎 [Generate Tests (`/test component_name`](./test.md))** | Automatically generates unit tests for a selected component, based on the PR code changes |
|
||||||
| **💎 [Improve Component (`/improve_component component_name`](./improve_component.md))** | Generates code suggestions for a specific code component that changed in the PR |
|
| **💎 [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 |
|
| **💎 [CI Feedback (`/checks ci_job`](./ci_feedback.md))** | Automatically generates feedback and analysis for a failed CI job |
|
||||||
|
| **💎 [Implement (`/implement`](./implement.md))** | Generates implementation code from review suggestions |
|
||||||
Note that the tools marked with 💎 are available only for Qodo Merge Pro users.
|
Note that the tools marked with 💎 are available only for Qodo Merge users.
|
||||||
|
@ -56,6 +56,10 @@ extra_instructions = "..."
|
|||||||
<td><b>persistent_comment</b></td>
|
<td><b>persistent_comment</b></td>
|
||||||
<td>If set to true, the review comment will be persistent, meaning that every new review request will edit the previous one. Default is true.</td>
|
<td>If set to true, the review comment will be persistent, meaning that every new review request will edit the previous one. Default is true.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>final_update_message</b></td>
|
||||||
|
<td>When set to true, updating a persistent review comment during online commenting will automatically add a short comment with a link to the updated review in the pull request .Default is true.</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>extra_instructions</b></td>
|
<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>
|
<td>Optional extra instructions to the tool. For example: "focus on the changes in the file X. Ignore change in ...".</td>
|
||||||
@ -119,10 +123,6 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
|
|||||||
<td><b>enable_auto_approval</b></td>
|
<td><b>enable_auto_approval</b></td>
|
||||||
<td>If set to true, the tool will approve the PR when invoked with the 'auto_approve' command. Default is false. This flag can be changed only from a configuration file.</td>
|
<td>If set to true, the tool will approve the PR when invoked with the 'auto_approve' command. Default is false. This flag can be changed only from a configuration file.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><b>maximal_review_effort</b></td>
|
|
||||||
<td>Maximal effort level for auto-approval. If the PR's estimated review effort is above this threshold, the auto-approval will not run. Default is 5.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
## Usage Tips
|
## Usage Tips
|
||||||
@ -194,12 +194,6 @@ If enabled, the `review` tool can approve a PR when a specific comment, `/review
|
|||||||
Qodo Merge 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:
|
|
||||||
```
|
|
||||||
[pr_reviewer]
|
|
||||||
maximal_review_effort = 5
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! tip "Code suggestions"
|
!!! tip "Code suggestions"
|
||||||
|
|
||||||
The `review` tool previously included a legacy feature for providing code suggestions (controlled by `--pr_reviewer.num_code_suggestion`). This functionality has been deprecated and replaced by the [`improve`](./improve.md) tool, which offers higher quality and more actionable code suggestions.
|
The `review` tool previously included a legacy feature for providing code suggestions (controlled by `--pr_reviewer.num_code_suggestion`). This functionality has been deprecated and replaced by the [`improve`](./improve.md) tool, which offers higher quality and more actionable code suggestions.
|
||||||
|
@ -17,8 +17,8 @@ The tool will generate tests for the selected component (if no component is stat
|
|||||||
|
|
||||||
(Example taken from [here](https://github.com/Codium-ai/pr-agent/pull/598#issuecomment-1913679429)):
|
(Example taken from [here](https://github.com/Codium-ai/pr-agent/pull/598#issuecomment-1913679429)):
|
||||||
|
|
||||||
**Notes**
|
**Notes** <br>
|
||||||
- Language that are currently supported by the tool: Python, Java, C++, JavaScript, TypeScript, C#.
|
- The following languages are currently supported: Python, Java, C++, JavaScript, TypeScript, C#. <br>
|
||||||
- This tool can also be triggered interactively by using the [`analyze`](./analyze.md) tool.
|
- This tool can also be triggered interactively by using the [`analyze`](./analyze.md) tool.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
## Qodo Merge Pro Models
|
|
||||||
|
|
||||||
The default models used by Qodo Merge Pro are a combination of Claude-3.5-sonnet and OpenAI's GPT-4 models.
|
|
||||||
|
|
||||||
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"
|
|
||||||
```
|
|
||||||
|
|
||||||
Or to restrict Qodo Merge Pro to using only `GPT-4o`, add this setting:
|
|
||||||
```
|
|
||||||
[config]
|
|
||||||
model="gpt-4o"
|
|
||||||
```
|
|
@ -1,5 +1,5 @@
|
|||||||
## Show possible configurations
|
## Show possible configurations
|
||||||
The possible configurations of Qodo Merge are stored in [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml).
|
The possible configurations of Qodo Merge are stored in [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml){:target="_blank"}.
|
||||||
In the [tools](https://qodo-merge-docs.qodo.ai/tools/) page you can find explanations on how to use these configurations for each tool.
|
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:
|
To print all the available configurations as a comment on your PR, you can use the following command:
|
||||||
@ -138,7 +138,17 @@ LANGSMITH_BASE_URL=<url>
|
|||||||
|
|
||||||
## Ignoring automatic commands in PRs
|
## Ignoring automatic commands in PRs
|
||||||
|
|
||||||
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).
|
Qodo Merge allows you to automatically ignore certain PRs based on various criteria:
|
||||||
|
|
||||||
|
- PRs with specific titles (using regex matching)
|
||||||
|
- PRs between specific branches (using regex matching)
|
||||||
|
- PRs that don't include changes from specific folders (using regex matching)
|
||||||
|
- PRs containing specific labels
|
||||||
|
- PRs opened by specific users
|
||||||
|
|
||||||
|
### Example usage
|
||||||
|
|
||||||
|
#### Ignoring PRs with specific titles
|
||||||
|
|
||||||
To ignore PRs with a specific title such as "[Bump]: ...", you can add the following to your `configuration.toml` file:
|
To ignore PRs with a specific title such as "[Bump]: ...", you can add the following to your `configuration.toml` file:
|
||||||
|
|
||||||
@ -149,6 +159,7 @@ ignore_pr_title = ["\\[Bump\\]"]
|
|||||||
|
|
||||||
Where the `ignore_pr_title` is a list of regex patterns to match the PR title you want to ignore. Default is `ignore_pr_title = ["^\\[Auto\\]", "^Auto"]`.
|
Where the `ignore_pr_title` is a list of regex patterns to match the PR title you want to ignore. Default is `ignore_pr_title = ["^\\[Auto\\]", "^Auto"]`.
|
||||||
|
|
||||||
|
#### Ignoring PRs between specific branches
|
||||||
|
|
||||||
To ignore PRs from specific source or target branches, you can add the following to your `configuration.toml` file:
|
To ignore PRs from specific source or target branches, you can add the following to your `configuration.toml` file:
|
||||||
|
|
||||||
@ -161,6 +172,7 @@ ignore_pr_target_branches = ["qa"]
|
|||||||
Where the `ignore_pr_source_branches` and `ignore_pr_target_branches` are lists of regex patterns to match the source and target branches you want to ignore.
|
Where the `ignore_pr_source_branches` and `ignore_pr_target_branches` are lists of regex patterns to match the source and target branches you want to ignore.
|
||||||
They are not mutually exclusive, you can use them together or separately.
|
They are not mutually exclusive, you can use them together or separately.
|
||||||
|
|
||||||
|
#### Ignoring PRs that don't include changes from specific folders
|
||||||
|
|
||||||
To allow only specific folders (often needed in large monorepos), set:
|
To allow only specific folders (often needed in large monorepos), set:
|
||||||
|
|
||||||
@ -170,3 +182,35 @@ allow_only_specific_folders=['folder1','folder2']
|
|||||||
```
|
```
|
||||||
|
|
||||||
For the configuration above, automatic feedback will only be triggered when the PR changes include files from 'folder1' or 'folder2'
|
For the configuration above, automatic feedback will only be triggered when the PR changes include files from 'folder1' or 'folder2'
|
||||||
|
|
||||||
|
#### Ignoring PRs containg specific labels
|
||||||
|
|
||||||
|
To ignore PRs containg specific labels, you can add the following to your `configuration.toml` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
ignore_pr_labels = ["do-not-merge"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the `ignore_pr_labels` is a list of labels that when present in the PR, the PR will be ignored.
|
||||||
|
|
||||||
|
#### Ignoring PRs from specific users
|
||||||
|
|
||||||
|
Qodo Merge automatically identifies and ignores pull requests created by bots using:
|
||||||
|
|
||||||
|
- GitHub's native bot detection system
|
||||||
|
- Name-based pattern matching
|
||||||
|
|
||||||
|
While this detection is robust, it may not catch all cases, particularly when:
|
||||||
|
|
||||||
|
- Bots are registered as regular user accounts
|
||||||
|
- Bot names don't match common patterns
|
||||||
|
|
||||||
|
To supplement the automatic bot detection, you can manually specify users to ignore. Add the following to your `configuration.toml` file to ignore PRs from specific users:
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
ignore_pr_authors = ["my-special-bot-user", ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the `ignore_pr_authors` is a list of usernames that you want to ignore.
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ When this parameter is set to `true`, Qodo Merge will not run any automatic tool
|
|||||||
|
|
||||||
### GitHub App
|
### GitHub App
|
||||||
|
|
||||||
!!! note "Configurations for Qodo Merge Pro"
|
!!! note "Configurations for Qodo Merge"
|
||||||
Qodo Merge Pro for GitHub is an App, hosted by CodiumAI. So all the instructions below are relevant also for Qodo Merge Pro users.
|
Qodo Merge for GitHub is an App, hosted by Qodo. So all the instructions below are relevant also for Qodo Merge users.
|
||||||
Same goes for [GitLab webhook](#gitlab-webhook) and [BitBucket App](#bitbucket-app) sections.
|
Same goes for [GitLab webhook](#gitlab-webhook) and [BitBucket App](#bitbucket-app) sections.
|
||||||
|
|
||||||
#### GitHub app automatic tools when a new PR is opened
|
#### GitHub app automatic tools when a new PR is opened
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
## Changing a model
|
## Changing a model in PR-Agent
|
||||||
|
|
||||||
See [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/algo/__init__.py) for a list of available models.
|
See [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/algo/__init__.py) for a list of available models.
|
||||||
To use a different model than the default (GPT-4), you need to edit in the [configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L2) the fields:
|
To use a different model than the default (GPT-4), you need to edit in the [configuration file](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L2) the fields:
|
||||||
@ -30,50 +30,39 @@ model="" # the OpenAI model you've deployed on Azure (e.g. gpt-4o)
|
|||||||
fallback_models=["..."]
|
fallback_models=["..."]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Ollama
|
||||||
|
|
||||||
|
You can run models locally through either [VLLM](https://docs.litellm.ai/docs/providers/vllm) or [Ollama](https://docs.litellm.ai/docs/providers/ollama)
|
||||||
|
|
||||||
|
E.g. to use a new model locally via Ollama, set in `.secrets.toml` or in a configuration file:
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
model = "ollama/qwen2.5-coder:32b"
|
||||||
|
fallback_models=["ollama/qwen2.5-coder:32b"]
|
||||||
|
custom_model_max_tokens=128000 # set the maximal input tokens for the model
|
||||||
|
duplicate_examples=true # will duplicate the examples in the prompt, to help the model to generate structured output
|
||||||
|
|
||||||
|
[ollama]
|
||||||
|
api_base = "http://localhost:11434" # or whatever port you're running Ollama on
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note "Local models vs commercial models"
|
||||||
|
Qodo Merge is compatible with almost any AI model, but analyzing complex code repositories and pull requests requires a model specifically optimized for code analysis.
|
||||||
|
|
||||||
|
Commercial models such as GPT-4, Claude Sonnet, and Gemini have demonstrated robust capabilities in generating structured output for code analysis tasks with large input. In contrast, most open-source models currently available (as of January 2025) face challenges with these complex tasks.
|
||||||
|
|
||||||
|
Based on our testing, local open-source models are suitable for experimentation and learning purposes (mainly for the `ask` command), but they are not suitable for production-level code analysis tasks.
|
||||||
|
|
||||||
|
Hence, for production workflows and real-world usage, we recommend using commercial models.
|
||||||
|
|
||||||
### Hugging Face
|
### Hugging Face
|
||||||
|
|
||||||
**Local**
|
|
||||||
You can run Hugging Face models locally through either [VLLM](https://docs.litellm.ai/docs/providers/vllm) or [Ollama](https://docs.litellm.ai/docs/providers/ollama)
|
|
||||||
|
|
||||||
E.g. to use a new Hugging Face model locally via Ollama, set:
|
|
||||||
```
|
|
||||||
[__init__.py]
|
|
||||||
MAX_TOKENS = {
|
|
||||||
"model-name-on-ollama": <max_tokens>
|
|
||||||
}
|
|
||||||
e.g.
|
|
||||||
MAX_TOKENS={
|
|
||||||
...,
|
|
||||||
"ollama/llama2": 4096
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[config] # in configuration.toml
|
|
||||||
model = "ollama/llama2"
|
|
||||||
fallback_models=["ollama/llama2"]
|
|
||||||
|
|
||||||
[ollama] # in .secrets.toml
|
|
||||||
api_base = ... # the base url for your Hugging Face inference endpoint
|
|
||||||
# e.g. if running Ollama locally, you may use:
|
|
||||||
api_base = "http://localhost:11434/"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Inference Endpoints
|
|
||||||
|
|
||||||
To use a new model with Hugging Face Inference Endpoints, for example, set:
|
To use a new model with Hugging Face Inference Endpoints, for example, set:
|
||||||
```
|
```
|
||||||
[__init__.py]
|
|
||||||
MAX_TOKENS = {
|
|
||||||
"model-name-on-huggingface": <max_tokens>
|
|
||||||
}
|
|
||||||
e.g.
|
|
||||||
MAX_TOKENS={
|
|
||||||
...,
|
|
||||||
"meta-llama/Llama-2-7b-chat-hf": 4096
|
|
||||||
}
|
|
||||||
[config] # in configuration.toml
|
[config] # in configuration.toml
|
||||||
model = "huggingface/meta-llama/Llama-2-7b-chat-hf"
|
model = "huggingface/meta-llama/Llama-2-7b-chat-hf"
|
||||||
fallback_models=["huggingface/meta-llama/Llama-2-7b-chat-hf"]
|
fallback_models=["huggingface/meta-llama/Llama-2-7b-chat-hf"]
|
||||||
|
custom_model_max_tokens=... # set the maximal input tokens for the model
|
||||||
|
|
||||||
[huggingface] # in .secrets.toml
|
[huggingface] # in .secrets.toml
|
||||||
key = ... # your Hugging Face api key
|
key = ... # your Hugging Face api key
|
||||||
@ -177,6 +166,25 @@ drop_params = true
|
|||||||
|
|
||||||
AWS session is automatically authenticated from your environment, but you can also explicitly set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION_NAME` environment variables. Please refer to [this document](https://litellm.vercel.app/docs/providers/bedrock) for more details.
|
AWS session is automatically authenticated from your environment, but you can also explicitly set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION_NAME` environment variables. Please refer to [this document](https://litellm.vercel.app/docs/providers/bedrock) for more details.
|
||||||
|
|
||||||
|
### DeepSeek
|
||||||
|
|
||||||
|
To use deepseek-chat model with DeepSeek, for example, set:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[config] # in configuration.toml
|
||||||
|
model = "deepseek/deepseek-chat"
|
||||||
|
fallback_models=["deepseek/deepseek-chat"]
|
||||||
|
```
|
||||||
|
|
||||||
|
and fill up your key
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[deepseek] # in .secrets.toml
|
||||||
|
key = ...
|
||||||
|
```
|
||||||
|
|
||||||
|
(you can obtain a deepseek-chat key from [here](https://platform.deepseek.com))
|
||||||
|
|
||||||
### Custom models
|
### Custom models
|
||||||
|
|
||||||
If the relevant model doesn't appear [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/algo/__init__.py), you can still use it as a custom model:
|
If the relevant model doesn't appear [here](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/algo/__init__.py), you can still use it as a custom model:
|
||||||
|
@ -20,7 +20,7 @@ In terms of precedence, wiki configurations will override local configurations,
|
|||||||
|
|
||||||
`Platforms supported: GitHub, GitLab, Bitbucket`
|
`Platforms supported: GitHub, GitLab, Bitbucket`
|
||||||
|
|
||||||
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.
|
With Qodo Merge, 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**.
|
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**.
|
||||||
|
|
||||||
|
|
||||||
|
33
docs/docs/usage-guide/enabling_a_wiki.md
Normal file
33
docs/docs/usage-guide/enabling_a_wiki.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
`Supported Git Platforms: GitHub, GitLab, Bitbucket`
|
||||||
|
|
||||||
|
|
||||||
|
For optimal functionality of Qodo Merge, we recommend enabling a wiki for each repository where Qodo Merge is installed. The wiki serves several important purposes:
|
||||||
|
|
||||||
|
**Key Wiki Features: 💎**
|
||||||
|
|
||||||
|
- Storing a [configuration file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#wiki-configuration-file)
|
||||||
|
- Defining a [`best_practices.md`](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) file
|
||||||
|
- Track [accepted suggestions](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking)
|
||||||
|
- Facilitates learning over time by creating an [auto_best_practices.md](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices) file
|
||||||
|
|
||||||
|
|
||||||
|
**Setup Instructions (GitHub):**
|
||||||
|
|
||||||
|
To enable a wiki for your repository:
|
||||||
|
|
||||||
|
1. Navigate to your repository's main page on GitHub
|
||||||
|
2. Select "Settings" from the top navigation bar
|
||||||
|
3. Locate the "Features" section
|
||||||
|
4. Enable the "Wikis" option by checking the corresponding box
|
||||||
|
5. Return to your repository's main page
|
||||||
|
6. Look for the newly added "Wiki" tab in the top navigation
|
||||||
|
7. Initialize your wiki by clicking "Create the first page" and saving (this step is important - without creating an initial page, the wiki will not be fully functional)
|
||||||
|
|
||||||
|
### Why Wiki?
|
||||||
|
|
||||||
|
- Your code (and its derivatives, including accepted code suggestions) is yours. Qodo Merge will never store it on external servers.
|
||||||
|
- Repository changes typically require pull requests, which create overhead and are time-consuming. This process is too cumbersome for auto data aggregation, and is not very convenient even for managing frequently updated content like configuration files and best practices.
|
||||||
|
- A repository wiki page provides an ideal balance:
|
||||||
|
- It lives within your repository, making it suitable for code-related documentation
|
||||||
|
- It enables quick updates without the overhead of pull requests
|
||||||
|
- It maintains full Git version control, allowing you to track changes over time.
|
@ -5,6 +5,7 @@ It includes information on how to adjust Qodo Merge configurations, define which
|
|||||||
|
|
||||||
|
|
||||||
- [Introduction](./introduction.md)
|
- [Introduction](./introduction.md)
|
||||||
|
- [Enabling a Wiki](./enabling_a_wiki)
|
||||||
- [Configuration File](./configuration_options.md)
|
- [Configuration File](./configuration_options.md)
|
||||||
- [Usage and Automation](./automations_and_usage.md)
|
- [Usage and Automation](./automations_and_usage.md)
|
||||||
- [Local Repo (CLI)](./automations_and_usage.md#local-repo-cli)
|
- [Local Repo (CLI)](./automations_and_usage.md#local-repo-cli)
|
||||||
@ -23,4 +24,4 @@ It includes information on how to adjust Qodo Merge configurations, define which
|
|||||||
- [Changing a model](./additional_configurations.md#changing-a-model)
|
- [Changing a model](./additional_configurations.md#changing-a-model)
|
||||||
- [Patch Extra Lines](./additional_configurations.md#patch-extra-lines)
|
- [Patch Extra Lines](./additional_configurations.md#patch-extra-lines)
|
||||||
- [Editing the prompts](./additional_configurations.md#editing-the-prompts)
|
- [Editing the prompts](./additional_configurations.md#editing-the-prompts)
|
||||||
- [Qodo Merge Pro Models](./PR_agent_pro_models.md)
|
- [Qodo Merge Models](./qodo_merge_models)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
After [installation](https://qodo-merge-docs.qodo.ai/installation/), there are three basic ways to invoke Qodo Merge:
|
After [installation](https://qodo-merge-docs.qodo.ai/installation/), there are three basic ways to invoke Qodo Merge:
|
||||||
|
|
||||||
1. Locally running a CLI command
|
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
|
2. Online usage - by [commenting](https://github.com/Codium-ai/pr-agent/pull/229#issuecomment-1695021901){:target="_blank"} on a PR
|
||||||
3. Enabling Qodo Merge tools to run automatically when a new PR is opened
|
3. Enabling Qodo Merge tools to run automatically when a new PR is opened
|
||||||
|
|
||||||
|
|
||||||
|
37
docs/docs/usage-guide/qodo_merge_models.md
Normal file
37
docs/docs/usage-guide/qodo_merge_models.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
The default models used by Qodo Merge are a combination of Claude-3.5-sonnet and OpenAI's GPT-4 models.
|
||||||
|
|
||||||
|
### Selecting a Specific Model
|
||||||
|
|
||||||
|
Users can configure Qodo Merge to use a specific model by editing the [configuration](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) file.
|
||||||
|
The models supported by Qodo Merge are:
|
||||||
|
|
||||||
|
- `claude-3-5-sonnet`
|
||||||
|
- `gpt-4o`
|
||||||
|
- `deepseek-r1`
|
||||||
|
- `o3-mini`
|
||||||
|
|
||||||
|
To restrict Qodo Merge to using only `Claude-3.5-sonnet`, add this setting:
|
||||||
|
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
model="claude-3-5-sonnet"
|
||||||
|
```
|
||||||
|
|
||||||
|
To restrict Qodo Merge to using only `GPT-4o`, add this setting:
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
model="gpt-4o"
|
||||||
|
```
|
||||||
|
|
||||||
|
To restrict Qodo Merge to using only `deepseek-r1`, add this setting:
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
model="deepseek/r1"
|
||||||
|
```
|
||||||
|
|
||||||
|
To restrict Qodo Merge to using only `o3-mini`, add this setting:
|
||||||
|
```
|
||||||
|
[config]
|
||||||
|
model="o3-mini"
|
||||||
|
```
|
@ -1,29 +1,26 @@
|
|||||||
site_name: Qodo Merge (formerly known as PR-Agent)
|
site_name: Qodo Merge (and open-source PR-Agent)
|
||||||
repo_url: https://github.com/Codium-ai/pr-agent
|
repo_url: https://github.com/Codium-ai/pr-agent
|
||||||
repo_name: Codium-ai/pr-agent
|
repo_name: Codium-ai/pr-agent
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
- Overview:
|
- Overview:
|
||||||
- 'index.md'
|
- 'index.md'
|
||||||
- 💎 Qodo Merge Pro: 'overview/pr_agent_pro.md'
|
- 💎 Qodo Merge: 'overview/pr_agent_pro.md'
|
||||||
- Data Privacy: 'overview/data_privacy.md'
|
- Data Privacy: 'overview/data_privacy.md'
|
||||||
- Installation:
|
- Installation:
|
||||||
- 'installation/index.md'
|
- 'installation/index.md'
|
||||||
- Locally: 'installation/locally.md'
|
- PR-Agent: 'installation/pr_agent.md'
|
||||||
- GitHub: 'installation/github.md'
|
- 💎 Qodo Merge: 'installation/qodo_merge.md'
|
||||||
- GitLab: 'installation/gitlab.md'
|
|
||||||
- BitBucket: 'installation/bitbucket.md'
|
|
||||||
- Azure DevOps: 'installation/azure.md'
|
|
||||||
- 💎 Qodo Merge Pro: 'installation/pr_agent_pro.md'
|
|
||||||
- Usage Guide:
|
- Usage Guide:
|
||||||
- 'usage-guide/index.md'
|
- 'usage-guide/index.md'
|
||||||
- Introduction: 'usage-guide/introduction.md'
|
- Introduction: 'usage-guide/introduction.md'
|
||||||
|
- Enabling a Wiki: 'usage-guide/enabling_a_wiki.md'
|
||||||
- Configuration File: 'usage-guide/configuration_options.md'
|
- Configuration File: 'usage-guide/configuration_options.md'
|
||||||
- Usage and Automation: 'usage-guide/automations_and_usage.md'
|
- Usage and Automation: 'usage-guide/automations_and_usage.md'
|
||||||
- Managing Mail Notifications: 'usage-guide/mail_notifications.md'
|
- Managing Mail Notifications: 'usage-guide/mail_notifications.md'
|
||||||
- Changing a Model: 'usage-guide/changing_a_model.md'
|
- Changing a Model: 'usage-guide/changing_a_model.md'
|
||||||
- Additional Configurations: 'usage-guide/additional_configurations.md'
|
- Additional Configurations: 'usage-guide/additional_configurations.md'
|
||||||
- 💎 Qodo Merge Pro Models: 'usage-guide/PR_agent_pro_models'
|
- 💎 Qodo Merge Models: 'usage-guide/qodo_merge_models.md'
|
||||||
- Tools:
|
- Tools:
|
||||||
- 'tools/index.md'
|
- 'tools/index.md'
|
||||||
- Describe: 'tools/describe.md'
|
- Describe: 'tools/describe.md'
|
||||||
@ -41,9 +38,11 @@ nav:
|
|||||||
- 💎 Custom Prompt: 'tools/custom_prompt.md'
|
- 💎 Custom Prompt: 'tools/custom_prompt.md'
|
||||||
- 💎 CI Feedback: 'tools/ci_feedback.md'
|
- 💎 CI Feedback: 'tools/ci_feedback.md'
|
||||||
- 💎 Similar Code: 'tools/similar_code.md'
|
- 💎 Similar Code: 'tools/similar_code.md'
|
||||||
|
- 💎 Implement: 'tools/implement.md'
|
||||||
- Core Abilities:
|
- Core Abilities:
|
||||||
- 'core-abilities/index.md'
|
- 'core-abilities/index.md'
|
||||||
- Fetching ticket context: 'core-abilities/fetching_ticket_context.md'
|
- Fetching ticket context: 'core-abilities/fetching_ticket_context.md'
|
||||||
|
- Auto best practices: 'core-abilities/auto_best_practices.md'
|
||||||
- Local and global metadata: 'core-abilities/metadata.md'
|
- Local and global metadata: 'core-abilities/metadata.md'
|
||||||
- Dynamic context: 'core-abilities/dynamic_context.md'
|
- Dynamic context: 'core-abilities/dynamic_context.md'
|
||||||
- Self-reflection: 'core-abilities/self_reflection.md'
|
- Self-reflection: 'core-abilities/self_reflection.md'
|
||||||
|
@ -60,13 +60,21 @@ class PRAgent:
|
|||||||
else:
|
else:
|
||||||
action, *args = request
|
action, *args = request
|
||||||
|
|
||||||
forbidden_cli_args = ['enable_auto_approval', 'base_url', 'url', 'app_name', 'secret_provider',
|
forbidden_cli_args = ['enable_auto_approval', 'approve_pr_on_self_review', 'base_url', 'url', 'app_name', 'secret_provider',
|
||||||
'git_provider', 'skip_keys', 'key', 'ANALYTICS_FOLDER', 'uri', 'app_id', 'webhook_secret',
|
'git_provider', 'skip_keys', 'openai.key', 'ANALYTICS_FOLDER', 'uri', 'app_id', 'webhook_secret',
|
||||||
'bearer_token', 'PERSONAL_ACCESS_TOKEN', 'override_deployment_type', 'private_key', 'api_base', 'api_type', 'api_version']
|
'bearer_token', 'PERSONAL_ACCESS_TOKEN', 'override_deployment_type', 'private_key',
|
||||||
|
'local_cache_path', 'enable_local_cache', 'jira_base_url', 'api_base', 'api_type', 'api_version',
|
||||||
|
'skip_keys']
|
||||||
if args:
|
if args:
|
||||||
for forbidden_arg in forbidden_cli_args:
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if forbidden_arg.lower() in arg.lower():
|
if arg.startswith('--'):
|
||||||
|
arg_word = arg.lower()
|
||||||
|
arg_word = arg_word.replace('__', '.') # replace double underscore with dot, e.g. --openai__key -> --openai.key
|
||||||
|
for forbidden_arg in forbidden_cli_args:
|
||||||
|
forbidden_arg_word = forbidden_arg.lower()
|
||||||
|
if '.' not in forbidden_arg_word:
|
||||||
|
forbidden_arg_word = '.' + forbidden_arg_word
|
||||||
|
if forbidden_arg_word in arg_word:
|
||||||
get_logger().error(
|
get_logger().error(
|
||||||
f"CLI argument for param '{forbidden_arg}' is forbidden. Use instead a configuration file."
|
f"CLI argument for param '{forbidden_arg}' is forbidden. Use instead a configuration file."
|
||||||
)
|
)
|
||||||
|
@ -26,9 +26,13 @@ MAX_TOKENS = {
|
|||||||
'o1-preview-2024-09-12': 128000, # 128K, but may be limited by config.max_model_tokens
|
'o1-preview-2024-09-12': 128000, # 128K, but may be limited by config.max_model_tokens
|
||||||
'o1-2024-12-17': 204800, # 200K, but may be limited by config.max_model_tokens
|
'o1-2024-12-17': 204800, # 200K, but may be limited by config.max_model_tokens
|
||||||
'o1': 204800, # 200K, but may be limited by config.max_model_tokens
|
'o1': 204800, # 200K, but may be limited by config.max_model_tokens
|
||||||
|
'o3-mini': 204800, # 200K, but may be limited by config.max_model_tokens
|
||||||
|
'o3-mini-2025-01-31': 204800, # 200K, but may be limited by config.max_model_tokens
|
||||||
'claude-instant-1': 100000,
|
'claude-instant-1': 100000,
|
||||||
'claude-2': 100000,
|
'claude-2': 100000,
|
||||||
'command-nightly': 4096,
|
'command-nightly': 4096,
|
||||||
|
'deepseek/deepseek-chat': 128000, # 128K, but may be limited by config.max_model_tokens
|
||||||
|
'deepseek/deepseek-reasoner': 64000, # 64K, but may be limited by config.max_model_tokens
|
||||||
'replicate/llama-2-70b-chat:2c1608e18606fad2812020dc541930f2d0495ce32eee50074220b87300bc16e1': 4096,
|
'replicate/llama-2-70b-chat:2c1608e18606fad2812020dc541930f2d0495ce32eee50074220b87300bc16e1': 4096,
|
||||||
'meta-llama/Llama-2-7b-chat-hf': 4096,
|
'meta-llama/Llama-2-7b-chat-hf': 4096,
|
||||||
'vertex_ai/codechat-bison': 6144,
|
'vertex_ai/codechat-bison': 6144,
|
||||||
@ -41,6 +45,7 @@ MAX_TOKENS = {
|
|||||||
'vertex_ai/claude-3-5-sonnet-v2@20241022': 100000,
|
'vertex_ai/claude-3-5-sonnet-v2@20241022': 100000,
|
||||||
'vertex_ai/gemini-1.5-pro': 1048576,
|
'vertex_ai/gemini-1.5-pro': 1048576,
|
||||||
'vertex_ai/gemini-1.5-flash': 1048576,
|
'vertex_ai/gemini-1.5-flash': 1048576,
|
||||||
|
'vertex_ai/gemini-2.0-flash-exp': 1048576,
|
||||||
'vertex_ai/gemma2': 8200,
|
'vertex_ai/gemma2': 8200,
|
||||||
'gemini/gemini-1.5-pro': 1048576,
|
'gemini/gemini-1.5-pro': 1048576,
|
||||||
'gemini/gemini-1.5-flash': 1048576,
|
'gemini/gemini-1.5-flash': 1048576,
|
||||||
@ -78,3 +83,21 @@ MAX_TOKENS = {
|
|||||||
"watsonx/ibm/granite-34b-code-instruct": 8191,
|
"watsonx/ibm/granite-34b-code-instruct": 8191,
|
||||||
"watsonx/mistralai/mistral-large": 32768,
|
"watsonx/mistralai/mistral-large": 32768,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
USER_MESSAGE_ONLY_MODELS = [
|
||||||
|
"deepseek/deepseek-reasoner",
|
||||||
|
"o1-mini",
|
||||||
|
"o1-mini-2024-09-12",
|
||||||
|
"o1-preview"
|
||||||
|
]
|
||||||
|
|
||||||
|
NO_SUPPORT_TEMPERATURE_MODELS = [
|
||||||
|
"deepseek/deepseek-reasoner",
|
||||||
|
"o1-mini",
|
||||||
|
"o1-mini-2024-09-12",
|
||||||
|
"o1",
|
||||||
|
"o1-2024-12-17",
|
||||||
|
"o3-mini",
|
||||||
|
"o3-mini-2025-01-31",
|
||||||
|
"o1-preview"
|
||||||
|
]
|
||||||
|
@ -6,6 +6,7 @@ import requests
|
|||||||
from litellm import acompletion
|
from litellm import acompletion
|
||||||
from tenacity import retry, retry_if_exception_type, stop_after_attempt
|
from tenacity import retry, retry_if_exception_type, stop_after_attempt
|
||||||
|
|
||||||
|
from pr_agent.algo import NO_SUPPORT_TEMPERATURE_MODELS, USER_MESSAGE_ONLY_MODELS
|
||||||
from pr_agent.algo.ai_handlers.base_ai_handler import BaseAiHandler
|
from pr_agent.algo.ai_handlers.base_ai_handler import BaseAiHandler
|
||||||
from pr_agent.algo.utils import get_version
|
from pr_agent.algo.utils import get_version
|
||||||
from pr_agent.config_loader import get_settings
|
from pr_agent.config_loader import get_settings
|
||||||
@ -90,6 +91,16 @@ class LiteLLMAIHandler(BaseAiHandler):
|
|||||||
if get_settings().get("GOOGLE_AI_STUDIO.GEMINI_API_KEY", None):
|
if get_settings().get("GOOGLE_AI_STUDIO.GEMINI_API_KEY", None):
|
||||||
os.environ["GEMINI_API_KEY"] = get_settings().google_ai_studio.gemini_api_key
|
os.environ["GEMINI_API_KEY"] = get_settings().google_ai_studio.gemini_api_key
|
||||||
|
|
||||||
|
# Support deepseek models
|
||||||
|
if get_settings().get("DEEPSEEK.KEY", None):
|
||||||
|
os.environ['DEEPSEEK_API_KEY'] = get_settings().get("DEEPSEEK.KEY")
|
||||||
|
|
||||||
|
# Models that only use user meessage
|
||||||
|
self.user_message_only_models = USER_MESSAGE_ONLY_MODELS
|
||||||
|
|
||||||
|
# Model that doesn't support temperature argument
|
||||||
|
self.no_support_temperature_models = NO_SUPPORT_TEMPERATURE_MODELS
|
||||||
|
|
||||||
def prepare_logs(self, response, system, user, resp, finish_reason):
|
def prepare_logs(self, response, system, user, resp, finish_reason):
|
||||||
response_log = response.dict().copy()
|
response_log = response.dict().copy()
|
||||||
response_log['system'] = system
|
response_log['system'] = system
|
||||||
@ -193,13 +204,11 @@ class LiteLLMAIHandler(BaseAiHandler):
|
|||||||
messages[1]["content"] = [{"type": "text", "text": messages[1]["content"]},
|
messages[1]["content"] = [{"type": "text", "text": messages[1]["content"]},
|
||||||
{"type": "image_url", "image_url": {"url": img_path}}]
|
{"type": "image_url", "image_url": {"url": img_path}}]
|
||||||
|
|
||||||
# Currently, model OpenAI o1 series does not support a separate system and user prompts
|
# Currently, some models do not support a separate system and user prompts
|
||||||
O1_MODEL_PREFIX = 'o1'
|
if model in self.user_message_only_models:
|
||||||
model_type = model.split('/')[-1] if '/' in model else model
|
|
||||||
if model_type.startswith(O1_MODEL_PREFIX):
|
|
||||||
user = f"{system}\n\n\n{user}"
|
user = f"{system}\n\n\n{user}"
|
||||||
system = ""
|
system = ""
|
||||||
get_logger().info(f"Using O1 model, combining system and user prompts")
|
get_logger().info(f"Using model {model}, combining system and user prompts")
|
||||||
messages = [{"role": "user", "content": user}]
|
messages = [{"role": "user", "content": user}]
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"model": model,
|
"model": model,
|
||||||
@ -213,11 +222,14 @@ class LiteLLMAIHandler(BaseAiHandler):
|
|||||||
"model": model,
|
"model": model,
|
||||||
"deployment_id": deployment_id,
|
"deployment_id": deployment_id,
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
"temperature": temperature,
|
|
||||||
"timeout": get_settings().config.ai_timeout,
|
"timeout": get_settings().config.ai_timeout,
|
||||||
"api_base": self.api_base,
|
"api_base": self.api_base,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add temperature only if model supports it
|
||||||
|
if model not in self.no_support_temperature_models:
|
||||||
|
kwargs["temperature"] = temperature
|
||||||
|
|
||||||
if get_settings().litellm.get("enable_callbacks", False):
|
if get_settings().litellm.get("enable_callbacks", False):
|
||||||
kwargs = self.add_litellm_callbacks(kwargs)
|
kwargs = self.add_litellm_callbacks(kwargs)
|
||||||
|
|
||||||
|
@ -205,10 +205,11 @@ def pr_generate_extended_diff(pr_languages: list,
|
|||||||
if not extended_patch:
|
if not extended_patch:
|
||||||
get_logger().warning(f"Failed to extend patch for file: {file.filename}")
|
get_logger().warning(f"Failed to extend patch for file: {file.filename}")
|
||||||
continue
|
continue
|
||||||
full_extended_patch = f"\n\n## {file.filename}\n{extended_patch.rstrip()}\n"
|
|
||||||
|
|
||||||
if add_line_numbers_to_hunks:
|
if add_line_numbers_to_hunks:
|
||||||
full_extended_patch = convert_to_hunks_with_lines_numbers(extended_patch, file)
|
full_extended_patch = convert_to_hunks_with_lines_numbers(extended_patch, file)
|
||||||
|
else:
|
||||||
|
full_extended_patch = f"\n\n## File: '{file.filename.strip()}'\n{extended_patch.rstrip()}\n"
|
||||||
|
|
||||||
# add AI-summary metadata to the patch
|
# add AI-summary metadata to the patch
|
||||||
if file.ai_file_summary and get_settings().get("config.enable_ai_metadata", False):
|
if file.ai_file_summary and get_settings().get("config.enable_ai_metadata", False):
|
||||||
|
@ -316,47 +316,98 @@ def extract_relevant_lines_str(end_line, files, relevant_file, start_line, deden
|
|||||||
|
|
||||||
def ticket_markdown_logic(emoji, markdown_text, value, gfm_supported) -> str:
|
def ticket_markdown_logic(emoji, markdown_text, value, gfm_supported) -> str:
|
||||||
ticket_compliance_str = ""
|
ticket_compliance_str = ""
|
||||||
final_compliance_level = -1
|
compliance_emoji = ''
|
||||||
|
# Track compliance levels across all tickets
|
||||||
|
all_compliance_levels = []
|
||||||
|
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
for v in value:
|
for ticket_analysis in value:
|
||||||
ticket_url = v.get('ticket_url', '').strip()
|
try:
|
||||||
compliance_level = v.get('overall_compliance_level', '').strip()
|
ticket_url = ticket_analysis.get('ticket_url', '').strip()
|
||||||
# add emojis, if 'Fully compliant' ✅, 'Partially compliant' 🔶, or 'Not compliant' ❌
|
|
||||||
if compliance_level.lower() == 'fully compliant':
|
|
||||||
# compliance_level = '✅ Fully compliant'
|
|
||||||
final_compliance_level = 2 if final_compliance_level == -1 else 1
|
|
||||||
elif compliance_level.lower() == 'partially compliant':
|
|
||||||
# compliance_level = '🔶 Partially compliant'
|
|
||||||
final_compliance_level = 1
|
|
||||||
elif compliance_level.lower() == 'not compliant':
|
|
||||||
# compliance_level = '❌ Not compliant'
|
|
||||||
final_compliance_level = 0 if final_compliance_level < 1 else 1
|
|
||||||
|
|
||||||
# explanation = v.get('compliance_analysis', '').strip()
|
|
||||||
explanation = ''
|
explanation = ''
|
||||||
fully_compliant_str = v.get('fully_compliant_requirements', '').strip()
|
ticket_compliance_level = '' # Individual ticket compliance
|
||||||
not_compliant_str = v.get('not_compliant_requirements', '').strip()
|
fully_compliant_str = ticket_analysis.get('fully_compliant_requirements', '').strip()
|
||||||
|
not_compliant_str = ticket_analysis.get('not_compliant_requirements', '').strip()
|
||||||
|
requires_further_human_verification = ticket_analysis.get('requires_further_human_verification',
|
||||||
|
'').strip()
|
||||||
|
|
||||||
|
if not fully_compliant_str and not not_compliant_str:
|
||||||
|
get_logger().debug(f"Ticket compliance has no requirements",
|
||||||
|
artifact={'ticket_url': ticket_url})
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Calculate individual ticket compliance level
|
||||||
if fully_compliant_str:
|
if fully_compliant_str:
|
||||||
explanation += f"Fully compliant requirements:\n{fully_compliant_str}\n\n"
|
|
||||||
if not_compliant_str:
|
if not_compliant_str:
|
||||||
explanation += f"Not compliant requirements:\n{not_compliant_str}\n\n"
|
ticket_compliance_level = 'Partially compliant'
|
||||||
|
|
||||||
ticket_compliance_str += f"\n\n**[{ticket_url.split('/')[-1]}]({ticket_url}) - {compliance_level}**\n\n{explanation}\n\n"
|
|
||||||
if final_compliance_level == 2:
|
|
||||||
compliance_level = '✅'
|
|
||||||
elif final_compliance_level == 1:
|
|
||||||
compliance_level = '🔶'
|
|
||||||
else:
|
else:
|
||||||
compliance_level = '❌'
|
if not requires_further_human_verification:
|
||||||
|
ticket_compliance_level = 'Fully compliant'
|
||||||
|
else:
|
||||||
|
ticket_compliance_level = 'PR Code Verified'
|
||||||
|
elif not_compliant_str:
|
||||||
|
ticket_compliance_level = 'Not compliant'
|
||||||
|
|
||||||
|
# Store the compliance level for aggregation
|
||||||
|
if ticket_compliance_level:
|
||||||
|
all_compliance_levels.append(ticket_compliance_level)
|
||||||
|
|
||||||
|
# build compliance string
|
||||||
|
if fully_compliant_str:
|
||||||
|
explanation += f"Compliant requirements:\n\n{fully_compliant_str}\n\n"
|
||||||
|
if not_compliant_str:
|
||||||
|
explanation += f"Non-compliant requirements:\n\n{not_compliant_str}\n\n"
|
||||||
|
if requires_further_human_verification:
|
||||||
|
explanation += f"Requires further human verification:\n\n{requires_further_human_verification}\n\n"
|
||||||
|
ticket_compliance_str += f"\n\n**[{ticket_url.split('/')[-1]}]({ticket_url}) - {ticket_compliance_level}**\n\n{explanation}\n\n"
|
||||||
|
|
||||||
|
# for debugging
|
||||||
|
if requires_further_human_verification:
|
||||||
|
get_logger().debug(f"Ticket compliance requires further human verification",
|
||||||
|
artifact={'ticket_url': ticket_url,
|
||||||
|
'requires_further_human_verification': requires_further_human_verification,
|
||||||
|
'compliance_level': ticket_compliance_level})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
get_logger().exception(f"Failed to process ticket compliance: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Calculate overall compliance level and emoji
|
||||||
|
if all_compliance_levels:
|
||||||
|
if all(level == 'Fully compliant' for level in all_compliance_levels):
|
||||||
|
compliance_level = 'Fully compliant'
|
||||||
|
compliance_emoji = '✅'
|
||||||
|
elif all(level == 'PR Code Verified' for level in all_compliance_levels):
|
||||||
|
compliance_level = 'PR Code Verified'
|
||||||
|
compliance_emoji = '✅'
|
||||||
|
elif any(level == 'Not compliant' for level in all_compliance_levels):
|
||||||
|
# If there's a mix of compliant and non-compliant tickets
|
||||||
|
if any(level in ['Fully compliant', 'PR Code Verified'] for level in all_compliance_levels):
|
||||||
|
compliance_level = 'Partially compliant'
|
||||||
|
compliance_emoji = '🔶'
|
||||||
|
else:
|
||||||
|
compliance_level = 'Not compliant'
|
||||||
|
compliance_emoji = '❌'
|
||||||
|
elif any(level == 'Partially compliant' for level in all_compliance_levels):
|
||||||
|
compliance_level = 'Partially compliant'
|
||||||
|
compliance_emoji = '🔶'
|
||||||
|
else:
|
||||||
|
compliance_level = 'PR Code Verified'
|
||||||
|
compliance_emoji = '✅'
|
||||||
|
|
||||||
|
# Set extra statistics outside the ticket loop
|
||||||
|
get_settings().set('config.extra_statistics', {'compliance_level': compliance_level})
|
||||||
|
|
||||||
|
# editing table row for ticket compliance analysis
|
||||||
if gfm_supported:
|
if gfm_supported:
|
||||||
markdown_text += f"<tr><td>\n\n"
|
markdown_text += f"<tr><td>\n\n"
|
||||||
markdown_text += f"**{emoji} Ticket compliance analysis {compliance_level}**\n\n"
|
markdown_text += f"**{emoji} Ticket compliance analysis {compliance_emoji}**\n\n"
|
||||||
markdown_text += ticket_compliance_str
|
markdown_text += ticket_compliance_str
|
||||||
markdown_text += f"</td></tr>\n"
|
markdown_text += f"</td></tr>\n"
|
||||||
else:
|
else:
|
||||||
markdown_text += f"### {emoji} Ticket compliance analysis {compliance_level}\n\n"
|
markdown_text += f"### {emoji} Ticket compliance analysis {compliance_emoji}\n\n"
|
||||||
markdown_text += ticket_compliance_str + "\n\n"
|
markdown_text += ticket_compliance_str + "\n\n"
|
||||||
|
|
||||||
return markdown_text
|
return markdown_text
|
||||||
|
|
||||||
|
|
||||||
@ -588,6 +639,8 @@ def load_large_diff(filename, new_file_content_str: str, original_file_content_s
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
original_file_content_str = (original_file_content_str or "").rstrip() + "\n"
|
||||||
|
new_file_content_str = (new_file_content_str or "").rstrip() + "\n"
|
||||||
diff = difflib.unified_diff(original_file_content_str.splitlines(keepends=True),
|
diff = difflib.unified_diff(original_file_content_str.splitlines(keepends=True),
|
||||||
new_file_content_str.splitlines(keepends=True))
|
new_file_content_str.splitlines(keepends=True))
|
||||||
if get_settings().config.verbosity_level >= 2 and show_warning:
|
if get_settings().config.verbosity_level >= 2 and show_warning:
|
||||||
@ -682,7 +735,7 @@ def try_fix_yaml(response_text: str,
|
|||||||
get_logger().info(f"Successfully parsed AI prediction after adding |-\n")
|
get_logger().info(f"Successfully parsed AI prediction after adding |-\n")
|
||||||
return data
|
return data
|
||||||
except:
|
except:
|
||||||
get_logger().info(f"Failed to parse AI prediction after adding |-\n")
|
pass
|
||||||
|
|
||||||
# second fallback - try to extract only range from first ```yaml to ````
|
# second fallback - try to extract only range from first ```yaml to ````
|
||||||
snippet_pattern = r'```(yaml)?[\s\S]*?```'
|
snippet_pattern = r'```(yaml)?[\s\S]*?```'
|
||||||
@ -726,9 +779,18 @@ def try_fix_yaml(response_text: str,
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# fifth fallback - try to remove leading '+' (sometimes added by AI for 'existing code' and 'improved code')
|
||||||
|
response_text_lines_copy = response_text_lines.copy()
|
||||||
|
for i in range(0, len(response_text_lines_copy)):
|
||||||
|
response_text_lines_copy[i] = ' ' + response_text_lines_copy[i][1:]
|
||||||
|
try:
|
||||||
|
data = yaml.safe_load('\n'.join(response_text_lines_copy))
|
||||||
|
get_logger().info(f"Successfully parsed AI prediction after removing leading '+'")
|
||||||
|
return data
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# fifth fallback - try to remove last lines
|
# sixth fallback - try to remove last lines
|
||||||
data = {}
|
|
||||||
for i in range(1, len(response_text_lines)):
|
for i in range(1, len(response_text_lines)):
|
||||||
response_text_lines_tmp = '\n'.join(response_text_lines[:-i])
|
response_text_lines_tmp = '\n'.join(response_text_lines[:-i])
|
||||||
try:
|
try:
|
||||||
|
@ -12,7 +12,6 @@ global_settings = Dynaconf(
|
|||||||
envvar_prefix=False,
|
envvar_prefix=False,
|
||||||
merge_enabled=True,
|
merge_enabled=True,
|
||||||
settings_files=[join(current_dir, f) for f in [
|
settings_files=[join(current_dir, f) for f in [
|
||||||
"settings/.secrets.toml",
|
|
||||||
"settings/configuration.toml",
|
"settings/configuration.toml",
|
||||||
"settings/ignore.toml",
|
"settings/ignore.toml",
|
||||||
"settings/language_extensions.toml",
|
"settings/language_extensions.toml",
|
||||||
@ -29,6 +28,7 @@ global_settings = Dynaconf(
|
|||||||
"settings/pr_add_docs.toml",
|
"settings/pr_add_docs.toml",
|
||||||
"settings/custom_labels.toml",
|
"settings/custom_labels.toml",
|
||||||
"settings/pr_help_prompts.toml",
|
"settings/pr_help_prompts.toml",
|
||||||
|
"settings/.secrets.toml",
|
||||||
"settings_prod/.secrets.toml",
|
"settings_prod/.secrets.toml",
|
||||||
]]
|
]]
|
||||||
)
|
)
|
||||||
|
@ -326,13 +326,13 @@ class AzureDevopsProvider(GitProvider):
|
|||||||
edit_type = EDIT_TYPE.ADDED
|
edit_type = EDIT_TYPE.ADDED
|
||||||
elif diff_types[file] == "delete":
|
elif diff_types[file] == "delete":
|
||||||
edit_type = EDIT_TYPE.DELETED
|
edit_type = EDIT_TYPE.DELETED
|
||||||
elif diff_types[file] == "rename":
|
elif "rename" in diff_types[file]: # diff_type can be `rename` | `edit, rename`
|
||||||
edit_type = EDIT_TYPE.RENAMED
|
edit_type = EDIT_TYPE.RENAMED
|
||||||
|
|
||||||
version = GitVersionDescriptor(
|
version = GitVersionDescriptor(
|
||||||
version=base_sha.commit_id, version_type="commit"
|
version=base_sha.commit_id, version_type="commit"
|
||||||
)
|
)
|
||||||
if edit_type == EDIT_TYPE.ADDED:
|
if edit_type == EDIT_TYPE.ADDED or edit_type == EDIT_TYPE.RENAMED:
|
||||||
original_file_content_str = ""
|
original_file_content_str = ""
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -234,7 +234,7 @@ class BitbucketServerProvider(GitProvider):
|
|||||||
new_file_content_str = self.get_file(file_path, head_sha)
|
new_file_content_str = self.get_file(file_path, head_sha)
|
||||||
new_file_content_str = decode_if_bytes(new_file_content_str)
|
new_file_content_str = decode_if_bytes(new_file_content_str)
|
||||||
|
|
||||||
patch = load_large_diff(file_path, new_file_content_str, original_file_content_str)
|
patch = load_large_diff(file_path, new_file_content_str, original_file_content_str, show_warning=False)
|
||||||
|
|
||||||
diff_files.append(
|
diff_files.append(
|
||||||
FilePatchInfo(
|
FilePatchInfo(
|
||||||
@ -402,10 +402,21 @@ class BitbucketServerProvider(GitProvider):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
projects_index = path_parts.index("projects")
|
projects_index = path_parts.index("projects")
|
||||||
except ValueError as e:
|
except ValueError:
|
||||||
|
projects_index = -1
|
||||||
|
|
||||||
|
try:
|
||||||
|
users_index = path_parts.index("users")
|
||||||
|
except ValueError:
|
||||||
|
users_index = -1
|
||||||
|
|
||||||
|
if projects_index == -1 and users_index == -1:
|
||||||
raise ValueError(f"The provided URL '{pr_url}' does not appear to be a Bitbucket PR URL")
|
raise ValueError(f"The provided URL '{pr_url}' does not appear to be a Bitbucket PR URL")
|
||||||
|
|
||||||
|
if projects_index != -1:
|
||||||
path_parts = path_parts[projects_index:]
|
path_parts = path_parts[projects_index:]
|
||||||
|
else:
|
||||||
|
path_parts = path_parts[users_index:]
|
||||||
|
|
||||||
if len(path_parts) < 6 or path_parts[2] != "repos" or path_parts[4] != "pull-requests":
|
if len(path_parts) < 6 or path_parts[2] != "repos" or path_parts[4] != "pull-requests":
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@ -413,6 +424,8 @@ class BitbucketServerProvider(GitProvider):
|
|||||||
)
|
)
|
||||||
|
|
||||||
workspace_slug = path_parts[1]
|
workspace_slug = path_parts[1]
|
||||||
|
if users_index != -1:
|
||||||
|
workspace_slug = f"~{workspace_slug}"
|
||||||
repo_slug = path_parts[3]
|
repo_slug = path_parts[3]
|
||||||
try:
|
try:
|
||||||
pr_number = int(path_parts[5])
|
pr_number = int(path_parts[5])
|
||||||
|
@ -9,7 +9,7 @@ from datetime import datetime
|
|||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from github import AppAuthentication, Auth, Github
|
from github import AppAuthentication, Auth, Github, GithubException
|
||||||
from retry import retry
|
from retry import retry
|
||||||
from starlette_context import context
|
from starlette_context import context
|
||||||
|
|
||||||
@ -475,8 +475,17 @@ class GithubProvider(GitProvider):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def edit_comment(self, comment, body: str):
|
def edit_comment(self, comment, body: str):
|
||||||
|
try:
|
||||||
body = self.limit_output_characters(body, self.max_comment_chars)
|
body = self.limit_output_characters(body, self.max_comment_chars)
|
||||||
comment.edit(body=body)
|
comment.edit(body=body)
|
||||||
|
except GithubException as e:
|
||||||
|
if hasattr(e, "status") and e.status == 403:
|
||||||
|
# Log as warning for permission-related issues (usually due to polling)
|
||||||
|
get_logger().warning(
|
||||||
|
"Failed to edit github comment due to permission restrictions",
|
||||||
|
artifact={"error": e})
|
||||||
|
else:
|
||||||
|
get_logger().exception(f"Failed to edit github comment", artifact={"error": e})
|
||||||
|
|
||||||
def edit_comment_from_comment_id(self, comment_id: int, body: str):
|
def edit_comment_from_comment_id(self, comment_id: int, body: str):
|
||||||
try:
|
try:
|
||||||
|
@ -141,6 +141,18 @@ class LocalGitProvider(GitProvider):
|
|||||||
def remove_comment(self, comment):
|
def remove_comment(self, comment):
|
||||||
pass # Not applicable to the local git provider, but required by the interface
|
pass # Not applicable to the local git provider, but required by the interface
|
||||||
|
|
||||||
|
def add_eyes_reaction(self, comment):
|
||||||
|
pass # Not applicable to the local git provider, but required by the interface
|
||||||
|
|
||||||
|
def get_commit_messages(self):
|
||||||
|
pass # Not applicable to the local git provider, but required by the interface
|
||||||
|
|
||||||
|
def get_repo_settings(self):
|
||||||
|
pass # Not applicable to the local git provider, but required by the interface
|
||||||
|
|
||||||
|
def remove_reaction(self, comment):
|
||||||
|
pass # Not applicable to the local git provider, but required by the interface
|
||||||
|
|
||||||
def get_languages(self):
|
def get_languages(self):
|
||||||
"""
|
"""
|
||||||
Calculate percentage of languages in repository. Used for hunk prioritisation.
|
Calculate percentage of languages in repository. Used for hunk prioritisation.
|
||||||
|
@ -24,10 +24,6 @@ from pr_agent.identity_providers import get_identity_provider
|
|||||||
from pr_agent.identity_providers.identity_provider import Eligibility
|
from pr_agent.identity_providers.identity_provider import Eligibility
|
||||||
from pr_agent.log import LoggingFormat, get_logger, setup_logger
|
from pr_agent.log import LoggingFormat, get_logger, setup_logger
|
||||||
from pr_agent.secret_providers import get_secret_provider
|
from pr_agent.secret_providers import get_secret_provider
|
||||||
from pr_agent.servers.github_action_runner import get_setting_or_env, is_true
|
|
||||||
from pr_agent.tools.pr_code_suggestions import PRCodeSuggestions
|
|
||||||
from pr_agent.tools.pr_description import PRDescription
|
|
||||||
from pr_agent.tools.pr_reviewer import PRReviewer
|
|
||||||
|
|
||||||
setup_logger(fmt=LoggingFormat.JSON, level="DEBUG")
|
setup_logger(fmt=LoggingFormat.JSON, level="DEBUG")
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
@ -75,6 +71,18 @@ async def handle_manifest(request: Request, response: Response):
|
|||||||
return JSONResponse(manifest_obj)
|
return JSONResponse(manifest_obj)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_username(data):
|
||||||
|
actor = data.get("data", {}).get("actor", {})
|
||||||
|
if actor:
|
||||||
|
if "username" in actor:
|
||||||
|
return actor["username"]
|
||||||
|
elif "display_name" in actor:
|
||||||
|
return actor["display_name"]
|
||||||
|
elif "nickname" in actor:
|
||||||
|
return actor["nickname"]
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
async def _perform_commands_bitbucket(commands_conf: str, agent: PRAgent, api_url: str, log_context: dict, data: dict):
|
async def _perform_commands_bitbucket(commands_conf: str, agent: PRAgent, api_url: str, log_context: dict, data: dict):
|
||||||
apply_repo_settings(api_url)
|
apply_repo_settings(api_url)
|
||||||
if commands_conf == "pr_commands" and get_settings().config.disable_auto_feedback: # auto commands for PR, and auto feedback is disabled
|
if commands_conf == "pr_commands" and get_settings().config.disable_auto_feedback: # auto commands for PR, and auto feedback is disabled
|
||||||
@ -118,6 +126,14 @@ def should_process_pr_logic(data) -> bool:
|
|||||||
title = pr_data.get("title", "")
|
title = pr_data.get("title", "")
|
||||||
source_branch = pr_data.get("source", {}).get("branch", {}).get("name", "")
|
source_branch = pr_data.get("source", {}).get("branch", {}).get("name", "")
|
||||||
target_branch = pr_data.get("destination", {}).get("branch", {}).get("name", "")
|
target_branch = pr_data.get("destination", {}).get("branch", {}).get("name", "")
|
||||||
|
sender = _get_username(data)
|
||||||
|
|
||||||
|
# logic to ignore PRs from specific users
|
||||||
|
ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", [])
|
||||||
|
if ignore_pr_users and sender:
|
||||||
|
if sender in ignore_pr_users:
|
||||||
|
get_logger().info(f"Ignoring PR from user '{sender}' due to 'config.ignore_pr_authors' setting")
|
||||||
|
return False
|
||||||
|
|
||||||
# logic to ignore PRs with specific titles
|
# logic to ignore PRs with specific titles
|
||||||
if title:
|
if title:
|
||||||
@ -167,16 +183,7 @@ async def handle_github_webhooks(background_tasks: BackgroundTasks, request: Req
|
|||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
# Get the username of the sender
|
# Get the username of the sender
|
||||||
actor = data.get("data", {}).get("actor", {})
|
log_context["sender"] = _get_username(data)
|
||||||
if actor:
|
|
||||||
try:
|
|
||||||
username = actor["username"]
|
|
||||||
except KeyError:
|
|
||||||
try:
|
|
||||||
username = actor["display_name"]
|
|
||||||
except KeyError:
|
|
||||||
username = actor["nickname"]
|
|
||||||
log_context["sender"] = username
|
|
||||||
|
|
||||||
sender_id = data.get("data", {}).get("actor", {}).get("account_id", "")
|
sender_id = data.get("data", {}).get("actor", {}).get("account_id", "")
|
||||||
log_context["sender_id"] = sender_id
|
log_context["sender_id"] = sender_id
|
||||||
|
@ -81,7 +81,7 @@ async def run_action():
|
|||||||
get_logger().info(f"github action: failed to apply repo settings: {e}")
|
get_logger().info(f"github action: failed to apply repo settings: {e}")
|
||||||
|
|
||||||
# Handle pull request opened event
|
# Handle pull request opened event
|
||||||
if GITHUB_EVENT_NAME == "pull_request":
|
if GITHUB_EVENT_NAME == "pull_request" or GITHUB_EVENT_NAME == "pull_request_target":
|
||||||
action = event_payload.get("action")
|
action = event_payload.get("action")
|
||||||
|
|
||||||
# Retrieve the list of actions from the configuration
|
# Retrieve the list of actions from the configuration
|
||||||
|
@ -257,6 +257,14 @@ def should_process_pr_logic(body) -> bool:
|
|||||||
pr_labels = pull_request.get("labels", [])
|
pr_labels = pull_request.get("labels", [])
|
||||||
source_branch = pull_request.get("head", {}).get("ref", "")
|
source_branch = pull_request.get("head", {}).get("ref", "")
|
||||||
target_branch = pull_request.get("base", {}).get("ref", "")
|
target_branch = pull_request.get("base", {}).get("ref", "")
|
||||||
|
sender = body.get("sender", {}).get("login")
|
||||||
|
|
||||||
|
# logic to ignore PRs from specific users
|
||||||
|
ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", [])
|
||||||
|
if ignore_pr_users and sender:
|
||||||
|
if sender in ignore_pr_users:
|
||||||
|
get_logger().info(f"Ignoring PR from user '{sender}' due to 'config.ignore_pr_authors' setting")
|
||||||
|
return False
|
||||||
|
|
||||||
# logic to ignore PRs with specific titles
|
# logic to ignore PRs with specific titles
|
||||||
if title:
|
if title:
|
||||||
@ -276,6 +284,7 @@ def should_process_pr_logic(body) -> bool:
|
|||||||
get_logger().info(f"Ignoring PR with labels '{labels_str}' due to config.ignore_pr_labels settings")
|
get_logger().info(f"Ignoring PR with labels '{labels_str}' due to config.ignore_pr_labels settings")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# logic to ignore PRs with specific source or target branches
|
||||||
ignore_pr_source_branches = get_settings().get("CONFIG.IGNORE_PR_SOURCE_BRANCHES", [])
|
ignore_pr_source_branches = get_settings().get("CONFIG.IGNORE_PR_SOURCE_BRANCHES", [])
|
||||||
ignore_pr_target_branches = get_settings().get("CONFIG.IGNORE_PR_TARGET_BRANCHES", [])
|
ignore_pr_target_branches = get_settings().get("CONFIG.IGNORE_PR_TARGET_BRANCHES", [])
|
||||||
if pull_request and (ignore_pr_source_branches or ignore_pr_target_branches):
|
if pull_request and (ignore_pr_source_branches or ignore_pr_target_branches):
|
||||||
|
@ -130,12 +130,14 @@ async def is_valid_notification(notification, headers, handled_ids, session, use
|
|||||||
artifact={"comment": comment_body})
|
artifact={"comment": comment_body})
|
||||||
return True, handled_ids, comment, comment_body, pr_url, user_tag
|
return True, handled_ids, comment, comment_body, pr_url, user_tag
|
||||||
|
|
||||||
get_logger().error(f"Failed to fetch comments for PR: {pr_url}")
|
get_logger().warning(f"Failed to fetch comments for PR: {pr_url}",
|
||||||
|
artifact={"comments": comments})
|
||||||
return False, handled_ids
|
return False, handled_ids
|
||||||
|
|
||||||
return False, handled_ids
|
return False, handled_ids
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
get_logger().error(f"Error processing notification: {e}", artifact={"traceback": traceback.format_exc()})
|
get_logger().exception(f"Error processing polling notification",
|
||||||
|
artifact={"notification": notification, "error": e})
|
||||||
return False, handled_ids
|
return False, handled_ids
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,6 +100,14 @@ def should_process_pr_logic(data) -> bool:
|
|||||||
if not data.get('object_attributes', {}):
|
if not data.get('object_attributes', {}):
|
||||||
return False
|
return False
|
||||||
title = data['object_attributes'].get('title')
|
title = data['object_attributes'].get('title')
|
||||||
|
sender = data.get("user", {}).get("username", "")
|
||||||
|
|
||||||
|
# logic to ignore PRs from specific users
|
||||||
|
ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", [])
|
||||||
|
if ignore_pr_users and sender:
|
||||||
|
if sender in ignore_pr_users:
|
||||||
|
get_logger().info(f"Ignoring PR from user '{sender}' due to 'config.ignore_pr_authors' settings")
|
||||||
|
return False
|
||||||
|
|
||||||
# logic to ignore MRs for titles, labels and source, target branches.
|
# logic to ignore MRs for titles, labels and source, target branches.
|
||||||
ignore_mr_title = get_settings().get("CONFIG.IGNORE_PR_TITLE", [])
|
ignore_mr_title = get_settings().get("CONFIG.IGNORE_PR_TITLE", [])
|
||||||
|
@ -91,3 +91,6 @@ pat = ""
|
|||||||
# Optional, uncomment if you want to use Azure devops webhooks. Value assinged when you create the webhook
|
# Optional, uncomment if you want to use Azure devops webhooks. Value assinged when you create the webhook
|
||||||
# webhook_username = "<basic auth user>"
|
# webhook_username = "<basic auth user>"
|
||||||
# webhook_password = "<basic auth password>"
|
# webhook_password = "<basic auth password>"
|
||||||
|
|
||||||
|
[deepseek]
|
||||||
|
key = ""
|
||||||
|
@ -34,6 +34,7 @@ ai_disclaimer_title="" # Pro feature, title for a collapsible disclaimer to AI
|
|||||||
ai_disclaimer="" # Pro feature, full text for the AI disclaimer
|
ai_disclaimer="" # Pro feature, full text for the AI disclaimer
|
||||||
output_relevant_configurations=false
|
output_relevant_configurations=false
|
||||||
large_patch_policy = "clip" # "clip", "skip"
|
large_patch_policy = "clip" # "clip", "skip"
|
||||||
|
duplicate_prompt_examples = false
|
||||||
# seed
|
# seed
|
||||||
seed=-1 # set positive value to fix the seed (and ensure temperature=0)
|
seed=-1 # set positive value to fix the seed (and ensure temperature=0)
|
||||||
temperature=0.2
|
temperature=0.2
|
||||||
@ -42,6 +43,7 @@ ignore_pr_title = ["^\\[Auto\\]", "^Auto"] # a list of regular expressions to ma
|
|||||||
ignore_pr_target_branches = [] # a list of regular expressions of target branches to ignore from PR agent when an PR is created
|
ignore_pr_target_branches = [] # a list of regular expressions of target branches to ignore from PR agent when an PR is created
|
||||||
ignore_pr_source_branches = [] # a list of regular expressions of source branches to ignore from PR agent when an PR is created
|
ignore_pr_source_branches = [] # a list of regular expressions of source branches to ignore from PR agent when an PR is created
|
||||||
ignore_pr_labels = [] # labels to ignore from PR agent when an PR is created
|
ignore_pr_labels = [] # labels to ignore from PR agent when an PR is created
|
||||||
|
ignore_pr_authors = [] # authors to ignore from PR agent when an PR is created
|
||||||
#
|
#
|
||||||
is_auto_command = false # will be auto-set to true if the command is triggered by an automation
|
is_auto_command = false # will be auto-set to true if the command is triggered by an automation
|
||||||
enable_ai_metadata = false # will enable adding ai metadata
|
enable_ai_metadata = false # will enable adding ai metadata
|
||||||
@ -69,7 +71,6 @@ enable_intro_text=true
|
|||||||
enable_help_text=false # Determines whether to include help text in the PR review. Enabled by default.
|
enable_help_text=false # Determines whether to include help text in the PR review. Enabled by default.
|
||||||
# auto approval
|
# auto approval
|
||||||
enable_auto_approval=false
|
enable_auto_approval=false
|
||||||
maximal_review_effort=5
|
|
||||||
|
|
||||||
|
|
||||||
[pr_description] # /describe #
|
[pr_description] # /describe #
|
||||||
@ -120,6 +121,9 @@ max_history_len=4
|
|||||||
apply_suggestions_checkbox=true
|
apply_suggestions_checkbox=true
|
||||||
# suggestions scoring
|
# suggestions scoring
|
||||||
suggestions_score_threshold=0 # [0-10]| 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
|
||||||
|
new_score_mechanism=true
|
||||||
|
new_score_mechanism_th_high=9
|
||||||
|
new_score_mechanism_th_medium=7
|
||||||
# params for '/improve --extended' mode
|
# params for '/improve --extended' mode
|
||||||
auto_extended_mode=true
|
auto_extended_mode=true
|
||||||
num_code_suggestions_per_chunk=4
|
num_code_suggestions_per_chunk=4
|
||||||
@ -306,7 +310,16 @@ number_of_results = 5
|
|||||||
|
|
||||||
[lancedb]
|
[lancedb]
|
||||||
uri = "./lancedb"
|
uri = "./lancedb"
|
||||||
|
|
||||||
[best_practices]
|
[best_practices]
|
||||||
content = ""
|
content = ""
|
||||||
|
organization_name = ""
|
||||||
max_lines_allowed = 800
|
max_lines_allowed = 800
|
||||||
enable_global_best_practices = false
|
enable_global_best_practices = false
|
||||||
|
|
||||||
|
[auto_best_practices]
|
||||||
|
enable_auto_best_practices = true # public - general flag to disable all auto best practices usage
|
||||||
|
utilize_auto_best_practices = true # public - disable usage of auto best practices in the 'improve' tool
|
||||||
|
extra_instructions = "" # public - extra instructions to the auto best practices generation prompt
|
||||||
|
content = ""
|
||||||
|
max_patterns = 5 # max number of patterns to be detected
|
||||||
|
@ -17,30 +17,36 @@ The PR code diff will be in the following structured format:
|
|||||||
|
|
||||||
@@ ... @@ def func1():
|
@@ ... @@ def func1():
|
||||||
__new hunk__
|
__new hunk__
|
||||||
unchanged code line0 in the PR
|
unchanged code line0
|
||||||
unchanged code line1 in the PR
|
unchanged code line1
|
||||||
+new code line2 added in the PR
|
+new code line2 added
|
||||||
unchanged code line3 in the PR
|
unchanged code line3
|
||||||
__old hunk__
|
__old hunk__
|
||||||
unchanged code line0
|
unchanged code line0
|
||||||
unchanged code line1
|
unchanged code line1
|
||||||
-old code line2 removed in the PR
|
-old code line2 removed
|
||||||
unchanged code line3
|
unchanged code line3
|
||||||
|
|
||||||
@@ ... @@ def func2():
|
@@ ... @@ def func2():
|
||||||
__new hunk__
|
__new hunk__
|
||||||
unchanged code line4
|
unchanged code line4
|
||||||
+new code line5 removed in the PR
|
+new code line5 added
|
||||||
unchanged code line6
|
unchanged code line6
|
||||||
|
|
||||||
## File: 'src/file2.py'
|
## File: 'src/file2.py'
|
||||||
...
|
...
|
||||||
======
|
======
|
||||||
|
|
||||||
- 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 removed in a specific chunk, the __old hunk__ section will be omitted.
|
Important notes about the structured diff format above:
|
||||||
- Code lines are prefixed with symbols: '+' for new code added in the PR, '-' for code removed, and ' ' for unchanged code.
|
1. Each PR code chunk is decoupled into separate '__new hunk__' and '__old hunk__' sections:
|
||||||
|
- The '__new hunk__' section shows the code chunk AFTER the PR changes.
|
||||||
|
- The '__old hunk__' section shows the code chunk BEFORE the PR changes. If no code was removed from the chunk, the '__old hunk__' section will be omitted.
|
||||||
|
2. The diff uses line prefixes to show changes:
|
||||||
|
'+' → new line code added (will appear only in '__new hunk__')
|
||||||
|
'-' → line code removed (will appear only in '__old hunk__')
|
||||||
|
' ' → unchanged context lines (will appear in both sections)
|
||||||
{%- if is_ai_metadata %}
|
{%- 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 complete.
|
3. 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 %}
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
@ -50,16 +56,17 @@ Specific guidelines for generating code suggestions:
|
|||||||
{%- else %}
|
{%- else %}
|
||||||
- Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions. Return less suggestions if no pertinent ones are applicable.
|
- Provide up to {{ num_code_suggestions }} distinct and insightful code suggestions. Return less suggestions if no pertinent ones are applicable.
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
- Focus solely on enhancing new code introduced in the PR, identified by '+' prefixes in '__new hunk__' sections.
|
- DO NOT suggest implementing changes that are already present in the '+' lines compared to the '-' lines.
|
||||||
|
- Focus your suggestions ONLY on new code introduced in the PR ('+' lines in '__new hunk__' sections).
|
||||||
{%- if not focus_only_on_problems %}
|
{%- if not focus_only_on_problems %}
|
||||||
- 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.
|
- 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.
|
||||||
|
- Don't suggest to add docstring, type hints, or comments, to remove unused imports, or to use more specific exception types.
|
||||||
{%- else %}
|
{%- else %}
|
||||||
- Only give suggestions that address critical problems and bugs in the PR code. If no relevant suggestions are applicable, return an empty list.
|
- Only give suggestions that address critical problems and bugs in the PR code. If no relevant suggestions are applicable, return an empty list.
|
||||||
|
- Do not suggest to change packages version, add missing import statement, or declare undefined variable.
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
- Don't suggest to add docstring, type hints, or comments, to remove unused imports, or to use more specific exception types.
|
- When mentioning code elements (variables, names, or files) in your response, surround them with backticks (`). For example: "verify that `user_id` is..."
|
||||||
- When referencing variables or names from the code, enclose them in backticks (`). Example: "ensure that `variable_name` is..."
|
- Note that you only see changed code segments (diff hunks in a PR), not the entire codebase. Avoid suggestions that might duplicate existing functionality or questioning code elements (like variables declarations or import statements) that may be defined elsewhere in the codebase.
|
||||||
- Be mindful you are viewing a partial PR code diff, not the full codebase. Avoid suggestions that might conflict with unseen code or alerting variables not declared in the visible scope, as the context is incomplete.
|
|
||||||
|
|
||||||
|
|
||||||
{%- if extra_instructions %}
|
{%- if extra_instructions %}
|
||||||
|
|
||||||
@ -77,13 +84,13 @@ class CodeSuggestion(BaseModel):
|
|||||||
relevant_file: str = Field(description="Full path of the relevant file")
|
relevant_file: str = Field(description="Full path of the relevant file")
|
||||||
language: str = Field(description="Programming language used by 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")
|
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. Use ellipsis (...) for brevity if needed. This snippet should represent the specific PR code targeted for improvement.")
|
existing_code: str = Field(description="A short code snippet, from a '__new hunk__' section after the PR changes, that the suggestion aims to enhance or fix. Include only complete code lines. 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.")
|
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.")
|
one_sentence_summary: str = Field(description="A concise, single-sentence overview (up to 6 words) of the suggested improvement. Focus on the 'what'. Be general, and avoid method or variable names.")
|
||||||
{%- if not focus_only_on_problems %}
|
{%- if not focus_only_on_problems %}
|
||||||
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', 'typo'. Other relevant labels are also acceptable.")
|
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', 'typo'. Other relevant labels are also acceptable.")
|
||||||
{%- else %}
|
{%- else %}
|
||||||
label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'critical bug', 'general'. The 'general' section should be used for suggestions that address a major issue, but are necessarily on a critical level.")
|
label: str = Field(description="A single, descriptive label that best characterizes the suggestion type. Possible labels include 'security', 'critical bug', 'general'. The 'general' section should be used for suggestions that address a major issue, but are not necessarily on a critical level.")
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
@ -111,7 +118,6 @@ code_suggestions:
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Each YAML output MUST be after a newline, indented, with block scalar indicator ('|').
|
Each YAML output MUST be after a newline, indented, with block scalar indicator ('|').
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -119,12 +125,40 @@ user="""--PR Info--
|
|||||||
|
|
||||||
Title: '{{title}}'
|
Title: '{{title}}'
|
||||||
|
|
||||||
|
{%- if date %}
|
||||||
|
|
||||||
|
Today's Date: {{date}}
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
The PR Diff:
|
The PR Diff:
|
||||||
======
|
======
|
||||||
{{ diff_no_line_numbers|trim }}
|
{{ diff_no_line_numbers|trim }}
|
||||||
======
|
======
|
||||||
|
|
||||||
|
{%- if duplicate_prompt_examples %}
|
||||||
|
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```yaml
|
||||||
|
code_suggestions:
|
||||||
|
- relevant_file: |
|
||||||
|
src/file1.py
|
||||||
|
language: |
|
||||||
|
python
|
||||||
|
suggestion_content: |
|
||||||
|
...
|
||||||
|
existing_code: |
|
||||||
|
...
|
||||||
|
improved_code: |
|
||||||
|
...
|
||||||
|
one_sentence_summary: |
|
||||||
|
...
|
||||||
|
label: |
|
||||||
|
...
|
||||||
|
```
|
||||||
|
(replace '...' with actual content)
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
Response (should be a valid YAML, and nothing else):
|
Response (should be a valid YAML, and nothing else):
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -49,14 +49,14 @@ The PR code diff will be presented in the following structured format:
|
|||||||
|
|
||||||
@@ ... @@ def func1():
|
@@ ... @@ def func1():
|
||||||
__new hunk__
|
__new hunk__
|
||||||
11 unchanged code line0 in the PR
|
11 unchanged code line0
|
||||||
12 unchanged code line1 in the PR
|
12 unchanged code line1
|
||||||
13 +new code line2 added in the PR
|
13 +new code line2 added
|
||||||
14 unchanged code line3 in the PR
|
14 unchanged code line3
|
||||||
__old hunk__
|
__old hunk__
|
||||||
unchanged code line0
|
unchanged code line0
|
||||||
unchanged code line1
|
unchanged code line1
|
||||||
-old code line2 removed in the PR
|
-old code line2 removed
|
||||||
unchanged code line3
|
unchanged code line3
|
||||||
|
|
||||||
@@ ... @@ def func2():
|
@@ ... @@ def func2():
|
||||||
@ -122,6 +122,25 @@ Below are {{ num_code_suggestions }} AI-generated code suggestions for enhancing
|
|||||||
======
|
======
|
||||||
|
|
||||||
|
|
||||||
|
{%- if duplicate_prompt_examples %}
|
||||||
|
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```yaml
|
||||||
|
code_suggestions:
|
||||||
|
- suggestion_summary: |
|
||||||
|
...
|
||||||
|
relevant_file: "..."
|
||||||
|
relevant_lines_start: ...
|
||||||
|
relevant_lines_end: ...
|
||||||
|
suggestion_score: ...
|
||||||
|
why: |
|
||||||
|
...
|
||||||
|
- ...
|
||||||
|
```
|
||||||
|
(replace '...' with actual content)
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
Response (should be a valid YAML, and nothing else):
|
Response (should be a valid YAML, and nothing else):
|
||||||
```yaml
|
```yaml
|
||||||
"""
|
"""
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
[pr_description_prompt]
|
[pr_description_prompt]
|
||||||
system="""You are PR-Reviewer, a language model designed to review a Git Pull Request (PR).
|
system="""You are PR-Reviewer, a language model designed to review a Git Pull Request (PR).
|
||||||
{%- if enable_custom_labels %}
|
Your task is to provide a full description for the PR content - type, description, title and files walkthrough.
|
||||||
Your task is to provide a full description for the PR content - files walkthrough, title, type, description and labels.
|
- Focus on the new PR code (lines starting with '+' in the 'PR Git Diff' section).
|
||||||
{%- else %}
|
|
||||||
Your task is to provide a full description for the PR content - files walkthrough, title, type, and description.
|
|
||||||
{%- endif %}
|
|
||||||
- Focus on the new PR code (lines starting with '+').
|
|
||||||
- Keep in mind that the 'Previous title', 'Previous description' and 'Commit messages' sections may be partial, simplistic, non-informative or out of date. Hence, compare them to the PR diff code, and use them only as a reference.
|
- Keep in mind that the 'Previous title', 'Previous description' and 'Commit messages' sections may be partial, simplistic, non-informative or out of date. Hence, compare them to the PR diff code, and use them only as a reference.
|
||||||
- The generated title and description should prioritize the most significant changes.
|
- The generated title and description should prioritize the most significant changes.
|
||||||
- If needed, each YAML output should be in block scalar indicator ('|-')
|
- If needed, each YAML output should be in block scalar indicator ('|')
|
||||||
- When quoting variables, names or file paths from the code, use backticks (`) instead of single quote (').
|
- When quoting variables, names or file paths from the code, use backticks (`) instead of single quote (').
|
||||||
|
|
||||||
{%- if extra_instructions %}
|
{%- if extra_instructions %}
|
||||||
@ -39,7 +35,6 @@ class PRType(str, Enum):
|
|||||||
|
|
||||||
class FileDescription(BaseModel):
|
class FileDescription(BaseModel):
|
||||||
filename: str = Field(description="The full file path of the relevant file")
|
filename: str = Field(description="The full file path of the relevant file")
|
||||||
language: str = Field(description="The programming language of the relevant file")
|
|
||||||
{%- if include_file_summary_changes %}
|
{%- if include_file_summary_changes %}
|
||||||
changes_summary: str = Field(description="concise summary of the changes in the relevant file, in bullet points (1-4 bullet points).")
|
changes_summary: str = Field(description="concise summary of the changes in the relevant file, in bullet points (1-4 bullet points).")
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
@ -49,11 +44,11 @@ class FileDescription(BaseModel):
|
|||||||
|
|
||||||
class PRDescription(BaseModel):
|
class PRDescription(BaseModel):
|
||||||
type: List[PRType] = Field(description="one or more types that describe the PR content. Return the label member value (e.g. 'Bug fix', not 'bug_fix')")
|
type: List[PRType] = Field(description="one or more types that describe the PR content. Return the label member value (e.g. 'Bug fix', not 'bug_fix')")
|
||||||
|
description: str = Field(description="summarize the PR changes in up to four bullet points, each up to 8 words. For large PRs, add sub-bullets if needed. Order bullets by importance, with each bullet highlighting a key change group.")
|
||||||
|
title: str = Field(description="a concise and descriptive title that captures the PR's main theme")
|
||||||
{%- if enable_semantic_files_types %}
|
{%- if enable_semantic_files_types %}
|
||||||
pr_files: List[FileDescription] = Field(max_items=20, description="a list of all the files that were changed in the PR, and summary of their changes. Each file must be analyzed regardless of change size.")
|
pr_files: List[FileDescription] = Field(max_items=20, description="a list of all the files that were changed in the PR, and summary of their changes. Each file must be analyzed regardless of change size.")
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
description: str = Field(description="an informative and concise description of the PR. Use bullet points. Display first the most significant changes.")
|
|
||||||
title: str = Field(description="an informative title for the PR, describing its main theme")
|
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
|
||||||
@ -63,12 +58,14 @@ Example output:
|
|||||||
type:
|
type:
|
||||||
- ...
|
- ...
|
||||||
- ...
|
- ...
|
||||||
|
description: |
|
||||||
|
...
|
||||||
|
title: |
|
||||||
|
...
|
||||||
{%- if enable_semantic_files_types %}
|
{%- if enable_semantic_files_types %}
|
||||||
pr_files:
|
pr_files:
|
||||||
- filename: |
|
- filename: |
|
||||||
...
|
...
|
||||||
language: |
|
|
||||||
...
|
|
||||||
{%- if include_file_summary_changes %}
|
{%- if include_file_summary_changes %}
|
||||||
changes_summary: |
|
changes_summary: |
|
||||||
...
|
...
|
||||||
@ -79,10 +76,6 @@ pr_files:
|
|||||||
label_key_1
|
label_key_1
|
||||||
...
|
...
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
description: |
|
|
||||||
...
|
|
||||||
title: |
|
|
||||||
...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Answer should be a valid YAML, and nothing else. Each YAML output MUST be after a newline, with proper indent, and block scalar indicator ('|')
|
Answer should be a valid YAML, and nothing else. Each YAML output MUST be after a newline, with proper indent, and block scalar indicator ('|')
|
||||||
@ -130,13 +123,44 @@ Commit messages:
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
The PR Diff:
|
The PR Git Diff:
|
||||||
=====
|
=====
|
||||||
{{ diff|trim }}
|
{{ diff|trim }}
|
||||||
=====
|
=====
|
||||||
|
|
||||||
Note that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines.
|
Note that lines in the diff body are prefixed with a symbol that represents the type of change: '-' for deletions, '+' for additions, and ' ' (a space) for unchanged lines.
|
||||||
|
|
||||||
|
{%- if duplicate_prompt_examples %}
|
||||||
|
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```yaml
|
||||||
|
type:
|
||||||
|
- Bug fix
|
||||||
|
- Refactoring
|
||||||
|
- ...
|
||||||
|
description: |
|
||||||
|
...
|
||||||
|
title: |
|
||||||
|
...
|
||||||
|
{%- if enable_semantic_files_types %}
|
||||||
|
pr_files:
|
||||||
|
- filename: |
|
||||||
|
...
|
||||||
|
{%- if include_file_summary_changes %}
|
||||||
|
changes_summary: |
|
||||||
|
...
|
||||||
|
{%- endif %}
|
||||||
|
changes_title: |
|
||||||
|
...
|
||||||
|
label: |
|
||||||
|
label_key_1
|
||||||
|
...
|
||||||
|
{%- endif %}
|
||||||
|
```
|
||||||
|
(replace '...' with the actual values)
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
Response (should be a valid YAML, and nothing else):
|
Response (should be a valid YAML, and nothing else):
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -13,7 +13,7 @@ The output must be a YAML object equivalent to type $DocHelper, according to the
|
|||||||
=====
|
=====
|
||||||
class relevant_section(BaseModel):
|
class relevant_section(BaseModel):
|
||||||
file_name: str = Field(description="The name of the relevant file")
|
file_name: str = Field(description="The name of the relevant file")
|
||||||
relevant_section_header_string: str = Field(description="From the relevant file, exact text of the relevant section heading. If no markdown heading is relevant, return empty string")
|
relevant_section_header_string: str = Field(description="The exact text of the relevant markdown section heading from the relevant file (starting with '#', '##', etc.). Return empty string if the entire file is the relevant section, or if the relevant section has no heading")
|
||||||
|
|
||||||
class DocHelper(BaseModel):
|
class DocHelper(BaseModel):
|
||||||
user_question: str = Field(description="The user's question")
|
user_question: str = Field(description="The user's question")
|
||||||
|
@ -16,20 +16,20 @@ The format we will use to present the PR code diff:
|
|||||||
|
|
||||||
@@ ... @@ def func1():
|
@@ ... @@ def func1():
|
||||||
__new hunk__
|
__new hunk__
|
||||||
11 unchanged code line0 in the PR
|
11 unchanged code line0
|
||||||
12 unchanged code line1 in the PR
|
12 unchanged code line1
|
||||||
13 +new code line2 added in the PR
|
13 +new code line2 added
|
||||||
14 unchanged code line3 in the PR
|
14 unchanged code line3
|
||||||
__old hunk__
|
__old hunk__
|
||||||
unchanged code line0
|
unchanged code line0
|
||||||
unchanged code line1
|
unchanged code line1
|
||||||
-old code line2 removed in the PR
|
-old code line2 removed
|
||||||
unchanged code line3
|
unchanged code line3
|
||||||
|
|
||||||
@@ ... @@ def func2():
|
@@ ... @@ def func2():
|
||||||
__new hunk__
|
__new hunk__
|
||||||
unchanged code line4
|
unchanged code line4
|
||||||
+new code line5 removed in the PR
|
+new code line5 removed
|
||||||
unchanged code line6
|
unchanged code line6
|
||||||
|
|
||||||
## File: 'src/file2.py'
|
## File: 'src/file2.py'
|
||||||
@ -43,7 +43,7 @@ __new hunk__
|
|||||||
{%- if is_ai_metadata %}
|
{%- 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.
|
- 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 %}
|
{%- endif %}
|
||||||
- When quoting variables or names from the code, use backticks (`) instead of single quote (').
|
- When quoting variables, names or file paths from the code, use backticks (`) instead of single quote (').
|
||||||
|
|
||||||
|
|
||||||
{%- if extra_instructions %}
|
{%- if extra_instructions %}
|
||||||
@ -75,10 +75,10 @@ class KeyIssuesComponentLink(BaseModel):
|
|||||||
|
|
||||||
class TicketCompliance(BaseModel):
|
class TicketCompliance(BaseModel):
|
||||||
ticket_url: str = Field(description="Ticket URL or ID")
|
ticket_url: str = Field(description="Ticket URL or ID")
|
||||||
ticket_requirements: str = Field(description="Repeat, in your own words, all ticket requirements, in bullet points")
|
ticket_requirements: str = Field(description="Repeat, in your own words (in bullet points), all the requirements, sub-tasks, DoD, and acceptance criteria raised by the ticket")
|
||||||
fully_compliant_requirements: str = Field(description="A list, in bullet points, of which requirements are met by the PR code. Don't explain how the requirements are met, just list them shortly. Can be empty")
|
fully_compliant_requirements: str = Field(description="Bullet-point list of items from the 'ticket_requirements' section above that are fulfilled by the PR code. Don't explain how the requirements are met, just list them shortly. Can be empty")
|
||||||
not_compliant_requirements: str = Field(description="A list, in bullet points, of which requirements are not met by the PR code. Don't explain how the requirements are not met, just list them shortly. Can be empty")
|
not_compliant_requirements: str = Field(description="Bullet-point list of items from the 'ticket_requirements' section above that are not fulfilled by the PR code. Don't explain how the requirements are not met, just list them shortly. Can be empty")
|
||||||
overall_compliance_level: str = Field(description="Overall give this PR one of these three values in relation to the ticket: 'Fully compliant', 'Partially compliant', or 'Not compliant'")
|
requires_further_human_verification: str = Field(description="Bullet-point list of items from the 'ticket_requirements' section above that cannot be assessed through code review alone, are unclear, or need further human review (e.g., browser testing, UI checks). Leave empty if all 'ticket_requirements' were marked as fully compliant or not compliant")
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
class Review(BaseModel):
|
class Review(BaseModel):
|
||||||
@ -221,6 +221,59 @@ The PR code diff:
|
|||||||
======
|
======
|
||||||
|
|
||||||
|
|
||||||
|
{%- if duplicate_prompt_examples %}
|
||||||
|
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```yaml
|
||||||
|
review:
|
||||||
|
{%- if related_tickets %}
|
||||||
|
ticket_compliance_check:
|
||||||
|
- ticket_url: |
|
||||||
|
...
|
||||||
|
ticket_requirements: |
|
||||||
|
...
|
||||||
|
fully_compliant_requirements: |
|
||||||
|
...
|
||||||
|
not_compliant_requirements: |
|
||||||
|
...
|
||||||
|
overall_compliance_level: |
|
||||||
|
...
|
||||||
|
{%- endif %}
|
||||||
|
{%- if require_estimate_effort_to_review %}
|
||||||
|
estimated_effort_to_review_[1-5]: |
|
||||||
|
3
|
||||||
|
{%- endif %}
|
||||||
|
{%- if require_score %}
|
||||||
|
score: 89
|
||||||
|
{%- endif %}
|
||||||
|
relevant_tests: |
|
||||||
|
No
|
||||||
|
key_issues_to_review:
|
||||||
|
- relevant_file: |
|
||||||
|
...
|
||||||
|
issue_header: |
|
||||||
|
...
|
||||||
|
issue_content: |
|
||||||
|
...
|
||||||
|
start_line: ...
|
||||||
|
end_line: ...
|
||||||
|
- ...
|
||||||
|
security_concerns: |
|
||||||
|
No
|
||||||
|
{%- if require_can_be_split_review %}
|
||||||
|
can_be_split:
|
||||||
|
- relevant_files:
|
||||||
|
- ...
|
||||||
|
- ...
|
||||||
|
title: ...
|
||||||
|
- ...
|
||||||
|
{%- endif %}
|
||||||
|
```
|
||||||
|
(replace '...' with the actual values)
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
Response (should be a valid YAML, and nothing else):
|
Response (should be a valid YAML, and nothing else):
|
||||||
```yaml
|
```yaml
|
||||||
"""
|
"""
|
||||||
|
@ -4,6 +4,7 @@ import difflib
|
|||||||
import re
|
import re
|
||||||
import textwrap
|
import textwrap
|
||||||
import traceback
|
import traceback
|
||||||
|
from datetime import datetime
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
@ -81,6 +82,8 @@ class PRCodeSuggestions:
|
|||||||
"relevant_best_practices": "",
|
"relevant_best_practices": "",
|
||||||
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
|
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
|
||||||
"focus_only_on_problems": get_settings().get("pr_code_suggestions.focus_only_on_problems", False),
|
"focus_only_on_problems": get_settings().get("pr_code_suggestions.focus_only_on_problems", False),
|
||||||
|
"date": datetime.now().strftime('%Y-%m-%d'),
|
||||||
|
'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False),
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|
||||||
@ -717,7 +720,7 @@ class PRCodeSuggestions:
|
|||||||
header = f"Suggestion"
|
header = f"Suggestion"
|
||||||
delta = 66
|
delta = 66
|
||||||
header += " " * delta
|
header += " " * delta
|
||||||
pr_body += f"""<thead><tr><td>Category</td><td align=left>{header}</td><td align=center>Score</td></tr>"""
|
pr_body += f"""<thead><tr><td><strong>Category</strong></td><td align=left><strong>{header}</strong></td><td align=center><strong>Impact</strong></td></tr>"""
|
||||||
pr_body += """<tbody>"""
|
pr_body += """<tbody>"""
|
||||||
suggestions_labels = dict()
|
suggestions_labels = dict()
|
||||||
# add all suggestions related to each label
|
# add all suggestions related to each label
|
||||||
@ -737,7 +740,7 @@ class PRCodeSuggestions:
|
|||||||
counter_suggestions = 0
|
counter_suggestions = 0
|
||||||
for label, suggestions in suggestions_labels.items():
|
for label, suggestions in suggestions_labels.items():
|
||||||
num_suggestions = len(suggestions)
|
num_suggestions = len(suggestions)
|
||||||
pr_body += f"""<tr><td rowspan={num_suggestions}><strong>{label.capitalize()}</strong></td>\n"""
|
pr_body += f"""<tr><td rowspan={num_suggestions}>{label.capitalize()}</td>\n"""
|
||||||
for i, suggestion in enumerate(suggestions):
|
for i, suggestion in enumerate(suggestions):
|
||||||
|
|
||||||
relevant_file = suggestion['relevant_file'].strip()
|
relevant_file = suggestion['relevant_file'].strip()
|
||||||
@ -791,14 +794,19 @@ class PRCodeSuggestions:
|
|||||||
|
|
||||||
{example_code.rstrip()}
|
{example_code.rstrip()}
|
||||||
"""
|
"""
|
||||||
|
if suggestion.get('score_why'):
|
||||||
pr_body += f"<details><summary>Suggestion importance[1-10]: {suggestion['score']}</summary>\n\n"
|
pr_body += f"<details><summary>Suggestion importance[1-10]: {suggestion['score']}</summary>\n\n"
|
||||||
pr_body += f"Why: {suggestion['score_why']}\n\n"
|
pr_body += f"__\n\nWhy: {suggestion['score_why']}\n\n"
|
||||||
pr_body += f"</details>"
|
pr_body += f"</details>"
|
||||||
|
|
||||||
pr_body += f"</details>"
|
pr_body += f"</details>"
|
||||||
|
|
||||||
# # add another column for 'score'
|
# # add another column for 'score'
|
||||||
pr_body += f"</td><td align=center>{suggestion['score']}\n\n"
|
score_int = int(suggestion.get('score', 0))
|
||||||
|
score_str = f"{score_int}"
|
||||||
|
if get_settings().pr_code_suggestions.new_score_mechanism:
|
||||||
|
score_str = self.get_score_str(score_int)
|
||||||
|
pr_body += f"</td><td align=center>{score_str}\n\n"
|
||||||
|
|
||||||
pr_body += f"</td></tr>"
|
pr_body += f"</td></tr>"
|
||||||
counter_suggestions += 1
|
counter_suggestions += 1
|
||||||
@ -811,6 +819,16 @@ class PRCodeSuggestions:
|
|||||||
get_logger().info(f"Failed to publish summarized code suggestions, error: {e}")
|
get_logger().info(f"Failed to publish summarized code suggestions, error: {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def get_score_str(self, score: int) -> str:
|
||||||
|
th_high = get_settings().pr_code_suggestions.get('new_score_mechanism_th_high', 9)
|
||||||
|
th_medium = get_settings().pr_code_suggestions.get('new_score_mechanism_th_medium', 7)
|
||||||
|
if score >= th_high:
|
||||||
|
return "High"
|
||||||
|
elif score >= th_medium:
|
||||||
|
return "Medium"
|
||||||
|
else: # score < 7
|
||||||
|
return "Low"
|
||||||
|
|
||||||
async def self_reflect_on_suggestions(self,
|
async def self_reflect_on_suggestions(self,
|
||||||
suggestion_list: List,
|
suggestion_list: List,
|
||||||
patches_diff: str,
|
patches_diff: str,
|
||||||
@ -830,7 +848,8 @@ class PRCodeSuggestions:
|
|||||||
"diff": patches_diff,
|
"diff": patches_diff,
|
||||||
'num_code_suggestions': len(suggestion_list),
|
'num_code_suggestions': len(suggestion_list),
|
||||||
'prev_suggestions_str': prev_suggestions_str,
|
'prev_suggestions_str': prev_suggestions_str,
|
||||||
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False)}
|
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
|
||||||
|
'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False)}
|
||||||
environment = Environment(undefined=StrictUndefined)
|
environment = Environment(undefined=StrictUndefined)
|
||||||
|
|
||||||
if dedicated_prompt:
|
if dedicated_prompt:
|
||||||
|
@ -38,12 +38,15 @@ class PRConfig:
|
|||||||
if (header.lower().startswith("pr_") or header.lower().startswith("config")) and header.lower() in configuration_headers
|
if (header.lower().startswith("pr_") or header.lower().startswith("config")) and header.lower() in configuration_headers
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_keys = ['ai_disclaimer', 'ai_disclaimer_title', 'ANALYTICS_FOLDER', 'secret_provider', "skip_keys",
|
skip_keys = ['ai_disclaimer', 'ai_disclaimer_title', 'ANALYTICS_FOLDER', 'secret_provider', "skip_keys", "app_id", "redirect",
|
||||||
'trial_prefix_message', 'no_eligible_message', 'identity_provider', 'ALLOWED_REPOS',
|
'trial_prefix_message', 'no_eligible_message', 'identity_provider', 'ALLOWED_REPOS',
|
||||||
'APP_NAME']
|
'APP_NAME', 'PERSONAL_ACCESS_TOKEN', 'shared_secret', 'key', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'user_token',
|
||||||
|
'private_key', 'private_key_id', 'client_id', 'client_secret', 'token', 'bearer_token']
|
||||||
extra_skip_keys = get_settings().config.get('config.skip_keys', [])
|
extra_skip_keys = get_settings().config.get('config.skip_keys', [])
|
||||||
if extra_skip_keys:
|
if extra_skip_keys:
|
||||||
skip_keys.extend(extra_skip_keys)
|
skip_keys.extend(extra_skip_keys)
|
||||||
|
skip_keys_lower = [key.lower() for key in skip_keys]
|
||||||
|
|
||||||
|
|
||||||
markdown_text = "<details> <summary><strong>🛠️ PR-Agent Configurations:</strong></summary> \n\n"
|
markdown_text = "<details> <summary><strong>🛠️ PR-Agent Configurations:</strong></summary> \n\n"
|
||||||
markdown_text += f"\n\n```yaml\n\n"
|
markdown_text += f"\n\n```yaml\n\n"
|
||||||
@ -52,7 +55,7 @@ class PRConfig:
|
|||||||
markdown_text += "\n\n"
|
markdown_text += "\n\n"
|
||||||
markdown_text += f"==================== {header} ===================="
|
markdown_text += f"==================== {header} ===================="
|
||||||
for key, value in configs.items():
|
for key, value in configs.items():
|
||||||
if key in skip_keys:
|
if key.lower() in skip_keys_lower:
|
||||||
continue
|
continue
|
||||||
markdown_text += f"\n{header.lower()}.{key.lower()} = {repr(value) if isinstance(value, str) else value}"
|
markdown_text += f"\n{header.lower()}.{key.lower()} = {repr(value) if isinstance(value, str) else value}"
|
||||||
markdown_text += " "
|
markdown_text += " "
|
||||||
|
@ -71,7 +71,8 @@ class PRDescription:
|
|||||||
"custom_labels_class": "", # will be filled if necessary in 'set_custom_labels' function
|
"custom_labels_class": "", # will be filled if necessary in 'set_custom_labels' function
|
||||||
"enable_semantic_files_types": get_settings().pr_description.enable_semantic_files_types,
|
"enable_semantic_files_types": get_settings().pr_description.enable_semantic_files_types,
|
||||||
"related_tickets": "",
|
"related_tickets": "",
|
||||||
"include_file_summary_changes": len(self.git_provider.get_diff_files()) <= self.COLLAPSIBLE_FILE_LIST_THRESHOLD
|
"include_file_summary_changes": len(self.git_provider.get_diff_files()) <= self.COLLAPSIBLE_FILE_LIST_THRESHOLD,
|
||||||
|
'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.user_description = self.git_provider.get_user_description()
|
self.user_description = self.git_provider.get_user_description()
|
||||||
@ -133,8 +134,18 @@ class PRDescription:
|
|||||||
pr_body += "<hr>\n\n<details> <summary><strong>✨ Describe tool usage guide:</strong></summary><hr> \n\n"
|
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 += HelpMessage.get_describe_usage_guide()
|
||||||
pr_body += "\n</details>\n"
|
pr_body += "\n</details>\n"
|
||||||
elif get_settings().pr_description.enable_help_comment:
|
elif get_settings().pr_description.enable_help_comment and self.git_provider.is_supported("gfm_markdown"):
|
||||||
pr_body += '\n\n___\n\n> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull request to receive relevant information'
|
if isinstance(self.git_provider, GithubProvider):
|
||||||
|
pr_body += ('\n\n___\n\n> <details> <summary> Need help?</summary><li>Type <code>/help how to ...</code> '
|
||||||
|
'in the comments thread for any questions about PR-Agent usage.</li><li>Check out the '
|
||||||
|
'<a href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a> '
|
||||||
|
'for more information.</li></details>')
|
||||||
|
else: # gitlab
|
||||||
|
pr_body += ("\n\n___\n\n<details><summary>Need help?</summary>- Type <code>/help how to ...</code> in the comments "
|
||||||
|
"thread for any questions about PR-Agent usage.<br>- Check out the "
|
||||||
|
"<a href='https://qodo-merge-docs.qodo.ai/usage-guide/'>documentation</a> for more information.</details>")
|
||||||
|
# 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
|
# Output the relevant configurations if enabled
|
||||||
if get_settings().get('config', {}).get('output_relevant_configurations', False):
|
if get_settings().get('config', {}).get('output_relevant_configurations', False):
|
||||||
@ -470,7 +481,16 @@ class PRDescription:
|
|||||||
|
|
||||||
def _prepare_pr_answer_with_markers(self) -> Tuple[str, str, str, List[dict]]:
|
def _prepare_pr_answer_with_markers(self) -> Tuple[str, str, str, List[dict]]:
|
||||||
get_logger().info(f"Using description marker replacements {self.pr_id}")
|
get_logger().info(f"Using description marker replacements {self.pr_id}")
|
||||||
|
|
||||||
|
# Remove the 'PR Title' key from the dictionary
|
||||||
|
ai_title = self.data.pop('title', self.vars["title"])
|
||||||
|
if (not get_settings().pr_description.generate_ai_title):
|
||||||
|
# Assign the original PR title to the 'title' variable
|
||||||
title = self.vars["title"]
|
title = self.vars["title"]
|
||||||
|
else:
|
||||||
|
# Assign the value of the 'PR Title' key to 'title' variable
|
||||||
|
title = ai_title
|
||||||
|
|
||||||
body = self.user_description
|
body = self.user_description
|
||||||
if get_settings().pr_description.include_generated_by_header:
|
if get_settings().pr_description.include_generated_by_header:
|
||||||
ai_header = f"### 🤖 Generated by PR Agent at {self.git_provider.last_commit_id.sha}\n\n"
|
ai_header = f"### 🤖 Generated by PR Agent at {self.git_provider.last_commit_id.sha}\n\n"
|
||||||
@ -479,6 +499,10 @@ class PRDescription:
|
|||||||
|
|
||||||
ai_type = self.data.get('type')
|
ai_type = self.data.get('type')
|
||||||
if ai_type and not re.search(r'<!--\s*pr_agent:type\s*-->', body):
|
if ai_type and not re.search(r'<!--\s*pr_agent:type\s*-->', body):
|
||||||
|
if isinstance(ai_type, list):
|
||||||
|
pr_types = [f"{ai_header}{t}" for t in ai_type]
|
||||||
|
pr_type = ','.join(pr_types)
|
||||||
|
else:
|
||||||
pr_type = f"{ai_header}{ai_type}"
|
pr_type = f"{ai_header}{ai_type}"
|
||||||
body = body.replace('pr_agent:type', pr_type)
|
body = body.replace('pr_agent:type', pr_type)
|
||||||
|
|
||||||
@ -556,6 +580,11 @@ class PRDescription:
|
|||||||
elif 'pr_files' in key.lower() and get_settings().pr_description.enable_semantic_files_types:
|
elif 'pr_files' in key.lower() and get_settings().pr_description.enable_semantic_files_types:
|
||||||
changes_walkthrough, pr_file_changes = self.process_pr_files_prediction(changes_walkthrough, value)
|
changes_walkthrough, pr_file_changes = self.process_pr_files_prediction(changes_walkthrough, value)
|
||||||
changes_walkthrough = f"{PRDescriptionHeader.CHANGES_WALKTHROUGH.value}\n{changes_walkthrough}"
|
changes_walkthrough = f"{PRDescriptionHeader.CHANGES_WALKTHROUGH.value}\n{changes_walkthrough}"
|
||||||
|
elif key.lower().strip() == 'description':
|
||||||
|
if isinstance(value, list):
|
||||||
|
value = ', '.join(v.rstrip() for v in value)
|
||||||
|
value = value.replace('\n-', '\n\n-').strip() # makes the bullet points more readable by adding double space
|
||||||
|
pr_body += f"{value}\n"
|
||||||
else:
|
else:
|
||||||
# if the value is a list, join its items by comma
|
# if the value is a list, join its items by comma
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import copy
|
import copy
|
||||||
|
import re
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -9,10 +10,9 @@ 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.ai_handlers.litellm_ai_handler import LiteLLMAIHandler
|
||||||
from pr_agent.algo.pr_processing import retry_with_fallback_models
|
from pr_agent.algo.pr_processing import retry_with_fallback_models
|
||||||
from pr_agent.algo.token_handler import TokenHandler
|
from pr_agent.algo.token_handler import TokenHandler
|
||||||
from pr_agent.algo.utils import ModelType, clip_tokens, load_yaml
|
from pr_agent.algo.utils import ModelType, clip_tokens, load_yaml, get_max_tokens
|
||||||
from pr_agent.config_loader import get_settings
|
from pr_agent.config_loader import get_settings
|
||||||
from pr_agent.git_providers import (BitbucketServerProvider, GithubProvider,
|
from pr_agent.git_providers import BitbucketServerProvider, GithubProvider, get_git_provider_with_context
|
||||||
get_git_provider_with_context)
|
|
||||||
from pr_agent.log import get_logger
|
from pr_agent.log import get_logger
|
||||||
|
|
||||||
|
|
||||||
@ -30,10 +30,11 @@ def extract_header(snippet):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
class PRHelpMessage:
|
class PRHelpMessage:
|
||||||
def __init__(self, pr_url: str, args=None, ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler):
|
def __init__(self, pr_url: str, args=None, ai_handler: partial[BaseAiHandler,] = LiteLLMAIHandler, return_as_string=False):
|
||||||
self.git_provider = get_git_provider_with_context(pr_url)
|
self.git_provider = get_git_provider_with_context(pr_url)
|
||||||
self.ai_handler = ai_handler()
|
self.ai_handler = ai_handler()
|
||||||
self.question_str = self.parse_args(args)
|
self.question_str = self.parse_args(args)
|
||||||
|
self.return_as_string = return_as_string
|
||||||
self.num_retrieved_snippets = get_settings().get('pr_help.num_retrieved_snippets', 5)
|
self.num_retrieved_snippets = get_settings().get('pr_help.num_retrieved_snippets', 5)
|
||||||
if self.question_str:
|
if self.question_str:
|
||||||
self.vars = {
|
self.vars = {
|
||||||
@ -65,6 +66,34 @@ class PRHelpMessage:
|
|||||||
question_str = ""
|
question_str = ""
|
||||||
return question_str
|
return question_str
|
||||||
|
|
||||||
|
def format_markdown_header(self, header: str) -> str:
|
||||||
|
try:
|
||||||
|
# First, strip common characters from both ends
|
||||||
|
cleaned = header.strip('# 💎\n')
|
||||||
|
|
||||||
|
# Define all characters to be removed/replaced in a single pass
|
||||||
|
replacements = {
|
||||||
|
"'": '',
|
||||||
|
"`": '',
|
||||||
|
'(': '',
|
||||||
|
')': '',
|
||||||
|
',': '',
|
||||||
|
'.': '',
|
||||||
|
'?': '',
|
||||||
|
'!': '',
|
||||||
|
' ': '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compile regex pattern for characters to remove
|
||||||
|
pattern = re.compile('|'.join(map(re.escape, replacements.keys())))
|
||||||
|
|
||||||
|
# Perform replacements in a single pass and convert to lowercase
|
||||||
|
return pattern.sub(lambda m: replacements[m.group()], cleaned).lower()
|
||||||
|
except Exception:
|
||||||
|
get_logger().exception(f"Error while formatting markdown header", artifacts={'header': header})
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
try:
|
try:
|
||||||
if self.question_str:
|
if self.question_str:
|
||||||
@ -106,7 +135,10 @@ class PRHelpMessage:
|
|||||||
get_logger().debug(f"Token count of full documentation website: {token_count}")
|
get_logger().debug(f"Token count of full documentation website: {token_count}")
|
||||||
|
|
||||||
model = get_settings().config.model
|
model = get_settings().config.model
|
||||||
|
if model in MAX_TOKENS:
|
||||||
max_tokens_full = MAX_TOKENS[model] # note - here we take the actual max tokens, without any reductions. we do aim to get the full documentation website in the prompt
|
max_tokens_full = MAX_TOKENS[model] # note - here we take the actual max tokens, without any reductions. we do aim to get the full documentation website in the prompt
|
||||||
|
else:
|
||||||
|
max_tokens_full = get_max_tokens(model)
|
||||||
delta_output = 2000
|
delta_output = 2000
|
||||||
if token_count > max_tokens_full - delta_output:
|
if token_count > max_tokens_full - delta_output:
|
||||||
get_logger().info(f"Token count {token_count} exceeds the limit {max_tokens_full - delta_output}. Skipping the PR Help message.")
|
get_logger().info(f"Token count {token_count} exceeds the limit {max_tokens_full - delta_output}. Skipping the PR Help message.")
|
||||||
@ -114,8 +146,16 @@ class PRHelpMessage:
|
|||||||
self.vars['snippets'] = docs_prompt.strip()
|
self.vars['snippets'] = docs_prompt.strip()
|
||||||
|
|
||||||
# run the AI model
|
# run the AI model
|
||||||
response = await retry_with_fallback_models(self._prepare_prediction, model_type=ModelType.WEAK)
|
response = await retry_with_fallback_models(self._prepare_prediction, model_type=ModelType.REGULAR)
|
||||||
response_yaml = load_yaml(response)
|
response_yaml = load_yaml(response)
|
||||||
|
if isinstance(response_yaml, str):
|
||||||
|
get_logger().warning(f"failing to parse response: {response_yaml}, publishing the response as is")
|
||||||
|
if get_settings().config.publish_output:
|
||||||
|
answer_str = f"### Question: \n{self.question_str}\n\n"
|
||||||
|
answer_str += f"### Answer:\n\n"
|
||||||
|
answer_str += response_yaml
|
||||||
|
self.git_provider.publish_comment(answer_str)
|
||||||
|
return ""
|
||||||
response_str = response_yaml.get('response')
|
response_str = response_yaml.get('response')
|
||||||
relevant_sections = response_yaml.get('relevant_sections')
|
relevant_sections = response_yaml.get('relevant_sections')
|
||||||
|
|
||||||
@ -138,7 +178,7 @@ class PRHelpMessage:
|
|||||||
for section in relevant_sections:
|
for section in relevant_sections:
|
||||||
file = section.get('file_name').strip().removesuffix('.md')
|
file = section.get('file_name').strip().removesuffix('.md')
|
||||||
if str(section['relevant_section_header_string']).strip():
|
if str(section['relevant_section_header_string']).strip():
|
||||||
markdown_header = section['relevant_section_header_string'].strip().strip('#').strip().lower().replace(' ', '-').replace("'", '').replace('(', '').replace(')', '').replace(',', '').replace('.', '').replace('?', '').replace('!', '')
|
markdown_header = self.format_markdown_header(section['relevant_section_header_string'])
|
||||||
answer_str += f"> - {base_path}{file}#{markdown_header}\n"
|
answer_str += f"> - {base_path}{file}#{markdown_header}\n"
|
||||||
else:
|
else:
|
||||||
answer_str += f"> - {base_path}{file}\n"
|
answer_str += f"> - {base_path}{file}\n"
|
||||||
@ -174,10 +214,11 @@ class PRHelpMessage:
|
|||||||
tool_names.append(f"[IMPROVE COMPONENT]({base_path}/improve_component/) 💎")
|
tool_names.append(f"[IMPROVE COMPONENT]({base_path}/improve_component/) 💎")
|
||||||
tool_names.append(f"[ANALYZE]({base_path}/analyze/) 💎")
|
tool_names.append(f"[ANALYZE]({base_path}/analyze/) 💎")
|
||||||
tool_names.append(f"[ASK]({base_path}/ask/)")
|
tool_names.append(f"[ASK]({base_path}/ask/)")
|
||||||
|
tool_names.append(f"[SIMILAR ISSUE]({base_path}/similar_issues/)")
|
||||||
tool_names.append(f"[GENERATE CUSTOM LABELS]({base_path}/custom_labels/) 💎")
|
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"[CI FEEDBACK]({base_path}/ci_feedback/) 💎")
|
||||||
tool_names.append(f"[CUSTOM PROMPT]({base_path}/custom_prompt/) 💎")
|
tool_names.append(f"[CUSTOM PROMPT]({base_path}/custom_prompt/) 💎")
|
||||||
tool_names.append(f"[SIMILAR ISSUE]({base_path}/similar_issues/)")
|
tool_names.append(f"[IMPLEMENT]({base_path}/implement/) 💎")
|
||||||
|
|
||||||
descriptions = []
|
descriptions = []
|
||||||
descriptions.append("Generates PR description - title, type, summary, code walkthrough and labels")
|
descriptions.append("Generates PR description - title, type, summary, code walkthrough and labels")
|
||||||
@ -189,10 +230,11 @@ class PRHelpMessage:
|
|||||||
descriptions.append("Code suggestions for a specific component that changed in the PR")
|
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("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("Answering free-text questions about the PR")
|
||||||
|
descriptions.append("Automatically retrieves and presents similar issues")
|
||||||
descriptions.append("Generates custom labels for the PR, based on specific guidelines defined by the user")
|
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 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("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")
|
descriptions.append("Generates implementation code from review suggestions")
|
||||||
|
|
||||||
commands =[]
|
commands =[]
|
||||||
commands.append("`/describe`")
|
commands.append("`/describe`")
|
||||||
@ -204,10 +246,11 @@ class PRHelpMessage:
|
|||||||
commands.append("`/improve_component`")
|
commands.append("`/improve_component`")
|
||||||
commands.append("`/analyze`")
|
commands.append("`/analyze`")
|
||||||
commands.append("`/ask`")
|
commands.append("`/ask`")
|
||||||
|
commands.append("`/similar_issue`")
|
||||||
commands.append("`/generate_labels`")
|
commands.append("`/generate_labels`")
|
||||||
commands.append("`/checks`")
|
commands.append("`/checks`")
|
||||||
commands.append("`/custom_prompt`")
|
commands.append("`/custom_prompt`")
|
||||||
commands.append("`/similar_issue`")
|
commands.append("`/implement`")
|
||||||
|
|
||||||
checkbox_list = []
|
checkbox_list = []
|
||||||
checkbox_list.append(" - [ ] Run <!-- /describe -->")
|
checkbox_list.append(" - [ ] Run <!-- /describe -->")
|
||||||
@ -226,13 +269,14 @@ class PRHelpMessage:
|
|||||||
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):
|
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>"
|
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)):
|
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 += 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 += "</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(1) Note that each tool can 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."""
|
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):
|
elif isinstance(self.git_provider, BitbucketServerProvider):
|
||||||
# only support basic commands in BBDC
|
# only support basic commands in BBDC
|
||||||
@ -242,7 +286,7 @@ class PRHelpMessage:
|
|||||||
for i in range(len(tool_names)):
|
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 += 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 += "</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)."""
|
pr_comment += f"""\n\nNote that each tool can 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:
|
if get_settings().config.publish_output:
|
||||||
self.git_provider.publish_comment(pr_comment)
|
self.git_provider.publish_comment(pr_comment)
|
||||||
|
@ -94,6 +94,7 @@ class PRReviewer:
|
|||||||
"enable_custom_labels": get_settings().config.enable_custom_labels,
|
"enable_custom_labels": get_settings().config.enable_custom_labels,
|
||||||
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
|
"is_ai_metadata": get_settings().get("config.enable_ai_metadata", False),
|
||||||
"related_tickets": get_settings().get('related_tickets', []),
|
"related_tickets": get_settings().get('related_tickets', []),
|
||||||
|
'duplicate_prompt_examples': get_settings().config.get('duplicate_prompt_examples', False),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.token_handler = TokenHandler(
|
self.token_handler = TokenHandler(
|
||||||
@ -370,7 +371,7 @@ class PRReviewer:
|
|||||||
else:
|
else:
|
||||||
get_logger().warning(f"Unexpected type for estimated_effort: {type(estimated_effort)}")
|
get_logger().warning(f"Unexpected type for estimated_effort: {type(estimated_effort)}")
|
||||||
if 1 <= estimated_effort_number <= 5: # 1, because ...
|
if 1 <= estimated_effort_number <= 5: # 1, because ...
|
||||||
review_labels.append(f'Review effort [1-5]: {estimated_effort_number}')
|
review_labels.append(f'Review effort {estimated_effort_number}/5')
|
||||||
if get_settings().pr_reviewer.enable_review_labels_security and get_settings().pr_reviewer.require_security_review:
|
if get_settings().pr_reviewer.enable_review_labels_security and get_settings().pr_reviewer.require_security_review:
|
||||||
security_concerns = data['review']['security_concerns'] # yes, because ...
|
security_concerns = data['review']['security_concerns'] # yes, because ...
|
||||||
security_concerns_bool = 'yes' in security_concerns.lower() or 'true' in security_concerns.lower()
|
security_concerns_bool = 'yes' in security_concerns.lower() or 'true' in security_concerns.lower()
|
||||||
@ -383,7 +384,7 @@ class PRReviewer:
|
|||||||
get_logger().debug(f"Current labels:\n{current_labels}")
|
get_logger().debug(f"Current labels:\n{current_labels}")
|
||||||
if current_labels:
|
if current_labels:
|
||||||
current_labels_filtered = [label for label in current_labels if
|
current_labels_filtered = [label for label in current_labels if
|
||||||
not label.lower().startswith('review effort [1-5]:') and not label.lower().startswith(
|
not label.lower().startswith('review effort') and not label.lower().startswith(
|
||||||
'possible security concern')]
|
'possible security concern')]
|
||||||
else:
|
else:
|
||||||
current_labels_filtered = []
|
current_labels_filtered = []
|
||||||
@ -401,20 +402,6 @@ class PRReviewer:
|
|||||||
Auto-approve a pull request if it meets the conditions for auto-approval.
|
Auto-approve a pull request if it meets the conditions for auto-approval.
|
||||||
"""
|
"""
|
||||||
if get_settings().pr_reviewer.enable_auto_approval:
|
if get_settings().pr_reviewer.enable_auto_approval:
|
||||||
maximal_review_effort = get_settings().pr_reviewer.maximal_review_effort
|
|
||||||
if maximal_review_effort < 5:
|
|
||||||
current_labels = self.git_provider.get_pr_labels()
|
|
||||||
for label in current_labels:
|
|
||||||
if label.lower().startswith('review effort [1-5]:'):
|
|
||||||
effort = int(label.split(':')[1].strip())
|
|
||||||
if effort > maximal_review_effort:
|
|
||||||
get_logger().info(
|
|
||||||
f"Auto-approve error: PR review effort ({effort}) is higher than the maximal review effort "
|
|
||||||
f"({maximal_review_effort}) allowed")
|
|
||||||
self.git_provider.publish_comment(
|
|
||||||
f"Auto-approve error: PR review effort ({effort}) is higher than the maximal review effort "
|
|
||||||
f"({maximal_review_effort}) allowed")
|
|
||||||
return
|
|
||||||
is_auto_approved = self.git_provider.auto_approve()
|
is_auto_approved = self.git_provider.auto_approve()
|
||||||
if is_auto_approved:
|
if is_auto_approved:
|
||||||
get_logger().info("Auto-approved PR")
|
get_logger().info("Auto-approved PR")
|
||||||
|
@ -51,6 +51,11 @@ def extract_ticket_links_from_pr_description(pr_description, repo_path, base_url
|
|||||||
issue_number = match[5][1:] # remove #
|
issue_number = match[5][1:] # remove #
|
||||||
if issue_number.isdigit() and len(issue_number) < 5 and repo_path:
|
if issue_number.isdigit() and len(issue_number) < 5 and repo_path:
|
||||||
github_tickets.add(f'{base_url_html.strip("/")}/{repo_path}/issues/{issue_number}')
|
github_tickets.add(f'{base_url_html.strip("/")}/{repo_path}/issues/{issue_number}')
|
||||||
|
|
||||||
|
if len(github_tickets) > 3:
|
||||||
|
get_logger().info(f"Too many tickets found in PR description: {len(github_tickets)}")
|
||||||
|
# Limit the number of tickets to 3
|
||||||
|
github_tickets = set(list(github_tickets)[:3])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
get_logger().error(f"Error extracting tickets error= {e}",
|
get_logger().error(f"Error extracting tickets error= {e}",
|
||||||
artifact={"traceback": traceback.format_exc()})
|
artifact={"traceback": traceback.format_exc()})
|
||||||
|
@ -31,7 +31,7 @@ dynamic = ["dependencies"]
|
|||||||
dependencies = { file = ["requirements.txt"] }
|
dependencies = { file = ["requirements.txt"] }
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
"Homepage" = "https://github.com/Codium-ai/pr-agent"
|
"Homepage" = "https://github.com/qodo-ai/pr-agent"
|
||||||
"Documentation" = "https://pr-agent-docs.codium.ai/"
|
"Documentation" = "https://pr-agent-docs.codium.ai/"
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
|
2
setup.py
2
setup.py
@ -3,3 +3,5 @@
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
|
|
||||||
|
print("Hi")
|
||||||
|
@ -24,6 +24,13 @@ class TestBitbucketServerProvider:
|
|||||||
assert repo_slug == "my-repo"
|
assert repo_slug == "my-repo"
|
||||||
assert pr_number == 1
|
assert pr_number == 1
|
||||||
|
|
||||||
|
def test_parse_pr_url_with_users(self):
|
||||||
|
url = "https://bitbucket.company-server.url/users/username/repos/my-repo/pull-requests/1"
|
||||||
|
workspace_slug, repo_slug, pr_number = BitbucketServerProvider._parse_pr_url(url)
|
||||||
|
assert workspace_slug == "~username"
|
||||||
|
assert repo_slug == "my-repo"
|
||||||
|
assert pr_number == 1
|
||||||
|
|
||||||
def mock_get_content_of_file(self, project_key, repository_slug, filename, at=None, markup=None):
|
def mock_get_content_of_file(self, project_key, repository_slug, filename, at=None, markup=None):
|
||||||
content_map = {
|
content_map = {
|
||||||
'9c1cffdd9f276074bfb6fb3b70fbee62d298b058': 'file\nwith\nsome\nlines\nto\nemulate\na\nreal\nfile\n',
|
'9c1cffdd9f276074bfb6fb3b70fbee62d298b058': 'file\nwith\nsome\nlines\nto\nemulate\na\nreal\nfile\n',
|
||||||
@ -244,7 +251,7 @@ class TestBitbucketServerProvider:
|
|||||||
FilePatchInfo(
|
FilePatchInfo(
|
||||||
'file\nwith\nmultiple\nlines\nto\nemulate\na\nreal\nfile',
|
'file\nwith\nmultiple\nlines\nto\nemulate\na\nreal\nfile',
|
||||||
'readme\nwithout\nsome\nlines\nto\nsimulate\na\nreal\nfile',
|
'readme\nwithout\nsome\nlines\nto\nsimulate\na\nreal\nfile',
|
||||||
'--- \n+++ \n@@ -1,9 +1,9 @@\n-file\n-with\n-multiple\n+readme\n+without\n+some\n lines\n to\n-emulate\n+simulate\n a\n real\n file',
|
'--- \n+++ \n@@ -1,9 +1,9 @@\n-file\n-with\n-multiple\n+readme\n+without\n+some\n lines\n to\n-emulate\n+simulate\n a\n real\n file\n',
|
||||||
'Readme.md',
|
'Readme.md',
|
||||||
edit_type=EDIT_TYPE.MODIFIED,
|
edit_type=EDIT_TYPE.MODIFIED,
|
||||||
)
|
)
|
||||||
@ -266,7 +273,7 @@ class TestBitbucketServerProvider:
|
|||||||
FilePatchInfo(
|
FilePatchInfo(
|
||||||
'file\nwith\nsome\nlines\nto\nemulate\na\nreal\nfile',
|
'file\nwith\nsome\nlines\nto\nemulate\na\nreal\nfile',
|
||||||
'readme\nwithout\nsome\nlines\nto\nsimulate\na\nreal\nfile',
|
'readme\nwithout\nsome\nlines\nto\nsimulate\na\nreal\nfile',
|
||||||
'--- \n+++ \n@@ -1,9 +1,9 @@\n-file\n-with\n+readme\n+without\n some\n lines\n to\n-emulate\n+simulate\n a\n real\n file',
|
'--- \n+++ \n@@ -1,9 +1,9 @@\n-file\n-with\n+readme\n+without\n some\n lines\n to\n-emulate\n+simulate\n a\n real\n file\n',
|
||||||
'Readme.md',
|
'Readme.md',
|
||||||
edit_type=EDIT_TYPE.MODIFIED,
|
edit_type=EDIT_TYPE.MODIFIED,
|
||||||
)
|
)
|
||||||
@ -288,7 +295,7 @@ class TestBitbucketServerProvider:
|
|||||||
FilePatchInfo(
|
FilePatchInfo(
|
||||||
'file\nwith\nsome\nlines\nto\nemulate\na\nreal\nfile',
|
'file\nwith\nsome\nlines\nto\nemulate\na\nreal\nfile',
|
||||||
'readme\nwithout\nsome\nlines\nto\nsimulate\na\nreal\nfile',
|
'readme\nwithout\nsome\nlines\nto\nsimulate\na\nreal\nfile',
|
||||||
'--- \n+++ \n@@ -1,9 +1,9 @@\n-file\n-with\n+readme\n+without\n some\n lines\n to\n-emulate\n+simulate\n a\n real\n file',
|
'--- \n+++ \n@@ -1,9 +1,9 @@\n-file\n-with\n+readme\n+without\n some\n lines\n to\n-emulate\n+simulate\n a\n real\n file\n',
|
||||||
'Readme.md',
|
'Readme.md',
|
||||||
edit_type=EDIT_TYPE.MODIFIED,
|
edit_type=EDIT_TYPE.MODIFIED,
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@ import pytest
|
|||||||
from pr_agent.algo.git_patch_processing import extend_patch
|
from pr_agent.algo.git_patch_processing import extend_patch
|
||||||
from pr_agent.algo.pr_processing import pr_generate_extended_diff
|
from pr_agent.algo.pr_processing import pr_generate_extended_diff
|
||||||
from pr_agent.algo.token_handler import TokenHandler
|
from pr_agent.algo.token_handler import TokenHandler
|
||||||
|
from pr_agent.algo.utils import load_large_diff
|
||||||
from pr_agent.config_loader import get_settings
|
from pr_agent.config_loader import get_settings
|
||||||
|
|
||||||
|
|
||||||
@ -145,8 +146,8 @@ class TestExtendedPatchMoreLines:
|
|||||||
# Check that with no extra lines, the patches are the same as the original patches
|
# Check that with no extra lines, the patches are the same as the original patches
|
||||||
p0 = patches_extended_no_extra_lines[0].strip()
|
p0 = patches_extended_no_extra_lines[0].strip()
|
||||||
p1 = patches_extended_no_extra_lines[1].strip()
|
p1 = patches_extended_no_extra_lines[1].strip()
|
||||||
assert p0 == '## file1\n' + pr_languages[0]['files'][0].patch.strip()
|
assert p0 == "## File: 'file1'\n" + pr_languages[0]['files'][0].patch.strip()
|
||||||
assert p1 == '## file2\n' + pr_languages[0]['files'][1].patch.strip()
|
assert p1 == "## File: 'file2'\n" + pr_languages[0]['files'][1].patch.strip()
|
||||||
|
|
||||||
patches_extended_with_extra_lines, total_tokens, patches_extended_tokens = pr_generate_extended_diff(
|
patches_extended_with_extra_lines, total_tokens, patches_extended_tokens = pr_generate_extended_diff(
|
||||||
pr_languages, token_handler, add_line_numbers_to_hunks=False,
|
pr_languages, token_handler, add_line_numbers_to_hunks=False,
|
||||||
@ -154,5 +155,37 @@ class TestExtendedPatchMoreLines:
|
|||||||
patch_extra_lines_after=1
|
patch_extra_lines_after=1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
p0_extended = patches_extended_with_extra_lines[0].strip()
|
p0_extended = patches_extended_with_extra_lines[0].strip()
|
||||||
assert p0_extended == '## file1\n\n@@ -3,8 +3,8 @@ \n line0\n line1\n-original content\n+modified content\n line2\n line3\n line4\n line5\n line6'
|
assert p0_extended == "## File: 'file1'\n\n@@ -3,8 +3,8 @@ \n line0\n line1\n-original content\n+modified content\n line2\n line3\n line4\n line5\n line6"
|
||||||
|
|
||||||
|
|
||||||
|
class TestLoadLargeDiff:
|
||||||
|
def test_no_newline(self):
|
||||||
|
patch = load_large_diff("test.py",
|
||||||
|
"""\
|
||||||
|
old content 1
|
||||||
|
some new content
|
||||||
|
another line
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
old content 1
|
||||||
|
old content 2""")
|
||||||
|
|
||||||
|
patch_expected="""\
|
||||||
|
---
|
||||||
|
+++
|
||||||
|
@@ -1,3 +1,3 @@
|
||||||
|
-
|
||||||
|
old content 1
|
||||||
|
- old content 2
|
||||||
|
+ some new content
|
||||||
|
+ another line
|
||||||
|
"""
|
||||||
|
assert patch == patch_expected
|
||||||
|
|
||||||
|
def test_empty_inputs(self):
|
||||||
|
assert load_large_diff("test.py", "", "") == ""
|
||||||
|
assert load_large_diff("test.py", None, None) == ""
|
||||||
|
assert (load_large_diff("test.py", "content\n", "") ==
|
||||||
|
'--- \n+++ \n@@ -1 +1 @@\n-\n+content\n')
|
Reference in New Issue
Block a user