mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-03 20:30:41 +08:00
Merge pull request #1811 from loolootech/feature/gitea-implement
[Feature] - Gitea implement
This commit is contained in:
82
README.md
82
README.md
@ -70,47 +70,47 @@ Read more about it [here](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discus
|
|||||||
|
|
||||||
Supported commands per platform:
|
Supported commands per platform:
|
||||||
|
|
||||||
| | | GitHub | GitLab | Bitbucket | Azure DevOps |
|
| | | GitHub | GitLab | Bitbucket | Azure DevOps | Gitea |
|
||||||
| ----- |---------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|
|
| ----- |---------------------------------------------------------------------------------------------------------|:------:|:------:|:---------:|:------------:|:-----:|
|
||||||
| TOOLS | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ |
|
| TOOLS | [Review](https://qodo-merge-docs.qodo.ai/tools/review/) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Describe](https://qodo-merge-docs.qodo.ai/tools/describe/) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Improve](https://qodo-merge-docs.qodo.ai/tools/improve/) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Ask](https://qodo-merge-docs.qodo.ai/tools/ask/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | ⮑ [Ask on code lines](https://qodo-merge-docs.qodo.ai/tools/ask/#ask-lines) | ✅ | ✅ | | |
|
| | ⮑ [Ask on code lines](https://qodo-merge-docs.qodo.ai/tools/ask/#ask-lines) | ✅ | ✅ | | | |
|
||||||
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Update CHANGELOG](https://qodo-merge-docs.qodo.ai/tools/update_changelog/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | [Help Docs](https://qodo-merge-docs.qodo.ai/tools/help_docs/?h=auto#auto-approval) | ✅ | ✅ | ✅ | |
|
| | [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/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Ticket Context](https://qodo-merge-docs.qodo.ai/core-abilities/fetching_ticket_context/) 💎 | ✅ | ✅ | ✅ | | |
|
||||||
| | [Utilizing Best Practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) 💎 | ✅ | ✅ | ✅ | |
|
| | [Utilizing Best Practices](https://qodo-merge-docs.qodo.ai/tools/improve/#best-practices) 💎 | ✅ | ✅ | ✅ | | |
|
||||||
| | [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) 💎 | ✅ | | | |
|
| | [PR Chat](https://qodo-merge-docs.qodo.ai/chrome-extension/features/#pr-chat) 💎 | ✅ | | | | |
|
||||||
| | [Suggestion Tracking](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking) 💎 | ✅ | ✅ | | |
|
| | [Suggestion Tracking](https://qodo-merge-docs.qodo.ai/tools/improve/#suggestion-tracking) 💎 | ✅ | ✅ | | | |
|
||||||
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | |
|
| | [CI Feedback](https://qodo-merge-docs.qodo.ai/tools/ci_feedback/) 💎 | ✅ | | | | |
|
||||||
| | [PR Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | |
|
| | [PR Documentation](https://qodo-merge-docs.qodo.ai/tools/documentation/) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | |
|
| | [Custom Labels](https://qodo-merge-docs.qodo.ai/tools/custom_labels/) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | |
|
| | [Analyze](https://qodo-merge-docs.qodo.ai/tools/analyze/) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | |
|
| | [Similar Code](https://qodo-merge-docs.qodo.ai/tools/similar_code/) 💎 | ✅ | | | | |
|
||||||
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Custom Prompt](https://qodo-merge-docs.qodo.ai/tools/custom_prompt/) 💎 | ✅ | ✅ | ✅ | | |
|
||||||
| | [Test](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | |
|
| | [Test](https://qodo-merge-docs.qodo.ai/tools/test/) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | ✅ | |
|
| | [Implement](https://qodo-merge-docs.qodo.ai/tools/implement/) 💎 | ✅ | ✅ | ✅ | | |
|
||||||
| | [Scan Repo Discussions](https://qodo-merge-docs.qodo.ai/tools/scan_repo_discussions/) 💎 | ✅ | | | |
|
| | [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) 💎 | ✅ | ✅ | ✅ | |
|
| | [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) | ✅ | ✅ | ✅ | ✅ |
|
| USAGE | [CLI](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#local-repo-cli) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [App / webhook](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-app) | ✅ | ✅ | ✅ | ✅ |
|
| | [App / webhook](https://qodo-merge-docs.qodo.ai/usage-guide/automations_and_usage/#github-app) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| | [Tagging bot](https://github.com/Codium-ai/pr-agent#try-it-now) | ✅ | | | |
|
| | [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) | ✅ | ✅ | ✅ | ✅ |
|
| | [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/) | ✅ | ✅ | ✅ | ✅ |
|
| CORE | [PR compression](https://qodo-merge-docs.qodo.ai/core-abilities/compression_strategy/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | Adaptive and token-aware file patch fitting | ✅ | ✅ | ✅ | ✅ |
|
| | Adaptive and token-aware file patch fitting | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Multiple models support](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Local and global metadata](https://qodo-merge-docs.qodo.ai/core-abilities/metadata/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Dynamic context](https://qodo-merge-docs.qodo.ai/core-abilities/dynamic_context/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | ✅ | ✅ | ✅ |
|
| | [Self reflection](https://qodo-merge-docs.qodo.ai/core-abilities/self_reflection/) | ✅ | ✅ | ✅ | ✅ | |
|
||||||
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | | |
|
| | [Static code analysis](https://qodo-merge-docs.qodo.ai/core-abilities/static_code_analysis/) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Global and wiki configurations](https://qodo-merge-docs.qodo.ai/usage-guide/configuration_options/) 💎 | ✅ | ✅ | ✅ | |
|
| | [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) 💎 | ✅ | ✅ | | |
|
| | [PR interactive actions](https://www.qodo.ai/images/pr_agent/pr-actions.mp4) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | |
|
| | [Impact Evaluation](https://qodo-merge-docs.qodo.ai/core-abilities/impact_evaluation/) 💎 | ✅ | ✅ | | | |
|
||||||
| | [Code Validation 💎](https://qodo-merge-docs.qodo.ai/core-abilities/code_validation/) | ✅ | ✅ | ✅ | ✅ |
|
| | [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/) | ✅ | | | |
|
| | [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/)
|
- 💎 means this feature is available only in [Qodo Merge](https://www.qodo.ai/pricing/)
|
||||||
|
|
||||||
[//]: # (- Support for additional git providers is described in [here](./docs/Full_environments.md))
|
[//]: # (- Support for additional git providers is described in [here](./docs/Full_environments.md))
|
||||||
|
@ -33,6 +33,11 @@ FROM base AS azure_devops_webhook
|
|||||||
ADD pr_agent pr_agent
|
ADD pr_agent pr_agent
|
||||||
CMD ["python", "pr_agent/servers/azuredevops_server_webhook.py"]
|
CMD ["python", "pr_agent/servers/azuredevops_server_webhook.py"]
|
||||||
|
|
||||||
|
FROM base AS gitea_app
|
||||||
|
ADD pr_agent pr_agent
|
||||||
|
CMD ["python", "-m", "gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-c", "pr_agent/servers/gunicorn_config.py","pr_agent.servers.gitea_app:app"]
|
||||||
|
|
||||||
|
|
||||||
FROM base AS test
|
FROM base AS test
|
||||||
ADD requirements-dev.txt .
|
ADD requirements-dev.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements-dev.txt && rm requirements-dev.txt
|
RUN pip install --no-cache-dir -r requirements-dev.txt && rm requirements-dev.txt
|
||||||
|
46
docs/docs/installation/gitea.md
Normal file
46
docs/docs/installation/gitea.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
## Run a Gitea webhook server
|
||||||
|
|
||||||
|
1. In Gitea create a new user and give it "Reporter" role ("Developer" if using Pro version of the agent) for the intended group or project.
|
||||||
|
|
||||||
|
2. For the user from step 1. generate a `personal_access_token` with `api` access.
|
||||||
|
|
||||||
|
3. Generate a random secret for your app, and save it for later (`webhook_secret`). For example, you can use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
WEBHOOK_SECRET=$(python -c "import secrets; print(secrets.token_hex(10))")
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Clone this repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/qodo-ai/pr-agent.git
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Prepare variables and secrets. Skip this step if you plan on setting these as environment variables when running the agent:
|
||||||
|
1. In the configuration file/variables:
|
||||||
|
- Set `config.git_provider` to "gitea"
|
||||||
|
|
||||||
|
2. In the secrets file/variables:
|
||||||
|
- Set your AI model key in the respective section
|
||||||
|
- In the [Gitea] section, set `personal_access_token` (with token from step 2) and `webhook_secret` (with secret from step 3)
|
||||||
|
|
||||||
|
6. Build a Docker image for the app and optionally push it to a Docker repository. We'll use Dockerhub as an example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -f /docker/Dockerfile -t pr-agent:gitea_app --target gitea_app .
|
||||||
|
docker push codiumai/pr-agent:gitea_webhook # Push to your Docker repository
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Set the environmental variables, the method depends on your docker runtime. Skip this step if you included your secrets/configuration directly in the Docker image.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CONFIG__GIT_PROVIDER=gitea
|
||||||
|
GITEA__PERSONAL_ACCESS_TOKEN=<personal_access_token>
|
||||||
|
GITEA__WEBHOOK_SECRET=<webhook_secret>
|
||||||
|
GITEA__URL=https://gitea.com # Or self host
|
||||||
|
OPENAI__KEY=<your_openai_api_key>
|
||||||
|
```
|
||||||
|
|
||||||
|
8. Create a webhook in your Gitea project. Set the URL to `http[s]://<PR_AGENT_HOSTNAME>/api/v1/gitea_webhooks`, the secret token to the generated secret from step 3, and enable the triggers `push`, `comments` and `merge request events`.
|
||||||
|
|
||||||
|
9. Test your installation by opening a merge request or commenting on a merge request using one of PR Agent's commands.
|
@ -9,6 +9,7 @@ There are several ways to use self-hosted PR-Agent:
|
|||||||
- [GitLab integration](./gitlab.md)
|
- [GitLab integration](./gitlab.md)
|
||||||
- [BitBucket integration](./bitbucket.md)
|
- [BitBucket integration](./bitbucket.md)
|
||||||
- [Azure DevOps integration](./azure.md)
|
- [Azure DevOps integration](./azure.md)
|
||||||
|
- [Gitea integration](./gitea.md)
|
||||||
|
|
||||||
## Qodo Merge 💎
|
## Qodo Merge 💎
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
To run PR-Agent locally, you first need to acquire two keys:
|
To run PR-Agent locally, you first need to acquire two keys:
|
||||||
|
|
||||||
1. An OpenAI key from [here](https://platform.openai.com/api-keys){:target="_blank"}, with access to GPT-4 and o4-mini (or a key for other [language models](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/), if you prefer).
|
1. An OpenAI key from [here](https://platform.openai.com/api-keys){:target="_blank"}, with access to GPT-4 and o4-mini (or a key for other [language models](https://qodo-merge-docs.qodo.ai/usage-guide/changing_a_model/), if you prefer).
|
||||||
2. A personal access token from your Git platform (GitHub, GitLab, BitBucket) with repo scope. GitHub token, for example, can be issued from [here](https://github.com/settings/tokens){:target="_blank"}
|
2. A personal access token from your Git platform (GitHub, GitLab, BitBucket,Gitea) with repo scope. GitHub token, for example, can be issued from [here](https://github.com/settings/tokens){:target="_blank"}
|
||||||
|
|
||||||
## Using Docker image
|
## Using Docker image
|
||||||
|
|
||||||
@ -40,6 +40,19 @@ To invoke a tool (for example `review`), you can run PR-Agent directly from the
|
|||||||
docker run --rm -it -e CONFIG.GIT_PROVIDER=bitbucket -e OPENAI.KEY=$OPENAI_API_KEY -e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN codiumai/pr-agent:latest --pr_url=<pr_url> review
|
docker run --rm -it -e CONFIG.GIT_PROVIDER=bitbucket -e OPENAI.KEY=$OPENAI_API_KEY -e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN codiumai/pr-agent:latest --pr_url=<pr_url> review
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- For Gitea:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it -e OPENAI.KEY=<your key> -e CONFIG.GIT_PROVIDER=gitea -e GITEA.PERSONAL_ACCESS_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have a dedicated Gitea instance, you need to specify the custom url as variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
-e GITEA.URL=<your gitea instance url>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
For other git providers, update `CONFIG.GIT_PROVIDER` accordingly and check the [`pr_agent/settings/.secrets_template.toml`](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/.secrets_template.toml) file for environment variables expected names and values.
|
For other git providers, update `CONFIG.GIT_PROVIDER` accordingly and check the [`pr_agent/settings/.secrets_template.toml`](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/.secrets_template.toml) file for environment variables expected names and values.
|
||||||
|
|
||||||
### Utilizing environment variables
|
### Utilizing environment variables
|
||||||
|
@ -30,7 +30,7 @@ verbosity_level=2
|
|||||||
This is useful for debugging or experimenting with different tools.
|
This is useful for debugging or experimenting with different tools.
|
||||||
|
|
||||||
3. **git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L5) field in a configuration file determines the GIT provider that will be used by Qodo Merge. Currently, the following providers are supported:
|
3. **git provider**: The [git_provider](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L5) field in a configuration file determines the GIT provider that will be used by Qodo Merge. Currently, the following providers are supported:
|
||||||
`github` **(default)**, `gitlab`, `bitbucket`, `azure`, `codecommit`, `local`, and `gerrit`.
|
`github` **(default)**, `gitlab`, `bitbucket`, `azure`, `codecommit`, `local`,`gitea`, and `gerrit`.
|
||||||
|
|
||||||
### CLI Health Check
|
### CLI Health Check
|
||||||
|
|
||||||
@ -312,3 +312,16 @@ pr_commands = [
|
|||||||
"/improve",
|
"/improve",
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Gitea Webhook
|
||||||
|
|
||||||
|
After setting up a Gitea webhook, to control which commands will run automatically when a new MR is opened, you can set the `pr_commands` parameter in the configuration file, similar to the GitHub App:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[gitea]
|
||||||
|
pr_commands = [
|
||||||
|
"/describe",
|
||||||
|
"/review",
|
||||||
|
"/improve",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
@ -12,6 +12,7 @@ It includes information on how to adjust Qodo Merge configurations, define which
|
|||||||
- [GitHub App](./automations_and_usage.md#github-app)
|
- [GitHub App](./automations_and_usage.md#github-app)
|
||||||
- [GitHub Action](./automations_and_usage.md#github-action)
|
- [GitHub Action](./automations_and_usage.md#github-action)
|
||||||
- [GitLab Webhook](./automations_and_usage.md#gitlab-webhook)
|
- [GitLab Webhook](./automations_and_usage.md#gitlab-webhook)
|
||||||
|
- [Gitea Webhook](./automations_and_usage.md#gitea-webhook)
|
||||||
- [BitBucket App](./automations_and_usage.md#bitbucket-app)
|
- [BitBucket App](./automations_and_usage.md#bitbucket-app)
|
||||||
- [Azure DevOps Provider](./automations_and_usage.md#azure-devops-provider)
|
- [Azure DevOps Provider](./automations_and_usage.md#azure-devops-provider)
|
||||||
- [Managing Mail Notifications](./mail_notifications.md)
|
- [Managing Mail Notifications](./mail_notifications.md)
|
||||||
|
@ -58,6 +58,9 @@ def filter_ignored(files, platform = 'github'):
|
|||||||
files = files_o
|
files = files_o
|
||||||
elif platform == 'azure':
|
elif platform == 'azure':
|
||||||
files = [f for f in files if not r.match(f)]
|
files = [f for f in files if not r.match(f)]
|
||||||
|
elif platform == 'gitea':
|
||||||
|
files = [f for f in files if not r.match(f.get("filename", ""))]
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Could not filter file list: {e}")
|
print(f"Could not filter file list: {e}")
|
||||||
|
@ -8,6 +8,7 @@ from pr_agent.git_providers.bitbucket_server_provider import \
|
|||||||
from pr_agent.git_providers.codecommit_provider import CodeCommitProvider
|
from pr_agent.git_providers.codecommit_provider import CodeCommitProvider
|
||||||
from pr_agent.git_providers.gerrit_provider import GerritProvider
|
from pr_agent.git_providers.gerrit_provider import GerritProvider
|
||||||
from pr_agent.git_providers.git_provider import GitProvider
|
from pr_agent.git_providers.git_provider import GitProvider
|
||||||
|
from pr_agent.git_providers.gitea_provider import GiteaProvider
|
||||||
from pr_agent.git_providers.github_provider import GithubProvider
|
from pr_agent.git_providers.github_provider import GithubProvider
|
||||||
from pr_agent.git_providers.gitlab_provider import GitLabProvider
|
from pr_agent.git_providers.gitlab_provider import GitLabProvider
|
||||||
from pr_agent.git_providers.local_git_provider import LocalGitProvider
|
from pr_agent.git_providers.local_git_provider import LocalGitProvider
|
||||||
@ -22,7 +23,7 @@ _GIT_PROVIDERS = {
|
|||||||
'codecommit': CodeCommitProvider,
|
'codecommit': CodeCommitProvider,
|
||||||
'local': LocalGitProvider,
|
'local': LocalGitProvider,
|
||||||
'gerrit': GerritProvider,
|
'gerrit': GerritProvider,
|
||||||
'gitea': GiteaProvider,
|
'gitea': GiteaProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
128
pr_agent/servers/gitea_app.py
Normal file
128
pr_agent/servers/gitea_app.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import asyncio
|
||||||
|
import copy
|
||||||
|
import os
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from fastapi import APIRouter, FastAPI, HTTPException, Request, Response
|
||||||
|
from starlette.background import BackgroundTasks
|
||||||
|
from starlette.middleware import Middleware
|
||||||
|
from starlette_context import context
|
||||||
|
from starlette_context.middleware import RawContextMiddleware
|
||||||
|
|
||||||
|
from pr_agent.agent.pr_agent import PRAgent
|
||||||
|
from pr_agent.config_loader import get_settings, global_settings
|
||||||
|
from pr_agent.log import LoggingFormat, get_logger, setup_logger
|
||||||
|
from pr_agent.servers.utils import verify_signature
|
||||||
|
|
||||||
|
# Setup logging and router
|
||||||
|
setup_logger(fmt=LoggingFormat.JSON, level=get_settings().get("CONFIG.LOG_LEVEL", "DEBUG"))
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/api/v1/gitea_webhooks")
|
||||||
|
async def handle_gitea_webhooks(background_tasks: BackgroundTasks, request: Request, response: Response):
|
||||||
|
"""Handle incoming Gitea webhook requests"""
|
||||||
|
get_logger().debug("Received a Gitea webhook")
|
||||||
|
|
||||||
|
body = await get_body(request)
|
||||||
|
|
||||||
|
# Set context for the request
|
||||||
|
context["settings"] = copy.deepcopy(global_settings)
|
||||||
|
context["git_provider"] = {}
|
||||||
|
|
||||||
|
# Handle the webhook in background
|
||||||
|
background_tasks.add_task(handle_request, body, event=request.headers.get("X-Gitea-Event", None))
|
||||||
|
return {}
|
||||||
|
|
||||||
|
async def get_body(request: Request):
|
||||||
|
"""Parse and verify webhook request body"""
|
||||||
|
try:
|
||||||
|
body = await request.json()
|
||||||
|
except Exception as e:
|
||||||
|
get_logger().error("Error parsing request body", artifact={'error': e})
|
||||||
|
raise HTTPException(status_code=400, detail="Error parsing request body") from e
|
||||||
|
|
||||||
|
|
||||||
|
# Verify webhook signature
|
||||||
|
webhook_secret = getattr(get_settings().gitea, 'webhook_secret', None)
|
||||||
|
if webhook_secret:
|
||||||
|
body_bytes = await request.body()
|
||||||
|
signature_header = request.headers.get('x-gitea-signature', None)
|
||||||
|
if not signature_header:
|
||||||
|
get_logger().error("Missing signature header")
|
||||||
|
raise HTTPException(status_code=400, detail="Missing signature header")
|
||||||
|
|
||||||
|
try:
|
||||||
|
verify_signature(body_bytes, webhook_secret, f"sha256={signature_header}")
|
||||||
|
except Exception as ex:
|
||||||
|
get_logger().error(f"Invalid signature: {ex}")
|
||||||
|
raise HTTPException(status_code=401, detail="Invalid signature")
|
||||||
|
|
||||||
|
return body
|
||||||
|
|
||||||
|
async def handle_request(body: Dict[str, Any], event: str):
|
||||||
|
"""Process Gitea webhook events"""
|
||||||
|
action = body.get("action")
|
||||||
|
if not action:
|
||||||
|
get_logger().debug("No action found in request body")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
agent = PRAgent()
|
||||||
|
|
||||||
|
# Handle different event types
|
||||||
|
if event == "pull_request":
|
||||||
|
if action in ["opened", "reopened", "synchronized"]:
|
||||||
|
await handle_pr_event(body, event, action, agent)
|
||||||
|
elif event == "issue_comment":
|
||||||
|
if action == "created":
|
||||||
|
await handle_comment_event(body, event, action, agent)
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
async def handle_pr_event(body: Dict[str, Any], event: str, action: str, agent: PRAgent):
|
||||||
|
"""Handle pull request events"""
|
||||||
|
pr = body.get("pull_request", {})
|
||||||
|
if not pr:
|
||||||
|
return
|
||||||
|
|
||||||
|
api_url = pr.get("url")
|
||||||
|
if not api_url:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Handle PR based on action
|
||||||
|
if action in ["opened", "reopened"]:
|
||||||
|
commands = get_settings().get("gitea.pr_commands", [])
|
||||||
|
for command in commands:
|
||||||
|
await agent.handle_request(api_url, command)
|
||||||
|
elif action == "synchronized":
|
||||||
|
# Handle push to PR
|
||||||
|
await agent.handle_request(api_url, "/review --incremental")
|
||||||
|
|
||||||
|
async def handle_comment_event(body: Dict[str, Any], event: str, action: str, agent: PRAgent):
|
||||||
|
"""Handle comment events"""
|
||||||
|
comment = body.get("comment", {})
|
||||||
|
if not comment:
|
||||||
|
return
|
||||||
|
|
||||||
|
comment_body = comment.get("body", "")
|
||||||
|
if not comment_body or not comment_body.startswith("/"):
|
||||||
|
return
|
||||||
|
|
||||||
|
pr_url = body.get("pull_request", {}).get("url")
|
||||||
|
if not pr_url:
|
||||||
|
return
|
||||||
|
|
||||||
|
await agent.handle_request(pr_url, comment_body)
|
||||||
|
|
||||||
|
# FastAPI app setup
|
||||||
|
middleware = [Middleware(RawContextMiddleware)]
|
||||||
|
app = FastAPI(middleware=middleware)
|
||||||
|
app.include_router(router)
|
||||||
|
|
||||||
|
def start():
|
||||||
|
"""Start the Gitea webhook server"""
|
||||||
|
port = int(os.environ.get("PORT", "3000"))
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=port)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
start()
|
@ -68,6 +68,11 @@ webhook_secret = "<WEBHOOK SECRET>" # Optional, may be commented out.
|
|||||||
personal_access_token = ""
|
personal_access_token = ""
|
||||||
shared_secret = "" # webhook secret
|
shared_secret = "" # webhook secret
|
||||||
|
|
||||||
|
[gitea]
|
||||||
|
# Gitea personal access token
|
||||||
|
personal_access_token=""
|
||||||
|
webhook_secret="" # webhook secret
|
||||||
|
|
||||||
[bitbucket]
|
[bitbucket]
|
||||||
# For Bitbucket authentication
|
# For Bitbucket authentication
|
||||||
auth_type = "bearer" # "bearer" or "basic"
|
auth_type = "bearer" # "bearer" or "basic"
|
||||||
|
@ -281,6 +281,15 @@ push_commands = [
|
|||||||
"/review",
|
"/review",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[gitea_app]
|
||||||
|
url = "https://gitea.com"
|
||||||
|
handle_push_trigger = false
|
||||||
|
pr_commands = [
|
||||||
|
"/describe",
|
||||||
|
"/review",
|
||||||
|
"/improve",
|
||||||
|
]
|
||||||
|
|
||||||
[bitbucket_app]
|
[bitbucket_app]
|
||||||
pr_commands = [
|
pr_commands = [
|
||||||
"/describe --pr_description.final_update_message=false",
|
"/describe --pr_description.final_update_message=false",
|
||||||
|
@ -31,6 +31,7 @@ gunicorn==22.0.0
|
|||||||
pytest-cov==5.0.0
|
pytest-cov==5.0.0
|
||||||
pydantic==2.8.2
|
pydantic==2.8.2
|
||||||
html2text==2024.2.26
|
html2text==2024.2.26
|
||||||
|
giteapy==1.0.8
|
||||||
# Uncomment the following lines to enable the 'similar issue' tool
|
# Uncomment the following lines to enable the 'similar issue' tool
|
||||||
# pinecone-client
|
# pinecone-client
|
||||||
# pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main
|
# pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main
|
||||||
|
Reference in New Issue
Block a user