mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-06 13:50:44 +08:00
Compare commits
2 Commits
es/add_qm_
...
es/api_key
Author | SHA1 | Date | |
---|---|---|---|
72ad76692b | |||
5dfd696c2b |
172
README.md
172
README.md
@ -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/
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
{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>
|
||||
{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.
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 Merge’s 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.
|
||||
|
@ -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).
|
||||
|
@ -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.
|
@ -73,7 +73,7 @@ enable_pr_diagram = true
|
||||
|
||||
## Configuration options
|
||||
|
||||
???+ example "Possible configurations"
|
||||
!!! example "Possible configurations"
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
||||
{width=512}
|
||||
{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>
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</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” request’s 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 |
|
@ -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'
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
|
@ -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}")
|
||||
|
60
pr_agent/scripts/qm_endpoint_auth/gen_api_key.py
Normal file
60
pr_agent/scripts/qm_endpoint_auth/gen_api_key.py
Normal 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()
|
4
pr_agent/scripts/qm_endpoint_auth/gen_api_key.sh
Normal file
4
pr_agent/scripts/qm_endpoint_auth/gen_api_key.sh
Normal 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
|
@ -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")
|
||||
|
@ -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
|
@ -30,9 +30,5 @@
|
||||
"url": "/webhook"
|
||||
}
|
||||
]
|
||||
},
|
||||
"links": {
|
||||
"privacy": "https://qodo.ai/privacy-policy",
|
||||
"terms": "https://qodo.ai/terms"
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 = ""
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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')
|
@ -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
|
@ -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()
|
Reference in New Issue
Block a user