Compare commits

..

2 Commits

Author SHA1 Message Date
72ad76692b Output the same output structure as in npx 2025-05-29 17:26:02 +03:00
5dfd696c2b - Add entrypoint: gen-api-key that generates API Key via QodoGen CLI.
```pipx run -e --spec . gen-api-key```

- Add shell script as an alternative to Python for API key generation
2025-05-28 14:12:41 +03:00
34 changed files with 324 additions and 1353 deletions

172
README.md
View File

@ -29,47 +29,19 @@ PR-Agent aims to help efficiently review and handle pull requests, by providing
## Table of Contents
- [Getting Started](#getting-started)
- [News and Updates](#news-and-updates)
- [Overview](#overview)
- [See It in Action](#see-it-in-action)
- [Try It Now](#try-it-now)
- [Qodo Merge 💎](#qodo-merge-)
- [How It Works](#how-it-works)
- [Why Use PR-Agent?](#why-use-pr-agent)
- [Data Privacy](#data-privacy)
- [Example results](#example-results)
- [Try it now](#try-it-now)
- [Qodo Merge](https://qodo-merge-docs.qodo.ai/overview/pr_agent_pro/)
- [How it works](#how-it-works)
- [Why use PR-Agent?](#why-use-pr-agent)
- [Data privacy](#data-privacy)
- [Contributing](#contributing)
- [Links](#links)
## Getting Started
### Try it Instantly
Test PR-Agent on any public GitHub repository by commenting `@CodiumAI-Agent /improve`
### GitHub Action
Add automated PR reviews to your repository with a simple workflow file using [GitHub Action setup guide](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action)
#### Other Platforms
- [GitLab webhook setup](https://qodo-merge-docs.qodo.ai/installation/gitlab/)
- [BitBucket app installation](https://qodo-merge-docs.qodo.ai/installation/bitbucket/)
- [Azure DevOps setup](https://qodo-merge-docs.qodo.ai/installation/azure/)
### CLI Usage
Run PR-Agent locally on your repository via command line: [Local CLI setup guide](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#local-repo-cli)
### Discover Qodo Merge 💎
Zero-setup hosted solution with advanced features and priority support
- [Intro and Installation guide](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/)
- [Plans & Pricing](https://www.qodo.ai/pricing/)
## News and Updates
## Jun 3, 2025
Qodo Merge now offers a simplified free tier 💎.
Organizations can use Qodo Merge at no cost, with a [monthly limit](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/#cloud-users) of 75 PR reviews per organization.
## May 17, 2025
- v0.29 was [released](https://github.com/qodo-ai/pr-agent/releases)
@ -98,58 +70,84 @@ Read more about it [here](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discus
Supported commands per platform:
| | | GitHub | GitLab | Bitbucket | Azure DevOps | Gitea |
|---------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|:-----:|
| [TOOLS](https://qodo-merge-docs.qodo.ai/tools/) | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ | |
| | ⮑ [Ask on code lines](https://qodo-merge-docs.qodo.ai/tools/ask/#ask-lines) | ✅ | ✅ | | | |
| | [Help Docs](https://qodo-merge-docs.qodo.ai/tools/help_docs/?h=auto#auto-approval) | ✅ | ✅ | ✅ | | |
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | | |
| | [Add Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | | |
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | | |
| | [Auto-Approve](https://qodo-merge-docs.qodo.ai/tools/improve/?h=auto#auto-approval) 💎 | ✅ | | | | |
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | | |
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | | | | |
| | [Generate Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | | |
| | [Generate Tests](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | | |
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | | | |
| | [Scan Repo Discussions](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discussions/) 💎 | ✅ | | | | |
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | | |
| | [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) 💎 | ✅ | ✅ | ✅ | | |
| | [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) 💎 | ✅ | ✅ | | | |
| | | | | | | |
| [USAGE](https://qodo-merge-docs.qodo.ai/usage-guide/) | [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) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Tagging bot](https://github.com/Codium-ai/pr-agent#try-it-now) | ✅ | | | | |
| | [Actions](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) | ✅ | ✅ | ✅ | ✅ | |
| | | | | | | |
| [CORE](https://qodo-merge-docs.qodo.ai/core-abilities/) | [Adaptive and token-aware file patch fitting](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ | |
| | [Auto Best Practices 💎](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices/) | ✅ | | | | |
| | [Chat on code suggestions](https://qodo-merge-docs.qodo.ai/core-abilities/chat_on_code_suggestions/) | ✅ | ✅ | | | |
| | [Code Validation 💎](https://qodo-merge-docs.qodo.ai/core-abilities/code_validation/) | ✅ | ✅ | ✅ | ✅ | |
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ | |
| | [Fetching ticket context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) | ✅ | ✅ | ✅ | | |
| | [Global and wiki configurations](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | | | |
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | | |
| | [Incremental Update](https://qodo-merge-docs.qodo.ai/core-abilities/incremental_update/) | ✅ | | | | |
| | [Interactivity](https://qodo-merge-docs.qodo.ai/core-abilities/interactivity/) | ✅ | ✅ | | | |
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ | |
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | | | | |
| | [PR compression](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ | |
| | [PR interactive actions](https://www.qodo.ai/images/pr_agent/pr-actions.mp4) 💎 | ✅ | ✅ | | | |
| | [RAG context enrichment](https://qodo-merge-docs.qodo.ai/core-abilities/rag_context_enrichment/) | ✅ | | ✅ | | |
| | [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/) 💎 | ✅ | ✅ | | | |
| | | GitHub | GitLab | Bitbucket | Azure DevOps | Gitea |
| ----- |---------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|:-----:|
| TOOLS | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ | |
| | ⮑ [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/) | ✅ | ✅ | ✅ | | |
| | [Help Docs](https://qodo-merge-docs.qodo.ai/tools/help_docs/?h=auto#auto-approval) | ✅ | ✅ | ✅ | | |
| | [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) 💎 | ✅ | ✅ | | | |
| | [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) 💎 | ✅ | | | | |
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | | |
| | [PR Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | | |
| | [Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | | |
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | | |
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | | |
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | | | | |
| | [Test](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | | |
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | ✅ | | |
| | [Scan Repo Discussions](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discussions/) 💎 | ✅ | | | | |
| | [Auto-Approve](https://qodo-merge-docs.qodo.ai/tools/improve/?h=auto#auto-approval) 💎 | ✅ | ✅ | | | |
| | | | | | | |
| 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) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Tagging bot](https://github.com/Codium-ai/pr-agent#try-it-now) | ✅ | | | | |
| | [Actions](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) | ✅ | ✅ | ✅ | ✅ | |
| | | | | | | |
| CORE | [PR compression](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ | |
| | Adaptive and token-aware file patch fitting | ✅ | ✅ | | | |
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | ✅ | | | |
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ | |
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ | |
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | | ✅ | | |
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | | | |
| | [Global and wiki configurations](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | | | |
| | [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/) 💎 | ✅ | ✅ | | | |
| | [Code Validation 💎](https://qodo-merge-docs.qodo.ai/core-abilities/code_validation/) | ✅ | ✅ | ✅ | ✅ | |
| | [Auto Best Practices 💎](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices/) | ✅ | | | | |
- 💎 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))
___
## See It in Action
**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://qodo-merge-docs.qodo.ai/tools/review/))**: Adjustable feedback about the PR, possible issues, security concerns, review effort and more.
\
**Code Suggestions ([`/improve`](https://qodo-merge-docs.qodo.ai/tools/improve/))**: Code suggestions for improving 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://qodo-merge-docs.qodo.ai/tools/update_changelog/))**: Automatically updating the CHANGELOG.md file with the PR changes.
\
**Help Docs ([`/help_docs`](https://qodo-merge-docs.qodo.ai/tools/help_docs/))**: Answers a question on any repository by utilizing given documentation.
\
**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://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://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.
\
**Test 💎 ([`/test`](https://qodo-merge-docs.qodo.ai/tools/test/))**: Generate 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.
\
**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.
\
**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
</div>
<h4><a href="https://github.com/Codium-ai/pr-agent/pull/530">/describe</a></h4>
@ -184,7 +182,7 @@ ___
</div>
<hr>
## Try It Now
## Try it now
Try the Claude Sonnet powered PR-Agent instantly on _your public GitHub repository_. Just mention `@CodiumAI-Agent` and add the desired command in any PR comment. The agent will generate a response based on your command.
For example, add a comment to any pull request with the following text:
@ -210,7 +208,7 @@ It does not have 'edit' access to your repo, for example, so it cannot update th
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 Qodo Merge.
## How It Works
## How it works
The following diagram illustrates PR-Agent tools and their flow:
@ -218,7 +216,7 @@ The following diagram illustrates PR-Agent tools and their flow:
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?
A reasonable question that can be asked is: `"Why use PR-Agent? What makes it stand out from existing tools?"`
@ -226,10 +224,10 @@ Here are some advantages of PR-Agent:
- We emphasize **real-life practical usage**. Each tool (review, improve, ask, ...) has a single LLM 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://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 us 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, Claude, Deepseek, ...)
## Data Privacy
## Data privacy
### Self-hosted PR-Agent
@ -254,7 +252,7 @@ To contribute to the project, get started by reading our [Contributing Guide](ht
## Links
- Discord community: https://discord.com/invite/SgSxuQ65GF
- Discord community: https://discord.gg/kG35uSHDBc
- Qodo site: https://www.qodo.ai/
- Blog: https://www.qodo.ai/blog/
- Troubleshooting: https://www.qodo.ai/blog/technical-faq-and-troubleshooting/

View File

@ -4,7 +4,7 @@ With a single-click installation you will gain access to a context-aware chat on
The extension is powered by top code models like Claude 3.7 Sonnet and o4-mini. All the extension's features are free to use on public repositories.
For private repositories, you will need to install [Qodo Merge](https://github.com/apps/qodo-merge-pro){:target="_blank"} in addition to the extension.
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 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">

View File

@ -9,9 +9,8 @@ This integration enriches the review process by automatically surfacing relevant
**Ticket systems supported**:
- [GitHub](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/#github-issues-integration)
- [Jira (💎)](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/#jira-integration)
- [Linear (💎)](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/#linear-integration)
- GitHub
- Jira (💎)
**Ticket data fetched:**
@ -76,17 +75,13 @@ The recommended way to authenticate with Jira Cloud is to install the Qodo Merge
Installation steps:
1. Go to the [Qodo Merge integrations page](https://app.qodo.ai/qodo-merge/integrations)
2. Click on the Connect **Jira Cloud** button to connect the Jira Cloud app
3. Click the `accept` button.<br>
1. Click [here](https://auth.atlassian.com/authorize?audience=api.atlassian.com&client_id=8krKmA4gMD8mM8z24aRCgPCSepZNP1xf&scope=read%3Ajira-work%20offline_access&redirect_uri=https%3A%2F%2Fregister.jira.pr-agent.codium.ai&state=qodomerge&response_type=code&prompt=consent) to install the Qodo Merge app in your Jira Cloud instance, click the `accept` button.<br>
![Jira Cloud App Installation](https://www.qodo.ai/images/pr_agent/jira_app_installation1.png){width=384}
4. After installing the app, you will be redirected to the Qodo Merge registration page. and you will see a success message.<br>
2. After installing the app, you will be redirected to the Qodo Merge registration page. and you will see a success message.<br>
![Jira Cloud App success message](https://www.qodo.ai/images/pr_agent/jira_app_success.png){width=384}
5. Now Qodo Merge will be able to fetch Jira ticket context for your PRs.
3. Now Qodo Merge will be able to fetch Jira ticket context for your PRs.
**2) Email/Token Authentication**
@ -195,7 +190,7 @@ This following steps will help you check if the basic auth is working correctly,
2. run the following Python script (after replacing the placeholders with your actual values):
???- example "Script to validate basic auth"
??? example "Script to validate basic auth"
```python
from jira import JIRA
@ -251,7 +246,7 @@ This following steps will help you check if the token is working correctly, and
2. run the following Python script (after replacing the placeholders with your actual values):
??? example- "Script to validate PAT token"
??? example "Script to validate PAT token"
```python
from jira import JIRA
@ -286,83 +281,6 @@ This following steps will help you check if the token is working correctly, and
print(f"Error fetching JIRA ticket details: {e}")
```
### Multi-JIRA Server Configuration 💎
Qodo Merge supports connecting to multiple JIRA servers using different authentication methods.
=== "Email/Token (Basic Auth)"
Configure multiple servers using Email/Token authentication:
- `jira_servers`: List of JIRA server URLs
- `jira_api_token`: List of API tokens (for Cloud) or passwords (for Data Center)
- `jira_api_email`: List of emails (for Cloud) or usernames (for Data Center)
- `jira_base_url`: Default server for ticket IDs like `PROJ-123`, Each repository can configure (local config file) its own `jira_base_url` to choose which server to use by default.
**Example Configuration:**
```toml
[jira]
# Server URLs
jira_servers = ["https://company.atlassian.net", "https://datacenter.jira.com"]
# API tokens/passwords
jira_api_token = ["cloud_api_token_here", "datacenter_password"]
# Emails/usernames (both required)
jira_api_email = ["user@company.com", "datacenter_username"]
# Default server for ticket IDs
jira_base_url = "https://company.atlassian.net"
```
=== "PAT Auth"
Configure multiple servers using Personal Access Token authentication:
- `jira_servers`: List of JIRA server URLs
- `jira_api_token`: List of PAT tokens
- `jira_api_email`: Not needed (can be omitted or left empty)
- `jira_base_url`: Default server for ticket IDs like `PROJ-123`, Each repository can configure (local config file) its own `jira_base_url` to choose which server to use by default.
**Example Configuration:**
```toml
[jira]
# Server URLs
jira_servers = ["https://server1.jira.com", "https://server2.jira.com"]
# PAT tokens only
jira_api_token = ["pat_token_1", "pat_token_2"]
# Default server for ticket IDs
jira_base_url = "https://server1.jira.com"
```
**Mixed Authentication (Email/Token + PAT):**
```toml
[jira]
jira_servers = ["https://company.atlassian.net", "https://server.jira.com"]
jira_api_token = ["cloud_api_token", "server_pat_token"]
jira_api_email = ["user@company.com", ""] # Empty for PAT
```
=== "Jira Cloud App"
For Jira Cloud instances using App Authentication:
1. Install the Qodo Merge app on each JIRA Cloud instance you want to connect to
2. Set the default server for ticket ID resolution:
```toml
[jira]
jira_base_url = "https://primary-team.atlassian.net"
```
Full URLs (e.g., `https://other-team.atlassian.net/browse/TASK-456`) will automatically use the correct connected instance.
### How to link a PR to a Jira ticket
To integrate with Jira, you can link your PR to a ticket using either of these methods:
@ -382,45 +300,3 @@ Name your branch with the ticket ID as a prefix (e.g., `ISSUE-123-feature-descri
[jira]
jira_base_url = "https://<JIRA_ORG>.atlassian.net"
```
## Linear Integration 💎
### Linear App Authentication
The recommended way to authenticate with Linear is to connect the Linear app through the Qodo Merge portal.
Installation steps:
1. Go to the [Qodo Merge integrations page](https://app.qodo.ai/qodo-merge/integrations)
2. Navigate to the **Integrations** tab
3. Click on the **Linear** button to connect the Linear app
4. Follow the authentication flow to authorize Qodo Merge to access your Linear workspace
5. Once connected, Qodo Merge will be able to fetch Linear ticket context for your PRs
### How to link a PR to a Linear ticket
Qodo Merge will automatically detect Linear tickets using either of these methods:
**Method 1: Description Reference:**
Include a ticket reference in your PR description using either:
- The complete Linear ticket URL: `https://linear.app/[ORG_ID]/issue/[TICKET_ID]`
- The shortened ticket ID: `[TICKET_ID]` (e.g., `ABC-123`) - requires linear_base_url configuration (see below).
**Method 2: Branch Name Detection:**
Name your branch with the ticket ID as a prefix (e.g., `ABC-123-feature-description` or `feature/ABC-123/feature-description`).
!!! note "Linear Base URL"
For shortened ticket IDs or branch detection (method 2), you must configure the Linear base URL in your configuration file under the [linear] section:
```toml
[linear]
linear_base_url = "https://linear.app/[ORG_ID]"
```
Replace `[ORG_ID]` with your Linear organization identifier.

View File

@ -27,7 +27,7 @@ In order to enable the RAG feature, add the following lines to your configuratio
enable_rag=true
```
???+ example "RAG Arguments Options"
!!! example "RAG Arguments Options"
<table>
<tr>

View File

@ -26,52 +26,48 @@ To search the documentation site using natural language:
PR-Agent and Qodo Merge offers extensive pull request functionalities across various git providers:
| | | GitHub | GitLab | Bitbucket | Azure DevOps | Gitea |
| ----- |---------------------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|:-----:|
| [TOOLS](https://qodo-merge-docs.qodo.ai/tools/) | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ | |
| | ⮑ [Ask on code lines](https://qodo-merge-docs.qodo.ai/tools/ask/#ask-lines) | ✅ | ✅ | | | |
| | [Help Docs](https://qodo-merge-docs.qodo.ai/tools/help_docs/?h=auto#auto-approval) | ✅ | ✅ | ✅ | | |
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | ✅ | |
| | [Add Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | | |
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | | |
| | [Auto-Approve](https://qodo-merge-docs.qodo.ai/tools/improve/?h=auto#auto-approval) 💎 | ✅ | ✅ | ✅ | | |
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | | |
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | ✅ | | |
| | [Generate Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | | |
| | [Generate Tests](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | | |
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | | | |
| | [Scan Repo Discussions](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discussions/) 💎 | ✅ | | | | |
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | | |
| | [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) 💎 | ✅ | ✅ | ✅ | | |
| | [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) 💎 | ✅ | ✅ | | | |
| | | | | | | |
| [USAGE](https://qodo-merge-docs.qodo.ai/usage-guide/) | [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) | ✅ | ✅ | ✅ | ✅ | ✅ |
| | [Tagging bot](https://github.com/Codium-ai/pr-agent#try-it-now) | ✅ | | | | |
| | [Actions](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) | ✅ | ✅ | ✅ | ✅ | |
| | | | | | | |
| [CORE](https://qodo-merge-docs.qodo.ai/core-abilities/) | [Adaptive and token-aware file patch fitting](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ | |
| | [Auto Best Practices 💎](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices/) | | | | | |
| | [Chat on code suggestions](https://qodo-merge-docs.qodo.ai/core-abilities/chat_on_code_suggestions/) | ✅ | ✅ | | | |
| | [Code Validation 💎](https://qodo-merge-docs.qodo.ai/core-abilities/code_validation/) | ✅ | ✅ | ✅ | ✅ | |
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ | |
| | [Fetching ticket context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) | | ✅ | ✅ | | |
| | [Global and wiki configurations](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | | | |
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | | |
| | [Incremental Update 💎](https://qodo-merge-docs.qodo.ai/core-abilities/incremental_update/) | ✅ | | | | |
| | [Interactivity](https://qodo-merge-docs.qodo.ai/core-abilities/interactivity/) | ✅ | ✅ | | | |
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ | |
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | | | ✅ | |
| | [PR compression](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | | | ✅ | |
| | [PR interactive actions](https://www.qodo.ai/images/pr_agent/pr-actions.mp4) 💎 | ✅ | ✅ | | | |
| | [RAG context enrichment](https://qodo-merge-docs.qodo.ai/core-abilities/rag_context_enrichment/) | ✅ | | ✅ | | |
| | [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/) 💎 | ✅ | ✅ | | | |
| | | GitHub | GitLab | Bitbucket | Azure DevOps |
| ----- | ------------------------------------------------------------------------------------------------------- |:------:|:------:|:---------:|:------------:|
| TOOLS | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ |
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ |
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ |
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ |
| | ⮑ [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/) | ✅ | ✅ | ✅ | |
| | [Help Docs](https://qodo-merge-docs.qodo.ai/tools/help_docs/?h=auto#auto-approval) | ✅ | ✅ | ✅ | |
| | [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) 💎 | ✅ | ✅ | | |
| | [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) 💎 | ✅ | | | |
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | |
| | [PR Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | |
| | [Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | |
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | |
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | |
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | | |
| | [Test](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | |
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | ✅ | |
| | [Scan Repo Discussions](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discussions/) 💎 | ✅ | | | |
| | [Auto-Approve](https://qodo-merge-docs.qodo.ai/tools/improve/?h=auto#auto-approval) 💎 | ✅ | ✅ | | |
| | | | | | |
| 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) | ✅ | ✅ | ✅ | ✅ |
| | [Tagging bot](https://github.com/Codium-ai/pr-agent#try-it-now) | ✅ | | | |
| | [Actions](https://qodo-merge-docs.qodo.ai/installation/github/#run-as-a-github-action) | ✅ | ✅ | ✅ | ✅ |
| | | | | | |
| CORE | [PR compression](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ |
| | Adaptive and token-aware file patch fitting | | | | |
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | ✅ | | |
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ |
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ |
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | ✅ | ✅ | |
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | | |
| | [Global and wiki configurations](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | | |
| | [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/) 💎 | ✅ | ✅ | | |
| | [Code Validation 💎](https://qodo-merge-docs.qodo.ai/core-abilities/code_validation/) | ✅ | ✅ | ✅ | ✅ |
| | [Auto Best Practices 💎](https://qodo-merge-docs.qodo.ai/core-abilities/auto_best_practices/) | ✅ | | | |
| | [Incremental Update 💎](https://qodo-merge-docs.qodo.ai/core-abilities/incremental_update/) | ✅ | | | |
!!! note "💎 means Qodo Merge only"
All along the documentation, 💎 marks a feature available only in [Qodo Merge](https://www.codium.ai/pricing/){:target="_blank"}, and not in the open-source version.

View File

@ -203,28 +203,6 @@ For example: `GITHUB.WEBHOOK_SECRET` --> `GITHUB__WEBHOOK_SECRET`
7. Go back to steps 8-9 of [Method 5](#run-as-a-github-app) with the function url as your Webhook URL.
The Webhook URL would look like `https://<LAMBDA_FUNCTION_URL>/api/v1/github_webhooks`
### Using AWS Secrets Manager
For production Lambda deployments, use AWS Secrets Manager instead of environment variables:
1. Create a secret in AWS Secrets Manager with JSON format like this:
```json
{
"openai.key": "sk-proj-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"github.webhook_secret": "your-webhook-secret-from-step-2",
"github.private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----"
}
```
2. Add IAM permission `secretsmanager:GetSecretValue` to your Lambda execution role
3. Set these environment variables in your Lambda:
```bash
AWS_SECRETS_MANAGER__SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:pr-agent-secrets-AbCdEf
CONFIG__SECRET_PROVIDER=aws_secrets_manager
```
---
## AWS CodeCommit Setup

View File

@ -1,20 +1,20 @@
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.
## Usage and Licensing
## Trial Period and Licensing
### Cloud Users
### Cloud Users with Teams Account
Non-paying users will enjoy feedback on up to 75 PRs per git organization per month. Above this limit, PRs will not receive feedback until a new month begins.
A complimentary two-week trial is provided to all new users (with three additional grace usages). When the trial period ends, users will stop receiving feedback from Qodo Merge.
For unlimited access, user licenses (seats) are required. Each user requires an individual seat license.
Following the trial period, user licenses (seats) are required for continued access. Each user requires an individual seat license.
After purchasing seats, the team owner can assign them to specific users through the management portal.
With an assigned seat, users can seamlessly deploy the application across any of their code repositories in a git organization, and receive feedback on all their PRs.
With an assigned seat, users can seamlessly deploy the application across any of their code repositories.
### Enterprise Account
For companies who require an Enterprise account, please [contact](https://www.qodo.ai/contact/#pricing) us to initiate a trial period, and to discuss pricing and licensing options.
For organizations who require an Enterprise account, please [contact](https://www.qodo.ai/contact/#pricing) us to initiate a trial period, and to discuss pricing and licensing options.
## Install Qodo Merge for GitHub
@ -95,4 +95,4 @@ Open a new merge request or add a MR comment with one of Qodo Merges commands
### GitLab Server
For [limited free usage](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/#cloud-users) on private GitLab Server, the same [installation steps](#gitlab-cloud) as for GitLab Cloud apply. For unlimited usage, you will need to [contact](https://www.qodo.ai/contact/#pricing) Qodo for moving to an Enterprise account.
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.

View File

@ -1,11 +1,7 @@
### Overview
[Qodo Merge](https://www.codium.ai/pricing/){:target="_blank"} is a hosted version of the open-source [PR-Agent](https://github.com/Codium-ai/pr-agent){:target="_blank"}.
It is designed for companies and teams that require additional features and capabilities.
Free users receive a monthly quota of 75 PR reviews per git organization, while unlimited usage requires a paid subscription. See [details](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/#cloud-users).
Qodo Merge provides the following benefits:
[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 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.
@ -49,7 +45,7 @@ Here are additional tools that are available only for Qodo Merge users:
### Supported languages
Qodo Merge leverages the world's leading code models, such as Claude 4 Sonnet, o4-mini and Gemini-2.5-Pro.
Qodo Merge leverages the world's leading code models, such as Claude 3.7 Sonnet and o3-mini.
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 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).

View File

@ -1,23 +1,21 @@
# Recent Updates and Future Roadmap
`Page last updated: 2025-06-01`
`Page last updated: 2025-05-11`
This page summarizes recent enhancements to Qodo Merge (last three months).
It also outlines our development roadmap for the upcoming three months. Please note that the roadmap is subject to change, and features may be adjusted, added, or reprioritized.
=== "Recent Updates"
- **Simplified Free Tier**: Qodo Merge now offers a simplified free tier with a monthly limit of 75 PR reviews per organization, replacing the previous two-week trial. ([Learn more](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/#cloud-users))
- **CLI Endpoint**: A new Qodo Merge endpoint that accepts a lists of before/after code changes, executes Qodo Merge commands, and return the results. Currently available for enterprise customers. Contact [Qodo](https://www.qodo.ai/contact/) for more information.
- **Linear tickets support**: Qodo Merge now supports Linear tickets. ([Learn more](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/#linear-integration))
- **Smart Update**: Upon PR updates, Qodo Merge will offer tailored code suggestions, addressing both the entire PR and the specific incremental changes since the last feedback ([Learn more](https://qodo-merge-docs.qodo.ai/core-abilities/incremental_update//))
- **Qodo Merge Pull Request Benchmark** - evaluating the performance of LLMs in analyzing pull request code ([Learn more](https://qodo-merge-docs.qodo.ai/pr_benchmark/))
- **Chat on Suggestions**: Users can now chat with code suggestions ([Learn more](https://qodo-merge-docs.qodo.ai/tools/improve/#chat-on-code-suggestions))
- **Chat on Suggestions**: Users can now chat with Qodo Merge code suggestions ([Learn more](https://qodo-merge-docs.qodo.ai/tools/improve/#chat-on-code-suggestions))
- **Scan Repo Discussions Tool**: A new tool that analyzes past code discussions to generate a `best_practices.md` file, distilling key insights and recommendations. ([Learn more](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discussions/))
- **Enhanced Models**: Qodo Merge now defaults to a combination of top models (Claude Sonnet 3.7 and Gemini 2.5 Pro) and incorporates dedicated code validation logic for improved results. ([Details 1](https://qodo-merge-docs.qodo.ai/usage-guide/qodo_merge_models/), [Details 2](https://qodo-merge-docs.qodo.ai/core-abilities/code_validation/))
- **Chrome Extension Update**: Qodo Merge Chrome extension now supports single-tenant users. ([Learn more](https://qodo-merge-docs.qodo.ai/chrome-extension/options/#configuration-options/))
=== "Future Roadmap"
- **Smart Update**: Upon PR updates, Qodo Merge will offer tailored code suggestions, addressing both the entire PR and the specific incremental changes since the last feedback.
- **CLI Endpoint**: A new Qodo Merge endpoint will accept lists of before/after code changes, execute Qodo Merge commands, and return the results.
- **Simplified Free Tier**: We plan to transition from a two-week free trial to a free tier offering a limited number of suggestions per month per organization.
- **Best Practices Hierarchy**: Introducing support for structured best practices, such as for folders in monorepos or a unified best practice file for a group of repositories.
- **Enhanced `review` tool**: Enhancing the `review` tool validate compliance across multiple categories including security, tickets, and custom best practices.
- **Smarter context retrieval**: Leverage AST and LSP analysis to gather relevant context from across the entire repository.
- **Enhanced portal experience**: Improved user experience in the Qodo Merge portal with new options and capabilities.
- **Installation Metrics**: Upon installation, Qodo Merge will analyze past PRs for key metrics (e.g., time to merge, time to first reviewer feedback), enabling pre/post-installation comparison to calculate ROI.

View File

@ -73,7 +73,7 @@ enable_pr_diagram = true
## Configuration options
???+ example "Possible configurations"
!!! example "Possible configurations"
<table>
<tr>

View File

@ -46,6 +46,9 @@ pr_commands = [
The `pr_commands` list defines commands that run automatically when a PR is opened.
Since this is under the [github_app] section, it only applies when using the Qodo Merge GitHub App in GitHub environments.
!!! note
By default, /add_docs is not triggered automatically. You must explicitly include it in pr_commands to enable this behavior.
## Configuration options
- `docs_style`: The exact style of the documentation (for python docstring). you can choose between: `google`, `numpy`, `sphinx`, `restructuredtext`, `plain`. Default is `sphinx`.

View File

@ -144,216 +144,84 @@ Use triple quotes to write multi-line instructions. Use bullet points or numbers
> `💎 feature. Platforms supported: GitHub, GitLab, Bitbucket`
Qodo Merge supports both simple and hierarchical best practices configurations to provide guidance to the AI model for generating relevant code suggestions.
Another option to give additional guidance to the AI model is by creating a `best_practices.md` file in your repository's root directory.
This page can contain a list of best practices, coding standards, and guidelines that are specific to your repo/organization.
???- tip "Writing effective best practices files"
The following guidelines apply to all best practices files:
- Write clearly and concisely
- Include brief code examples when helpful with before/after patterns
- Focus on project-specific guidelines that will result in relevant suggestions you actually want to get
- Keep each file relatively short, under 800 lines, since:
- AI models may not process effectively very long documents
- Long files tend to contain generic guidelines already known to AI
- Use pattern-based structure rather than simple bullet points for better clarity
The AI model will use this `best_practices.md` file as a reference, and in case the PR code violates any of the guidelines, it will create additional suggestions, with a dedicated label: `Organization
best practice`.
???- tip "Example of a best practices file"
Pattern 1: Add proper error handling with try-except blocks around external function calls.
Example code before:
Example for a Python `best_practices.md` content:
```python
# Some code that might raise an exception
return process_pr_data(data)
```
```markdown
## Project best practices
- Make sure that I/O operations are encapsulated in a try-except block
- Use the `logging` module for logging instead of `print` statements
- Use `is` and `is not` to compare with `None`
- Use `if __name__ == '__main__':` to run the code only when the script is executed
- Use `with` statement to open files
...
```
Example code after:
Tips for writing an effective `best_practices.md` file:
```python
try:
# Some code that might raise an exception
return process_pr_data(data)
except Exception as e:
logger.exception("Failed to process request", extra={"error": e})
```
- Write clearly and concisely
- Include brief code examples when helpful
- Focus on project-specific guidelines, that will result in relevant suggestions you actually want to get
- Keep the file relatively short, under 800 lines, since:
- AI models may not process effectively very long documents
- Long files tend to contain generic guidelines already known to AI
Pattern 2: Add defensive null/empty checks before accessing object properties or performing operations on potentially null variables to prevent runtime errors.
Example code before:
To control the number of best practices suggestions generated by the `improve` tool, give the following configuration:
```python
def get_pr_code(pr_data):
if "changed_code" in pr_data:
return pr_data.get("changed_code", "")
return ""
```
```toml
[best_practices]
num_best_practice_suggestions = 2
```
Example code after:
#### Local and global best practices
```python
def get_pr_code(pr_data):
if pr_data is None:
return ""
if "changed_code" in pr_data:
return pr_data.get("changed_code", "")
return ""
```
By default, Qodo Merge will look for a local `best_practices.md` in the root of the relevant local repo.
#### Local best practices
If you want to enable also a global `best_practices.md` file, set first in the global configuration file:
For basic usage, create a `best_practices.md` file in your repository's root directory containing a list of best practices, coding standards, and guidelines specific to your repository.
```toml
[best_practices]
enable_global_best_practices = true
```
The AI model will use this `best_practices.md` file as a reference, and in case the PR code violates any of the guidelines, it will create additional suggestions, with a dedicated label: `Organization best practice`.
Then, create a `best_practices.md` file in the root of [global](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#global-configuration-file) configuration repository, `pr-agent-settings`.
#### Global hierarchical best practices
#### Best practices for multiple languages
For a git organization working with multiple programming languages, you can maintain a centralized global `best_practices.md` file containing language-specific guidelines.
When reviewing pull requests, Qodo Merge automatically identifies the programming language and applies the relevant best practices from this file.
For organizations managing multiple repositories with different requirements, Qodo Merge supports a hierarchical best practices system using a dedicated global configuration repository.
To do this, structure your `best_practices.md` file using the following format:
**Supported scenarios:**
```
# [Python]
...
# [Java]
...
# [JavaScript]
...
```
1. **Standalone repositories**: Individual repositories can have their own specific best practices tailored to their unique requirements
2. **Groups of repositories**: Repositories can be mapped to shared group-level best practices for consistent standards across similar projects
3. **Monorepos with subprojects**: Large monorepos can have both repository-level and subproject-level best practices, with automatic path-based matching
#### Dedicated label for best practices suggestions
#### Setting up global hierarchical best practices
1\. Create a new repository named `pr-agent-settings` in your organization/workspace.
Best practice suggestions are labeled as `Organization best practice` by default.
To customize this label, modify it in your configuration file:
2\. Build the folder hierarchy in your `pr-agent-settings` repository, for example:
```toml
[best_practices]
organization_name = "..."
```
```bash
pr-agent-settings/
├── metadata.yaml # Maps repos/folders to best practice paths
└── codebase_standards/ # Root for all best practice definitions
├── global/ # Global rules, inherited widely
│ └── best_practices.md
├── groups/ # For groups of repositories
│ ├── frontend_repos/
│ │ └── best_practices.md
│ ├── backend_repos/
│ │ └── best_practices.md
│ └── ...
├── qodo-merge/ # For standalone repositories
│ └── best_practices.md
├── qodo-monorepo/ # For monorepo-specific rules
│ ├── best_practices.md # Root level monorepo rules
│ ├── qodo-github/ # Subproject best practices
│ │ └── best_practices.md
│ └── qodo-gitlab/ # Another subproject
│ └── best_practices.md
└── ... # More repositories
```
And the label will be: `{organization_name} best practice`.
3\. Define the metadata file `metadata.yaml` that maps your repositories to their relevant best practices paths, for example:
#### Example results
```yaml
# Standalone repos
qodo-merge:
best_practices_paths:
- "qodo-merge"
# Group-associated repos
repo_b:
best_practices_paths:
- "groups/backend_repos"
# Multi-group repos
repo_c:
best_practices_paths:
- "groups/frontend_repos"
- "groups/backend_repos"
# Monorepo with subprojects
qodo-monorepo:
best_practices_paths:
- "qodo-monorepo"
monorepo_subprojects:
qodo-github:
best_practices_paths:
- "qodo-monorepo/qodo-github"
qodo-gitlab:
best_practices_paths:
- "qodo-monorepo/qodo-gitlab"
```
4\. Set the following configuration in your global configuration file:
```toml
[best_practices]
enable_global_best_practices = true
```
???- info "Best practices priority and fallback behavior"
When global best practices are enabled, Qodo Merge follows this priority order:
1\. **Primary**: Global hierarchical best practices from `pr-agent-settings` repository:
1.1 If the repository is mapped in `metadata.yaml`, it uses the specified paths
1.2 For monorepos, it automatically collects best practices matching PR file paths
1.3 If no mapping exists, it falls back to the global best practices
2\. **Fallback**: Local repository `best_practices.md` file:
2.1 Used when global best practices are not found or configured
2.2 Acts as a safety net for repositories not yet configured in the global system
2.3 Local best practices are completely ignored when global best practices are successfully loaded
???- info "Edge cases and behavior"
- **Missing paths**: If specified paths in `metadata.yaml` don't exist in the file system, those paths are skipped
- **Monorepo subproject matching**: For monorepos, Qodo Merge automatically matches PR file paths against subproject paths to apply relevant best practices
- **Multiple group inheritance**: Repositories can inherit from multiple groups, and all applicable best practices are combined
[//]: # (#### Best practices for multiple languages)
[//]: # ()
[//]: # (For a git organization working with multiple programming languages, you can maintain a centralized global `best_practices.md` file containing language-specific guidelines.)
[//]: # (When reviewing pull requests, Qodo Merge automatically identifies the programming language and applies the relevant best practices from this file.)
[//]: # ()
[//]: # (To do this, structure your `best_practices.md` file using the following format:)
[//]: # ()
[//]: # (```)
[//]: # (# [Python])
[//]: # (...)
[//]: # (# [Java])
[//]: # (...)
[//]: # (# [JavaScript])
[//]: # (...)
[//]: # (```)
???- info "Dedicated label for best practices suggestions"
Best practice suggestions are labeled as `Organization best practice` by default.
To customize this label, modify it in your configuration file:
```toml
[best_practices]
organization_name = "..."
```
And the label will be: `{organization_name} best practice`.
#### Example results
![best_practice](https://codium.ai/images/pr_agent/org_best_practice.png){width=512}
![best_practice](https://codium.ai/images/pr_agent/org_best_practice.png){width=512}
### Auto best practices
@ -586,7 +454,7 @@ Note: Chunking is primarily relevant for large PRs. For most PRs (up to 600 line
## Configuration options
???+ example "General options"
??? example "General options"
<table>
<tr>
@ -646,7 +514,7 @@ Note: Chunking is primarily relevant for large PRs. For most PRs (up to 600 line
</tr>
</table>
???+ example "Params for number of suggestions and AI calls"
??? example "Params for number of suggestions and AI calls"
<table>
<tr>

View File

@ -3,23 +3,22 @@
Here is a list of Qodo Merge tools, each with a dedicated page that explains how to use it:
| Tool | Description |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **[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 |
| **[Code Suggestions (`/improve`](./improve.md))** | Code suggestions for improving the PR |
| **[Question Answering (`/ask ...`](./ask.md))** | Answering free-text questions about the PR, or on specific code lines |
| **[Help (`/help`](./help.md))** | Provides a list of all the available tools. Also enables to trigger them interactively (💎) |
| **[Help Docs (`/help_docs`](./help_docs.md))** | Answer a free-text question based on a git documentation folder. |
| **[Update Changelog (`/update_changelog`](./update_changelog.md))** | Automatically updating the CHANGELOG.md file with the PR changes |
| **[Help (`/help`](./help.md))** | Provides a list of all the available tools. Also enables to trigger them interactively (💎) |
| **💎 [Add Documentation (`/add_docs`](./documentation.md))** | Generates documentation to methods/functions/classes that changed in the PR |
| **💎 [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 |
| **💎 [CI Feedback (`/checks ci_job`](./ci_feedback.md))** | Automatically generates feedback and analysis for a failed CI job |
| **💎 [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 Custom Labels (`/generate_labels`](./custom_labels.md))** | Generates custom labels for the PR, based on specific guidelines defined by the user |
| **💎 [Generate Tests (`/test`](./test.md))** | Automatically generates unit tests for a selected component, based on the PR code changes |
| **💎 [Implement (`/implement`](./implement.md))** | Generates implementation code from review suggestions |
| **💎 [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 |
| **💎 [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 |
| **💎 [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 |
| **💎 [Scan Repo Discussions (`/scan_repo_discussions`](./scan_repo_discussions.md))** | Generates `best_practices.md` file based on previous discussions in the repository |
| **💎 [Similar Code (`/similar_code`](./similar_code.md))** | Retrieves the most similar code components from inside the organization's codebase, or from open-source code. |
Note that the tools marked with 💎 are available only for Qodo Merge users.
Note that the tools marked with 💎 are available only for Qodo Merge users.

View File

@ -51,7 +51,7 @@ extra_instructions = "..."
## Configuration options
???+ example "General options"
!!! example "General options"
<table>
<tr>
@ -76,7 +76,7 @@ extra_instructions = "..."
</tr>
</table>
???+ example "Enable\\disable specific sub-sections"
!!! example "Enable\\disable specific sub-sections"
<table>
<tr>
@ -105,7 +105,7 @@ extra_instructions = "..."
</tr>
</table>
???+ example "Adding PR labels"
!!! example "Adding PR labels"
You can enable\disable the `review` tool to add specific labels to the PR:
@ -144,26 +144,16 @@ extra_instructions = "..."
Meaning the `review` tool will run automatically on every PR, without any additional configurations.
Edit this field to enable/disable the tool, or to change the configurations used.
### Auto-generated PR labels by the Review Tool
### Auto-generated PR labels from the Review Tool
!!! tip ""
The `review` can tool automatically add labels to your Pull Requests:
The `review` tool automatically adds two specific labels to your Pull Requests:
- **`possible security issue`**: This label is applied if the tool detects a potential [security vulnerability](https://github.com/qodo-ai/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml#L103) in the PR's code. This feedback is controlled by the 'enable_review_labels_security' flag (default is true).
- **`review effort [x/5]`**: This label estimates the [effort](https://github.com/qodo-ai/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml#L90) required to review the PR on a relative scale of 1 to 5, where 'x' represents the assessed effort. This feedback is controlled by the 'enable_review_labels_effort' flag (default is true).
- **`ticket compliance`**: Adds a label indicating code compliance level ("Fully compliant" | "PR Code Verified" | "Partially compliant" | "Not compliant") to any GitHub/Jira/Linea ticket linked in the PR. Controlled by the 'require_ticket_labels' flag (default: false). If 'require_no_ticket_labels' is also enabled, PRs without ticket links will receive a "No ticket found" label.
- **`possible security issue`**: This label is applied if the tool detects a potential [security vulnerability](https://github.com/qodo-ai/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml#L103) in the PR's code. This feedback is controlled by the 'enable_review_labels_security' flag.
- **`review effort [x/5]`**: This label estimates the [effort](https://github.com/qodo-ai/pr-agent/blob/main/pr_agent/settings/pr_reviewer_prompts.toml#L90) required to review the PR on a relative scale of 1 to 5, where 'x' represents the assessed effort. This feedback is controlled by the 'enable_review_labels_effort' flag.
### Blocking PRs from merging based on the generated labels
!!! tip ""
You can configure a CI/CD Action to prevent merging PRs with specific labels. For example, implement a dedicated [GitHub Action](https://medium.com/sequra-tech/quick-tip-block-pull-request-merge-using-labels-6cc326936221).
This approach helps ensure PRs with potential security issues or ticket compliance problems will not be merged without further review.
Since AI may make mistakes or lack complete context, use this feature judiciously. For flexibility, users with appropriate permissions can remove generated labels when necessary. When a label is removed, this action will be automatically documented in the PR discussion, clearly indicating it was a deliberate override by an authorized user to allow the merge.
Note: The `possible security issue` label highlights potential security risks. You can configure a GitHub Action to [prevent merging](https://medium.com/sequra-tech/quick-tip-block-pull-request-merge-using-labels-6cc326936221) PRs that have this label.
### Extra instructions

View File

@ -249,4 +249,4 @@ ignore_pr_authors = ["my-special-bot-user", ...]
Where the `ignore_pr_authors` is a list of usernames that you want to ignore.
!!! note
There is one specific case where bots will receive an automatic response - when they generated a PR with a _failed test_. In that case, the [`ci_feedback`](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) tool will be invoked.
There is one specific case where bots will receive an automatic response - when they generated a PR with a _failed test_. In that case, the [`ci_feedback`](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) tool will be invoked.

View File

@ -88,7 +88,7 @@ Create a dedicated project to hold a global configuration file that affects all
1. Create a new project with both the name and key: PR_AGENT_SETTINGS.
2. Inside the PR_AGENT_SETTINGS project, create a repository named pr-agent-settings.
3. In this repository, add a `.pr_agent.toml` configuration file—structured similarly to the global configuration file described above.
4. Optionally, you can add organizational-level [global best practices](https://qodo-merge-docs.qodo.ai/tools/improve/#global-hierarchical-best-practices).
4. Optionally, you can add organizational-level [global best practices file](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/#global-configuration-file).
Repositories across your entire Bitbucket organization will inherit the configuration from this file.

View File

@ -25,4 +25,3 @@ It includes information on how to adjust Qodo Merge configurations, define which
- [Patch Extra Lines](./additional_configurations.md#patch-extra-lines)
- [FAQ](https://qodo-merge-docs.qodo.ai/faq/)
- [Qodo Merge Models](./qodo_merge_models)
- [Qodo Merge Endpoints](./qm_endpoints)

View File

@ -1,369 +0,0 @@
# Overview
By default, Qodo Merge processes webhooks that respond to events or comments (for example, PR is opened), posting its responses directly on the PR page.
Qodo Merge now features two CLI endpoints that let you invoke its tools and receive responses directly (both as formatted markdown as well as a raw JSON), rather than having them posted to the PR page:
- **Pull Request Endpoint** - Accepts GitHub PR URL, along with the desired tool to invoke (**note**: only available on-premises, or single tenant).
- **Diff Endpoint** - Git agnostic option that accepts a comparison of two states, either as a list of “before” and “after” files contents, or as a unified diff file, along with the desired tool to invoke.
# Setup
## Enabling desired endpoints (for on-prem deployment)
:bulb: Add the following to your helm chart\secrets file:
Pull Request Endpoint:
```toml
[qm_pull_request_endpoint]
enabled = true
```
Diff Endpoint:
```toml
[qm_diff_endpoint]
enabled = true
```
**Important:** This endpoint can only be enabled through the pod's main secret file, **not** through standard configuration files.
## Access Key
The endpoints require the user to provide an access key in each invocation. Choose one of the following options to retrieve such key.
### Option 1: Endpoint Key (On Premise / Single Tenant only)
Define an endpoint key in the helm chart of your pod configuration:
```toml
[qm_pull_request_endpoint]
enabled = true
endpoint_key = "your-secure-key-here"
```
```toml
[qm_diff_endpoint]
enabled = true
endpoint_key = "your-secure-key-here"
```
### Option 2: API Key for Cloud users (Diff Endpoint only)
Generate a long-lived API key by authenticating the user. We offer two different methods to achieve this:
### - Shell script
Download and run the following script: [gen_api_key.sh](https://github.com/qodo-ai/pr-agent/blob/5dfd696c2b1f43e1d620fe17b9dc10c25c2304f9/pr_agent/scripts/qm_endpoint_auth/gen_api_key.sh)
### - npx
1. Install node
2. Run: `npx @qodo/gen login`
Regardless of which method used, follow the instructions in the opened browser page. Once logged in successfully via the website, the script will return the generated API key:
```toml
Authentication successful! API key saved.
📋 Your API key: ...
```
**Note:** Each login generates a new API key, making any previous ones **obsolete**.
# Available Tools
Both endpoints support the following Qodo Merge tools:
[**Improve**](https://qodo-merge-docs.qodo.ai/tools/improve/) | [**Review**](https://qodo-merge-docs.qodo.ai/tools/review/) | [**Describe**](https://qodo-merge-docs.qodo.ai/tools/describe/) | [**Ask**](https://qodo-merge-docs.qodo.ai/tools/ask/) | [**Add Docs**](https://qodo-merge-docs.qodo.ai/tools/documentation/) | [**Analyze**](https://qodo-merge-docs.qodo.ai/tools/analyze/) | [**Config**](https://qodo-merge-docs.qodo.ai/tools/config/) | [**Generate Labels**](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) | [**Improve Component**](https://qodo-merge-docs.qodo.ai/tools/improve_component/) | [**Test**](https://qodo-merge-docs.qodo.ai/tools/test/) | [**Custom Prompt**](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/)
# How to Run
For all endpoints, there is a need to specify the access key in the header as the value next to the field: “X-API-Key”.
## Pull Request Endpoint
**URL:** `/api/v1/qm_pull_request`
### Request Format
```json
{
"pr_url": "<https://github.com/owner/repo/pull/123>",
"command": "<COMMAND> ARG_1 ARG_2 ..."
}
```
### Usage Examples
### cURL
```bash
curl -X POST "<your-server>/api/v1/qm_pull_request" \\
-H "Content-Type: application/json" \\
-H "X-API-Key: <your-key>"
-d '{
"pr_url": "<https://github.com/owner/repo/pull/123>",
"command": "improve"
}'
```
### Python
```python
import requests
import json
def call_qm_pull_request(pr_url: str, command: str, endpoint_key: str):
url = "<your-server>/api/v1/qm_pull_request"
payload = {
"pr_url": pr_url,
"command": command
}
response = requests.post(
url=url,
headers={"Content-Type": "application/json", "X-API-Key": endpoint_key},
data=json.dumps(payload)
)
if response.status_code == 200:
result = response.json()
response_str = result.get("response_str") # Formatted response
raw_data = result.get("raw_data") # Metadata and suggestions
return response_str, raw_data
else:
print(f"Error: {response.status_code} - {response.text}")
return None, None
```
## Diff Endpoint
**URL:** `/api/v1/qm_diff`
### Request Format
With before and after files contents:
```json
{
"command": "<COMMAND> ARG_1 ARG_2 ...",
"diff_files": {
"<FILE_PATH>": ["<BEFORE_CONTENT>", "<AFTER_CONTENT>"],
"...": ["...", "..."]
}
}
```
Alternatively, with unified diff:
```toml
{
"command": "<COMMAND> ARG_1 ARG_2 ...",
"diff": "<UNIFIED_DIFF_CONTENT>"
}
```
### Example Payloads
**Using before and after per file (recommended):**
```json
{
"command": "improve_component hello",
"diff_files": {
"src/main.py": [
"def hello():\\n print('Hello')",
"def hello():\\n print('Hello World')\\n return 'success'"
]
}
}
```
**Using unified diff:**
```json
{
"command": "improve",
"diff": "diff --git a/src/main.py b/src/main.py\\nindex 123..456 100644\\n--- a/src/main.py\\n+++ b/src/main.py\\n@@ -1,2 +1,3 @@\\n def hello():\\n- print('Hello')\\n+ print('Hello World')\\n+ return 'success'"
}
```
### Usage Examples
### cURL
```bash
curl -X POST "<your-server>/api/v1/qm_diff" \\
-H "X-API-Key: <YOUR_KEY>" \\
-H "Content-Type: application/json" \\
-d @your_request.json
```
### Python
```python
import requests
import json
def call_qm_diff(api_key: str, payload: dict):
url = "<your-server>/api/v1/qm_diff"
response = requests.post(
url=url,
headers={"Content-Type": "application/json", "X-API-Key": api_key},
data=json.dumps(payload)
)
if response.status_code == 200:
result = response.json()
markdown_result = result.get("response_str") # Formatted markdown
raw_data = result.get("raw_data") # Metadata and suggestions
return markdown_result, raw_data
else:
print(f"Error: {response.status_code} - {response.text}")
return None, None
```
# Response Format
Both endpoints return identical JSON structure:
```json
{
"response_str": "## PR Code Suggestions ✨\n\n<table>...",
"raw_data": {
<FIELD>: <VALUE>
}
}
```
- **`response_str`** - Formatted markdown for display
- **`raw_data`** - Structured data with detailed suggestions and metadata, if applicable
# Complete Workflows Examples
### Pull Request Endpoint
Given the following “/improve” request:
```toml
{
"command": "improve",
"pr_url": "https://github.com/qodo-ai/pr-agent/pull/1831"
}
```
Received the following response:
```toml
{"response_str":"## PR Code Suggestions ✨\n\n<table><thead><tr><td><strong>Category
</strong></td><td align=left><strong>Suggestion&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong></td><td align=center>
<strong>Impact</strong></td></tr><tbody><tr><td rowspan=1>Learned<br>best practice</td>
\n<td>\n\n\n\n<details><summary>Improve documentation clarity</summary>\n\n___\n
\n\n**The documentation parameter description contains a grammatical issue.
The <br>sentence \"This field remains empty if not applicable\" is unclear in context
and <br>should be clarified to better explain what happens when the feature is not
<br>applicable.**\n\n[docs/docs/tools/describe.md [128-129]]
(https://github.com/qodo-ai/pr-agent/pull/1831/files#diff-960aad71fec9617804a02c904da37db217b6ba8a48fec3ac8bda286511d534ebR128-R129)
\n\n```diff\n <td><b>enable_pr_diagram</b></td>\n-<td>If set to true, the tool
will generate a horizontal Mermaid flowchart summarizing the main pull request
changes. This field remains empty if not applicable. Default is false.</td>\n
+<td>If set to true, the tool will generate a horizontal Mermaid flowchart
summarizing the main pull request changes. No diagram will be generated if
changes cannot be effectively visualized. Default is false.</td>\n```\n\n
- [ ] **Apply / Chat** <!-- /improve --apply_suggestion=0 -->\n\n<details>
<summary>Suggestion importance[1-10]: 6</summary>\n\n__\n\nWhy: \nRelevant
best practice - Fix grammatical errors and typos in user-facing documentation
to maintain professionalism and clarity.\n\n</details></details></td><td
align=center>Low\n\n</td></tr>\n<tr><td align=\"center\" colspan=\"2\">\n\n
- [ ] More <!-- /improve --more_suggestions=true -->\n\n</td><td></td></tr>
</tbody></table>","raw_data":{"code_suggestions":[{"relevant_file":
"docs/docs/tools/describe.md\n","language":"markdown\n","relevant_best_practice":
"Fix grammatical errors and typos in user-facing documentation to maintain
professionalism and clarity.\n","existing_code":"<td><b>enable_pr_diagram</b>
</td>\n<td>If set to true, the tool will generate a horizontal Mermaid flowchart
summarizing the main pull request changes. This field remains empty if not applicable.
Default is false.</td>\n","suggestion_content":"The documentation parameter description
contains a grammatical issue. The sentence \"This field remains empty if not applicable\"
is unclear in context and should be clarified to better explain what happens when the
feature is not applicable.\n","improved_code":"<td><b>enable_pr_diagram</b></td>
\n<td>If set to true, the tool will generate a horizontal Mermaid flowchart summarizing
the main pull request changes. No diagram will be generated if changes cannot be effectively
visualized. Default is false.</td>\n","one_sentence_summary":"Improve documentation clarity\n",
"score":6,"score_why":"\nRelevant best practice - Fix grammatical errors and typos in
user-facing documentation to maintain professionalism and clarity.","label":"Learned best practice",
"relevant_lines_start":128,"relevant_lines_end":129,"enable_apply":true}]}}
```
In case user has failed authentication, due to not enabling the endpoint in the helm chart:
```toml
HTTP/1.1 400 Bad Request
date: Tue, 03 Jun 2025 09:40:21 GMT
server: uvicorn
content-length: 3486
content-type: application/json
{"detail":{"error":"QM Pull Request endpoint is not enabled"}}
```
### Diff Endpoint
Given the following “/improve” requests payload:
[improve_example_short.json](https://codium.ai/images/pr_agent/improve_example_short.json)
Received the following response:
```toml
{"response_str":"## PR Code Suggestions ✨\n\n<table><thead><tr><td><strong>Category</strong></td><td align=left><strong>Suggestion                                                                                                                                   
</strong></td><td align=center><strong>Impact</strong></td></tr><tbody><tr><td rowspan=1>Possible issue</td>\n<td>\n\n\n\n<details>
<summary>Fix invalid repository URL</summary>\n\n___\n\n\n**The <code>base_branch</code> is set to <code>None</code> but then used
in the <code>repo_url</code> string <br>interpolation, which will cause a runtime error. Also, the repository URL format <br>is incorrect
as it includes the branch in the middle of the organization/repo <br>path.**\n\n[tests/e2e_tests/test_github_app.py [1]]
(file://tests/e2e_tests/test_github_app.py#L1-1)\n\ndiff\\n-base_branch = None\\n+base_branch = \\"main\\" # or any base branch you want\\n
new_branch = f\\"github_app_e2e_test-{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}-where-am-I\\"\\n-repo_url =
f'Codium-ai/{base_branch}/pr-agent-tests'\\n+repo_url = 'Codium-ai/pr-agent-tests'\\n\n<details><summary>Suggestion importance[1-10]: 9</summary>
\n\n__\n\nWhy: The suggestion correctly identifies a critical runtime bug where base_branch = None is used in string interpolation,
which would produce an invalid repository URL Codium-ai/None/pr-agent-tests. This would cause the test to fail at runtime.\n\n\n</details></details>
</td><td align=center>High\n\n</td></tr></tbody></table>",
"raw_data":{"code_suggestions":[{"relevant_file":"tests/e2e_tests/test_github_app.py\n",
"language":"python\n","existing_code":"base_branch = None\nnew_branch = f\"github_app_e2e_test-{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}
-where-am-I\"\nrepo_url = f'Codium-ai/{base_branch}/pr-agent-tests'\n","suggestion_content":"The base_branch is set to None but then used in the
repo_url string interpolation, which will cause a runtime error. Also, the repository URL format is incorrect as it includes the branch in the middle
of the organization/repo path.\n","improved_code":"base_branch = \"main\" # or any base branch you want\nnew_branch = f\"github_app_e2e_test-
{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}-where-am-I\"\nrepo_url = 'Codium-ai/pr-agent-tests'\n","one_sentence_summary":"Fix invalid repository
URL\n","label":"possible issue","score":9,"score_why":"The suggestion correctly identifies a critical runtime bug where base_branch = None is used in
string interpolation, which would produce an invalid repository URL Codium-ai/None/pr-agent-tests. This would cause the test to fail at runtime.\n",
"relevant_lines_start":1,"relevant_lines_end":1,"enable_apply":false}]}}
```
In case user has failed authentication:
```toml
HTTP/1.1 400 Bad Request
date: Tue, 03 Jun 2025 08:45:36 GMT
server: uvicorn
content-length: 43
content-type: application/json
{"detail":{"error":"Invalid API key"}}
```
# Appendix: Endpoints Comparison Table
| **Feature** | **Pull Request Endpoint** | **Diff Endpoint** |
| --- | --- | --- |
| **Input** | GitHub PR URL | File diffs / Unified diff |
| **Git Provider** | GitHub only | N/A |
| **Deployment** | On-premise/Single Tenant | All deployments |
| **Authentication** | Endpoint key only | Endpoint key or API key |

View File

@ -22,26 +22,25 @@ nav:
- Additional Configurations: 'usage-guide/additional_configurations.md'
- Frequently Asked Questions: 'faq/index.md'
- 💎 Qodo Merge Models: 'usage-guide/qodo_merge_models.md'
- 💎 Qodo Merge Endpoints: 'usage-guide/qm_endpoints.md'
- Tools:
- 'tools/index.md'
- Describe: 'tools/describe.md'
- Review: 'tools/review.md'
- Improve: 'tools/improve.md'
- Ask: 'tools/ask.md'
- Help: 'tools/help.md'
- Help Docs: 'tools/help_docs.md'
- Update Changelog: 'tools/update_changelog.md'
- 💎 Add Documentation: 'tools/documentation.md'
- 💎 Analyze: 'tools/analyze.md'
- 💎 CI Feedback: 'tools/ci_feedback.md'
- 💎 Custom Prompt: 'tools/custom_prompt.md'
- 💎 Generate Labels: 'tools/custom_labels.md'
- 💎 Generate Tests: 'tools/test.md'
- 💎 Implement: 'tools/implement.md'
- 💎 Improve Components: 'tools/improve_component.md'
- 💎 Scan Repo Discussions: 'tools/scan_repo_discussions.md'
- 💎 Similar Code: 'tools/similar_code.md'
- 'tools/index.md'
- Describe: 'tools/describe.md'
- Review: 'tools/review.md'
- Improve: 'tools/improve.md'
- Ask: 'tools/ask.md'
- Update Changelog: 'tools/update_changelog.md'
- Help Docs: 'tools/help_docs.md'
- Help: 'tools/help.md'
- 💎 Analyze: 'tools/analyze.md'
- 💎 Test: 'tools/test.md'
- 💎 Improve Component: 'tools/improve_component.md'
- 💎 Documentation: 'tools/documentation.md'
- 💎 Custom Labels: 'tools/custom_labels.md'
- 💎 Custom Prompt: 'tools/custom_prompt.md'
- 💎 CI Feedback: 'tools/ci_feedback.md'
- 💎 Similar Code: 'tools/similar_code.md'
- 💎 Implement: 'tools/implement.md'
- 💎 Scan Repo Discussions: 'tools/scan_repo_discussions.md'
- Core Abilities:
- 'core-abilities/index.md'
- Auto best practices: 'core-abilities/auto_best_practices.md'

View File

@ -61,7 +61,6 @@ MAX_TOKENS = {
'vertex_ai/gemini-1.5-pro': 1048576,
'vertex_ai/gemini-2.5-pro-preview-03-25': 1048576,
'vertex_ai/gemini-2.5-pro-preview-05-06': 1048576,
'vertex_ai/gemini-2.5-pro-preview-06-05': 1048576,
'vertex_ai/gemini-1.5-flash': 1048576,
'vertex_ai/gemini-2.0-flash': 1048576,
'vertex_ai/gemini-2.5-flash-preview-04-17': 1048576,
@ -74,7 +73,6 @@ MAX_TOKENS = {
'gemini/gemini-2.5-flash-preview-05-20': 1048576,
'gemini/gemini-2.5-pro-preview-03-25': 1048576,
'gemini/gemini-2.5-pro-preview-05-06': 1048576,
'gemini/gemini-2.5-pro-preview-06-05': 1048576,
'codechat-bison': 6144,
'codechat-bison-32k': 32000,
'anthropic.claude-instant-v1': 100000,
@ -103,9 +101,6 @@ MAX_TOKENS = {
"bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0": 100000,
"bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0": 200000,
"bedrock/us.anthropic.claude-sonnet-4-20250514-v1:0": 200000,
"bedrock/apac.anthropic.claude-3-5-sonnet-20241022-v2:0": 100000,
"bedrock/apac.anthropic.claude-3-7-sonnet-20250219-v1:0": 200000,
"bedrock/apac.anthropic.claude-sonnet-4-20250514-v1:0": 200000,
'claude-3-5-sonnet': 100000,
'groq/meta-llama/llama-4-scout-17b-16e-instruct': 131072,
'groq/meta-llama/llama-4-maverick-17b-128e-instruct': 131072,

View File

@ -81,62 +81,3 @@ def _find_pyproject() -> Optional[Path]:
pyproject_path = _find_pyproject()
if pyproject_path is not None:
get_settings().load_file(pyproject_path, env=f'tool.{PR_AGENT_TOML_KEY}')
def apply_secrets_manager_config():
"""
Retrieve configuration from AWS Secrets Manager and override existing settings
"""
try:
# Dynamic imports to avoid circular dependency (secret_providers imports config_loader)
from pr_agent.secret_providers import get_secret_provider
from pr_agent.log import get_logger
secret_provider = get_secret_provider()
if not secret_provider:
return
if (hasattr(secret_provider, 'get_all_secrets') and
get_settings().get("CONFIG.SECRET_PROVIDER") == 'aws_secrets_manager'):
try:
secrets = secret_provider.get_all_secrets()
if secrets:
apply_secrets_to_config(secrets)
get_logger().info("Applied AWS Secrets Manager configuration")
except Exception as e:
get_logger().error(f"Failed to apply AWS Secrets Manager config: {e}")
except Exception as e:
try:
from pr_agent.log import get_logger
get_logger().debug(f"Secret provider not configured: {e}")
except:
# Fail completely silently if log module is not available
pass
def apply_secrets_to_config(secrets: dict):
"""
Apply secret dictionary to configuration
"""
try:
# Dynamic import to avoid potential circular dependency
from pr_agent.log import get_logger
except:
def get_logger():
class DummyLogger:
def debug(self, msg): pass
return DummyLogger()
for key, value in secrets.items():
if '.' in key: # nested key like "openai.key"
parts = key.split('.')
if len(parts) == 2:
section, setting = parts
section_upper = section.upper()
setting_upper = setting.upper()
# Set only when no existing value (prioritize environment variables)
current_value = get_settings().get(f"{section_upper}.{setting_upper}")
if current_value is None or current_value == "":
get_settings().set(f"{section_upper}.{setting_upper}", value)
get_logger().debug(f"Set {section}.{setting} from AWS Secrets Manager")

View File

@ -409,7 +409,7 @@ class GiteaProvider(GitProvider):
def _get_file_content_from_base(self, filename: str) -> str:
return self.repo_api.get_file_content(
owner=self.owner,
repo=self.repo,
repo=self.base_ref,
commit_sha=self.base_sha,
filepath=filename
)
@ -417,7 +417,7 @@ class GiteaProvider(GitProvider):
def _get_file_content_from_latest_commit(self, filename: str) -> str:
return self.repo_api.get_file_content(
owner=self.owner,
repo=self.repo,
repo=self.base_ref,
commit_sha=self.last_commit.sha,
filepath=filename
)
@ -471,11 +471,11 @@ class GiteaProvider(GitProvider):
if status == 'added':
edit_type = EDIT_TYPE.ADDED
elif status == 'removed' or status == 'deleted':
elif status == 'removed':
edit_type = EDIT_TYPE.DELETED
elif status == 'renamed':
edit_type = EDIT_TYPE.RENAMED
elif status == 'modified' or status == 'changed':
elif status == 'modified':
edit_type = EDIT_TYPE.MODIFIED
else:
self.logger.error(f"Unknown edit type: {status}")

View File

@ -0,0 +1,60 @@
import requests
import json
import webbrowser
BASE_URL="https://api.cli.qodo.ai"
QM_CMD_ENDPOINT_KEY_NAME="qm_cmd_endpoint"
def get_api_key():
try:
url = f"{BASE_URL}/v1/auth/cli-auth?key_name={QM_CMD_ENDPOINT_KEY_NAME}"
# Make HTTP request
response = requests.get(url, stream=True, # For SSE (Server-Sent Events)
headers={'Accept': 'text/event-stream'})
# Parse Server-Sent Events format
# Look for line:
# data: {"auth_url":"https:\/\/auth.qodo.ai\/?extensionId=Codium.codium&extensionQuery=<SOME UUID>&uriScheme=cli"}
opened_auth_url = False
for line in response.iter_lines(decode_unicode=True):
if line and line.startswith('data:'):
data_json = line.replace('data: ', '', 1)
try:
data = json.loads(data_json)
if not opened_auth_url:
if 'auth_url' not in data:
print(f"Expected an auth_url, but couldn't find one.")
return None
print(f"Got url: {data['auth_url']}.")
# Unescape the URL
auth_url = data['auth_url'].replace('\\/', '/')
webbrowser.open(auth_url)
opened_auth_url = True
else:
api_key = data.get('api_key', None)
print(f"Got api key: {api_key}.")
if not api_key:
print(f"Expected an api_key, but couldn't find one.")
return api_key
except json.JSONDecodeError as e:
print(f"Error parsing JSON: {e}")
return None
print("No data line found in response")
return None
except requests.exceptions.RequestException as e:
print(f"Error making HTTP request: {e}")
return None
def run():
"""This is the function serving as this file's entry point, as defined in pyproject.toml"""
print("Attempting to generate an API Key...")
api_key = get_api_key()
if api_key:
print(f"Please use the following API Key: {api_key} when invoking QM endpoint.")
print(f"For example: curl -i --header \"Authorization: ApiKey {api_key}\" -X POST https://<QM ENDPOINT SERVER ADDR>/api/v1/qodo_merge_cmd")
if __name__ == "__main__":
run()

View File

@ -0,0 +1,4 @@
curl -s --no-buffer "https://api.cli.qodo.ai/v1/auth/cli-auth" | while read line; do
[[ $line == data:*auth_url* ]] && open "$(echo "$line" | sed 's/.*"auth_url":"\([^"]*\)".*/\1/' | sed 's/\\//g')"
[[ $line == data:*api_key* ]] && echo "✅ Authentication successful! API key saved.\n📋 Your API key: $(echo "$line" | sed 's/.*"api_key":"\([^"]*\)".*/\1/')" && break
done

View File

@ -13,12 +13,5 @@ def get_secret_provider():
return GoogleCloudStorageSecretProvider()
except Exception as e:
raise ValueError(f"Failed to initialize google_cloud_storage secret provider {provider_id}") from e
elif provider_id == 'aws_secrets_manager':
try:
from pr_agent.secret_providers.aws_secrets_manager_provider import \
AWSSecretsManagerProvider
return AWSSecretsManagerProvider()
except Exception as e:
raise ValueError(f"Failed to initialize aws_secrets_manager secret provider {provider_id}") from e
else:
raise ValueError("Unknown SECRET_PROVIDER")

View File

@ -1,57 +0,0 @@
import json
import boto3
from botocore.exceptions import ClientError
from pr_agent.config_loader import get_settings
from pr_agent.log import get_logger
from pr_agent.secret_providers.secret_provider import SecretProvider
class AWSSecretsManagerProvider(SecretProvider):
def __init__(self):
try:
region_name = get_settings().get("aws_secrets_manager.region_name") or \
get_settings().get("aws.AWS_REGION_NAME")
if region_name:
self.client = boto3.client('secretsmanager', region_name=region_name)
else:
self.client = boto3.client('secretsmanager')
self.secret_arn = get_settings().get("aws_secrets_manager.secret_arn")
if not self.secret_arn:
raise ValueError("AWS Secrets Manager ARN is not configured")
except Exception as e:
get_logger().error(f"Failed to initialize AWS Secrets Manager Provider: {e}")
raise e
def get_secret(self, secret_name: str) -> str:
"""
Retrieve individual secret by name (for webhook tokens)
"""
try:
response = self.client.get_secret_value(SecretId=secret_name)
return response['SecretString']
except Exception as e:
get_logger().warning(f"Failed to get secret {secret_name} from AWS Secrets Manager: {e}")
return ""
def get_all_secrets(self) -> dict:
"""
Retrieve all secrets for configuration override
"""
try:
response = self.client.get_secret_value(SecretId=self.secret_arn)
return json.loads(response['SecretString'])
except Exception as e:
get_logger().error(f"Failed to get secrets from AWS Secrets Manager {self.secret_arn}: {e}")
return {}
def store_secret(self, secret_name: str, secret_value: str):
try:
self.client.put_secret_value(
SecretId=secret_name,
SecretString=secret_value
)
except Exception as e:
get_logger().error(f"Failed to store secret {secret_name} in AWS Secrets Manager: {e}")
raise e

View File

@ -30,9 +30,5 @@
"url": "/webhook"
}
]
},
"links": {
"privacy": "https://qodo.ai/privacy-policy",
"terms": "https://qodo.ai/terms"
}
}

View File

@ -5,17 +5,6 @@ from starlette_context.middleware import RawContextMiddleware
from pr_agent.servers.github_app import router
try:
from pr_agent.config_loader import apply_secrets_manager_config
apply_secrets_manager_config()
except Exception as e:
try:
from pr_agent.log import get_logger
get_logger().debug(f"AWS Secrets Manager initialization failed, falling back to environment variables: {e}")
except:
# Fail completely silently if log module is not available
pass
middleware = [Middleware(RawContextMiddleware)]
app = FastAPI(middleware=middleware)
app.include_router(router)

View File

@ -121,8 +121,4 @@ api_base = ""
[aws]
AWS_ACCESS_KEY_ID = ""
AWS_SECRET_ACCESS_KEY = ""
AWS_REGION_NAME = ""
[aws_secrets_manager]
secret_arn = "" # The ARN of the AWS Secrets Manager secret containing PR-Agent configuration
region_name = "" # Optional: specific AWS region (defaults to AWS_REGION_NAME or Lambda region)
AWS_REGION_NAME = ""

View File

@ -39,7 +39,7 @@ allow_dynamic_context=true
max_extra_lines_before_dynamic_context = 10 # will try to include up to 10 extra lines before the hunk in the patch, until we reach an enclosing function or class
patch_extra_lines_before = 5 # Number of extra lines (+3 default ones) to include before each hunk in the patch
patch_extra_lines_after = 1 # Number of extra lines (+3 default ones) to include after each hunk in the patch
secret_provider="" # "" (disabled), "google_cloud_storage", or "aws_secrets_manager" for secure secret management
secret_provider=""
cli_mode=false
ai_disclaimer_title="" # Pro feature, title for a collapsible disclaimer to AI outputs
ai_disclaimer="" # Pro feature, full text for the AI disclaimer

View File

@ -44,6 +44,7 @@ include = [
[project.scripts]
pr-agent = "pr_agent.cli:run"
gen-api-key = "pr_agent.scripts.qm_endpoint_auth.gen_api_key:run"
[tool.ruff]
line-length = 120

View File

@ -1,89 +0,0 @@
import json
import pytest
from unittest.mock import MagicMock, patch
from botocore.exceptions import ClientError
from pr_agent.secret_providers.aws_secrets_manager_provider import AWSSecretsManagerProvider
class TestAWSSecretsManagerProvider:
def _provider(self):
"""Create provider following existing pattern"""
with patch('pr_agent.secret_providers.aws_secrets_manager_provider.get_settings') as mock_get_settings, \
patch('pr_agent.secret_providers.aws_secrets_manager_provider.boto3.client') as mock_boto3_client:
settings = MagicMock()
settings.get.side_effect = lambda k, d=None: {
'aws_secrets_manager.secret_arn': 'arn:aws:secretsmanager:us-east-1:123456789012:secret:test-secret',
'aws_secrets_manager.region_name': 'us-east-1',
'aws.AWS_REGION_NAME': 'us-east-1'
}.get(k, d)
settings.aws_secrets_manager.secret_arn = 'arn:aws:secretsmanager:us-east-1:123456789012:secret:test-secret'
mock_get_settings.return_value = settings
# Mock boto3 client
mock_client = MagicMock()
mock_boto3_client.return_value = mock_client
provider = AWSSecretsManagerProvider()
provider.client = mock_client # Set client directly for testing
return provider, mock_client
# Positive test cases
def test_get_secret_success(self):
provider, mock_client = self._provider()
mock_client.get_secret_value.return_value = {'SecretString': 'test-secret-value'}
result = provider.get_secret('test-secret-name')
assert result == 'test-secret-value'
mock_client.get_secret_value.assert_called_once_with(SecretId='test-secret-name')
def test_get_all_secrets_success(self):
provider, mock_client = self._provider()
secret_data = {'openai.key': 'sk-test', 'github.webhook_secret': 'webhook-secret'}
mock_client.get_secret_value.return_value = {'SecretString': json.dumps(secret_data)}
result = provider.get_all_secrets()
assert result == secret_data
# Negative test cases (following Google Cloud Storage pattern)
def test_get_secret_failure(self):
provider, mock_client = self._provider()
mock_client.get_secret_value.side_effect = Exception("AWS error")
result = provider.get_secret('nonexistent-secret')
assert result == "" # Confirm empty string is returned
def test_get_all_secrets_failure(self):
provider, mock_client = self._provider()
mock_client.get_secret_value.side_effect = Exception("AWS error")
result = provider.get_all_secrets()
assert result == {} # Confirm empty dictionary is returned
def test_store_secret_update_existing(self):
provider, mock_client = self._provider()
mock_client.update_secret.return_value = {}
provider.store_secret('test-secret', 'test-value')
mock_client.put_secret_value.assert_called_once_with(
SecretId='test-secret',
SecretString='test-value'
)
def test_init_failure_invalid_config(self):
with patch('pr_agent.secret_providers.aws_secrets_manager_provider.get_settings') as mock_get_settings:
settings = MagicMock()
settings.aws_secrets_manager.secret_arn = None # Configuration error
mock_get_settings.return_value = settings
with pytest.raises(Exception):
AWSSecretsManagerProvider()
def test_store_secret_failure(self):
provider, mock_client = self._provider()
mock_client.put_secret_value.side_effect = Exception("AWS error")
with pytest.raises(Exception):
provider.store_secret('test-secret', 'test-value')

View File

@ -1,120 +0,0 @@
import pytest
from unittest.mock import MagicMock, patch
from pr_agent.config_loader import apply_secrets_manager_config, apply_secrets_to_config
class TestConfigLoaderSecrets:
def test_apply_secrets_manager_config_success(self):
with patch('pr_agent.secret_providers.get_secret_provider') as mock_get_provider, \
patch('pr_agent.config_loader.apply_secrets_to_config') as mock_apply_secrets, \
patch('pr_agent.config_loader.get_settings') as mock_get_settings:
# Mock secret provider
mock_provider = MagicMock()
mock_provider.get_all_secrets.return_value = {'openai.key': 'sk-test'}
mock_get_provider.return_value = mock_provider
# Mock settings
settings = MagicMock()
settings.get.return_value = "aws_secrets_manager"
mock_get_settings.return_value = settings
apply_secrets_manager_config()
mock_apply_secrets.assert_called_once_with({'openai.key': 'sk-test'})
def test_apply_secrets_manager_config_no_provider(self):
with patch('pr_agent.secret_providers.get_secret_provider') as mock_get_provider:
mock_get_provider.return_value = None
# Confirm no exception is raised
apply_secrets_manager_config()
def test_apply_secrets_manager_config_not_aws(self):
with patch('pr_agent.secret_providers.get_secret_provider') as mock_get_provider, \
patch('pr_agent.config_loader.get_settings') as mock_get_settings:
# Mock Google Cloud Storage provider
mock_provider = MagicMock()
mock_get_provider.return_value = mock_provider
# Mock settings (Google Cloud Storage)
settings = MagicMock()
settings.get.return_value = "google_cloud_storage"
mock_get_settings.return_value = settings
# Confirm execution is skipped for non-AWS Secrets Manager
apply_secrets_manager_config()
# Confirm get_all_secrets is not called
assert not hasattr(mock_provider, 'get_all_secrets') or \
not mock_provider.get_all_secrets.called
def test_apply_secrets_to_config_nested_keys(self):
with patch('pr_agent.config_loader.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = None # No existing value
settings.set = MagicMock()
mock_get_settings.return_value = settings
secrets = {
'openai.key': 'sk-test',
'github.webhook_secret': 'webhook-secret'
}
apply_secrets_to_config(secrets)
# Confirm settings are applied correctly
settings.set.assert_any_call('OPENAI.KEY', 'sk-test')
settings.set.assert_any_call('GITHUB.WEBHOOK_SECRET', 'webhook-secret')
def test_apply_secrets_to_config_existing_value_preserved(self):
with patch('pr_agent.config_loader.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = "existing-value" # Existing value present
settings.set = MagicMock()
mock_get_settings.return_value = settings
secrets = {'openai.key': 'sk-test'}
apply_secrets_to_config(secrets)
# Confirm settings are not overridden when existing value present
settings.set.assert_not_called()
def test_apply_secrets_to_config_single_key(self):
with patch('pr_agent.config_loader.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = None
settings.set = MagicMock()
mock_get_settings.return_value = settings
secrets = {'simple_key': 'simple_value'}
apply_secrets_to_config(secrets)
# Confirm non-dot notation keys are ignored
settings.set.assert_not_called()
def test_apply_secrets_to_config_multiple_dots(self):
with patch('pr_agent.config_loader.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = None
settings.set = MagicMock()
mock_get_settings.return_value = settings
secrets = {'section.subsection.key': 'value'}
apply_secrets_to_config(secrets)
# Confirm keys with multiple dots are ignored
settings.set.assert_not_called()
def test_apply_secrets_manager_config_exception_handling(self):
with patch('pr_agent.secret_providers.get_secret_provider') as mock_get_provider:
mock_get_provider.side_effect = Exception("Provider error")
# Confirm processing continues even when exception occurs
apply_secrets_manager_config() # Confirm no exception is raised

View File

@ -1,69 +0,0 @@
import pytest
from unittest.mock import MagicMock, patch
from pr_agent.secret_providers import get_secret_provider
class TestSecretProviderFactory:
def test_get_secret_provider_none_when_not_configured(self):
with patch('pr_agent.secret_providers.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = None
mock_get_settings.return_value = settings
result = get_secret_provider()
assert result is None
def test_get_secret_provider_google_cloud_storage(self):
with patch('pr_agent.secret_providers.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = "google_cloud_storage"
settings.config.secret_provider = "google_cloud_storage"
mock_get_settings.return_value = settings
with patch('pr_agent.secret_providers.google_cloud_storage_secret_provider.GoogleCloudStorageSecretProvider') as MockProvider:
mock_instance = MagicMock()
MockProvider.return_value = mock_instance
result = get_secret_provider()
assert result is mock_instance
MockProvider.assert_called_once()
def test_get_secret_provider_aws_secrets_manager(self):
with patch('pr_agent.secret_providers.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = "aws_secrets_manager"
settings.config.secret_provider = "aws_secrets_manager"
mock_get_settings.return_value = settings
with patch('pr_agent.secret_providers.aws_secrets_manager_provider.AWSSecretsManagerProvider') as MockProvider:
mock_instance = MagicMock()
MockProvider.return_value = mock_instance
result = get_secret_provider()
assert result is mock_instance
MockProvider.assert_called_once()
def test_get_secret_provider_unknown_provider(self):
with patch('pr_agent.secret_providers.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = "unknown_provider"
settings.config.secret_provider = "unknown_provider"
mock_get_settings.return_value = settings
with pytest.raises(ValueError, match="Unknown SECRET_PROVIDER"):
get_secret_provider()
def test_get_secret_provider_initialization_error(self):
with patch('pr_agent.secret_providers.get_settings') as mock_get_settings:
settings = MagicMock()
settings.get.return_value = "aws_secrets_manager"
settings.config.secret_provider = "aws_secrets_manager"
mock_get_settings.return_value = settings
with patch('pr_agent.secret_providers.aws_secrets_manager_provider.AWSSecretsManagerProvider') as MockProvider:
MockProvider.side_effect = Exception("Initialization failed")
with pytest.raises(ValueError, match="Failed to initialize aws_secrets_manager secret provider"):
get_secret_provider()