196 lines
5.4 KiB
Python
196 lines
5.4 KiB
Python
"""
|
|
title: Gitea Connector
|
|
author: H5N3RG
|
|
version: 0.1
|
|
license: MIT
|
|
description: Allows Open WebUI LLMs to read and edit Gitea repositories.
|
|
"""
|
|
|
|
import requests
|
|
import base64
|
|
from typing import Optional
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class GiteaAPI:
|
|
def __init__(self, base_url: str, token: str):
|
|
self.base_url = base_url.rstrip("/")
|
|
self.headers = {
|
|
"Authorization": f"token {token}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
def get(self, endpoint):
|
|
r = requests.get(f"{self.base_url}{endpoint}", headers=self.headers)
|
|
r.raise_for_status()
|
|
return r.json()
|
|
|
|
def put(self, endpoint, data):
|
|
r = requests.put(f"{self.base_url}{endpoint}", headers=self.headers, json=data)
|
|
r.raise_for_status()
|
|
return r.json()
|
|
|
|
def post(self, endpoint, data):
|
|
r = requests.post(f"{self.base_url}{endpoint}", headers=self.headers, json=data)
|
|
r.raise_for_status()
|
|
return r.json()
|
|
|
|
|
|
class Tools:
|
|
|
|
class Valves(BaseModel):
|
|
|
|
GITEA_URL: str = "https://git.example.com/api/v1"
|
|
API_TOKEN: str = ""
|
|
|
|
DEFAULT_OWNER: str = "user"
|
|
DEFAULT_REPO: str = "repo"
|
|
DEFAULT_BRANCH: str = "main"
|
|
|
|
ENABLE_READ: bool = True
|
|
ENABLE_WRITE: bool = False
|
|
ENABLE_BRANCH: bool = True
|
|
ENABLE_PR: bool = True
|
|
|
|
ALLOWED_PATH_PREFIX: str = "docs/"
|
|
|
|
MAX_FILE_SIZE_KB: int = 200
|
|
|
|
def __init__(self):
|
|
self.valves = self.Valves()
|
|
|
|
self.api = GiteaAPI(self.valves.GITEA_URL, self.valves.API_TOKEN)
|
|
|
|
# --------------------------------------------------
|
|
# LIST FILES
|
|
# --------------------------------------------------
|
|
|
|
def list_repository_tree(self, path: str = ""):
|
|
"""
|
|
List files in the repository.
|
|
"""
|
|
|
|
if not self.valves.ENABLE_READ:
|
|
return "Reading repository disabled."
|
|
|
|
owner = self.valves.DEFAULT_OWNER
|
|
repo = self.valves.DEFAULT_REPO
|
|
branch = self.valves.DEFAULT_BRANCH
|
|
|
|
endpoint = f"/repos/{owner}/{repo}/contents/{path}?ref={branch}"
|
|
|
|
data = self.api.get(endpoint)
|
|
|
|
return [{"name": f["name"], "path": f["path"], "type": f["type"]} for f in data]
|
|
|
|
# --------------------------------------------------
|
|
# READ FILE
|
|
# --------------------------------------------------
|
|
|
|
def read_file(self, path: str):
|
|
"""
|
|
Read a file from the repository.
|
|
"""
|
|
|
|
if not self.valves.ENABLE_READ:
|
|
return "Reading disabled."
|
|
|
|
owner = self.valves.DEFAULT_OWNER
|
|
repo = self.valves.DEFAULT_REPO
|
|
branch = self.valves.DEFAULT_BRANCH
|
|
|
|
endpoint = f"/repos/{owner}/{repo}/contents/{path}?ref={branch}"
|
|
|
|
data = self.api.get(endpoint)
|
|
|
|
content = base64.b64decode(data["content"]).decode("utf-8")
|
|
|
|
return content
|
|
|
|
# --------------------------------------------------
|
|
# CREATE OR UPDATE FILE
|
|
# --------------------------------------------------
|
|
|
|
def create_or_update_file(
|
|
self, path: str, content: str, commit_message: str, branch: Optional[str] = None
|
|
):
|
|
"""
|
|
Create or update a file in the repository.
|
|
"""
|
|
|
|
if not self.valves.ENABLE_WRITE:
|
|
return "Write access disabled."
|
|
|
|
if not path.startswith(self.valves.ALLOWED_PATH_PREFIX):
|
|
return "Path not allowed."
|
|
|
|
if len(content) > self.valves.MAX_FILE_SIZE_KB * 1024:
|
|
return "File too large."
|
|
|
|
owner = self.valves.DEFAULT_OWNER
|
|
repo = self.valves.DEFAULT_REPO
|
|
branch = branch or self.valves.DEFAULT_BRANCH
|
|
|
|
endpoint = f"/repos/{owner}/{repo}/contents/{path}"
|
|
|
|
# check if file exists
|
|
sha = None
|
|
try:
|
|
existing = self.api.get(f"{endpoint}?ref={branch}")
|
|
sha = existing["sha"]
|
|
except:
|
|
pass
|
|
|
|
encoded = base64.b64encode(content.encode()).decode()
|
|
|
|
payload = {"message": commit_message, "content": encoded, "branch": branch}
|
|
|
|
if sha:
|
|
payload["sha"] = sha
|
|
|
|
return self.api.put(endpoint, payload)
|
|
|
|
# --------------------------------------------------
|
|
# CREATE BRANCH
|
|
# --------------------------------------------------
|
|
|
|
def create_branch(self, new_branch: str, from_branch: Optional[str] = None):
|
|
"""
|
|
Create a new branch.
|
|
"""
|
|
|
|
if not self.valves.ENABLE_BRANCH:
|
|
return "Branch creation disabled."
|
|
|
|
owner = self.valves.DEFAULT_OWNER
|
|
repo = self.valves.DEFAULT_REPO
|
|
|
|
from_branch = from_branch or self.valves.DEFAULT_BRANCH
|
|
|
|
endpoint = f"/repos/{owner}/{repo}/branches"
|
|
|
|
payload = {"new_branch_name": new_branch, "old_branch_name": from_branch}
|
|
|
|
return self.api.post(endpoint, payload)
|
|
|
|
# --------------------------------------------------
|
|
# CREATE PR
|
|
# --------------------------------------------------
|
|
|
|
def create_pull_request(self, head: str, base: str, title: str, body: str = ""):
|
|
"""
|
|
Create a pull request.
|
|
"""
|
|
|
|
if not self.valves.ENABLE_PR:
|
|
return "PR creation disabled."
|
|
|
|
owner = self.valves.DEFAULT_OWNER
|
|
repo = self.valves.DEFAULT_REPO
|
|
|
|
endpoint = f"/repos/{owner}/{repo}/pulls"
|
|
|
|
payload = {"title": title, "head": head, "base": base, "body": body}
|
|
|
|
return self.api.post(endpoint, payload)
|