|
|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
import urllib.parse
|
|
|
|
|
from typing import Any, Union
|
|
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
@ -11,14 +12,14 @@ class GitlabFilesTool(BuiltinTool):
|
|
|
|
|
self, user_id: str, tool_parameters: dict[str, Any]
|
|
|
|
|
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
|
|
|
|
project = tool_parameters.get("project", "")
|
|
|
|
|
repository = tool_parameters.get("repository", "")
|
|
|
|
|
branch = tool_parameters.get("branch", "")
|
|
|
|
|
path = tool_parameters.get("path", "")
|
|
|
|
|
|
|
|
|
|
if not project:
|
|
|
|
|
return self.create_text_message("Project is required")
|
|
|
|
|
if not project and not repository:
|
|
|
|
|
return self.create_text_message("Either project or repository is required")
|
|
|
|
|
if not branch:
|
|
|
|
|
return self.create_text_message("Branch is required")
|
|
|
|
|
|
|
|
|
|
if not path:
|
|
|
|
|
return self.create_text_message("Path is required")
|
|
|
|
|
|
|
|
|
|
@ -30,56 +31,51 @@ class GitlabFilesTool(BuiltinTool):
|
|
|
|
|
if "site_url" not in self.runtime.credentials or not self.runtime.credentials.get("site_url"):
|
|
|
|
|
site_url = "https://gitlab.com"
|
|
|
|
|
|
|
|
|
|
# Get project ID from project name
|
|
|
|
|
project_id = self.get_project_id(site_url, access_token, project)
|
|
|
|
|
if not project_id:
|
|
|
|
|
return self.create_text_message(f"Project '{project}' not found.")
|
|
|
|
|
|
|
|
|
|
# Get commit content
|
|
|
|
|
result = self.fetch(user_id, project_id, site_url, access_token, branch, path)
|
|
|
|
|
# Get file content
|
|
|
|
|
if repository:
|
|
|
|
|
result = self.fetch_files(site_url, access_token, repository, branch, path, is_repository=True)
|
|
|
|
|
else:
|
|
|
|
|
result = self.fetch_files(site_url, access_token, project, branch, path, is_repository=False)
|
|
|
|
|
|
|
|
|
|
return [self.create_json_message(item) for item in result]
|
|
|
|
|
|
|
|
|
|
def extract_project_name_and_path(self, path: str) -> tuple[str, str]:
|
|
|
|
|
parts = path.split("/", 1)
|
|
|
|
|
if len(parts) < 2:
|
|
|
|
|
return None, None
|
|
|
|
|
return parts[0], parts[1]
|
|
|
|
|
|
|
|
|
|
def get_project_id(self, site_url: str, access_token: str, project_name: str) -> Union[str, None]:
|
|
|
|
|
headers = {"PRIVATE-TOKEN": access_token}
|
|
|
|
|
try:
|
|
|
|
|
url = f"{site_url}/api/v4/projects?search={project_name}"
|
|
|
|
|
response = requests.get(url, headers=headers)
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
projects = response.json()
|
|
|
|
|
for project in projects:
|
|
|
|
|
if project["name"] == project_name:
|
|
|
|
|
return project["id"]
|
|
|
|
|
except requests.RequestException as e:
|
|
|
|
|
print(f"Error fetching project ID from GitLab: {e}")
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def fetch(
|
|
|
|
|
self, user_id: str, project_id: str, site_url: str, access_token: str, branch: str, path: str = None
|
|
|
|
|
def fetch_files(
|
|
|
|
|
self, site_url: str, access_token: str, identifier: str, branch: str, path: str, is_repository: bool
|
|
|
|
|
) -> list[dict[str, Any]]:
|
|
|
|
|
domain = site_url
|
|
|
|
|
headers = {"PRIVATE-TOKEN": access_token}
|
|
|
|
|
results = []
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# List files and directories in the given path
|
|
|
|
|
url = f"{domain}/api/v4/projects/{project_id}/repository/tree?path={path}&ref={branch}"
|
|
|
|
|
response = requests.get(url, headers=headers)
|
|
|
|
|
if is_repository:
|
|
|
|
|
# URL encode the repository path
|
|
|
|
|
encoded_identifier = urllib.parse.quote(identifier, safe="")
|
|
|
|
|
tree_url = f"{domain}/api/v4/projects/{encoded_identifier}/repository/tree?path={path}&ref={branch}"
|
|
|
|
|
else:
|
|
|
|
|
# Get project ID from project name
|
|
|
|
|
project_id = self.get_project_id(site_url, access_token, identifier)
|
|
|
|
|
if not project_id:
|
|
|
|
|
return self.create_text_message(f"Project '{identifier}' not found.")
|
|
|
|
|
tree_url = f"{domain}/api/v4/projects/{project_id}/repository/tree?path={path}&ref={branch}"
|
|
|
|
|
|
|
|
|
|
response = requests.get(tree_url, headers=headers)
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
items = response.json()
|
|
|
|
|
|
|
|
|
|
for item in items:
|
|
|
|
|
item_path = item["path"]
|
|
|
|
|
if item["type"] == "tree": # It's a directory
|
|
|
|
|
results.extend(self.fetch(project_id, site_url, access_token, branch, item_path))
|
|
|
|
|
results.extend(
|
|
|
|
|
self.fetch_files(site_url, access_token, identifier, branch, item_path, is_repository)
|
|
|
|
|
)
|
|
|
|
|
else: # It's a file
|
|
|
|
|
file_url = f"{domain}/api/v4/projects/{project_id}/repository/files/{item_path}/raw?ref={branch}"
|
|
|
|
|
if is_repository:
|
|
|
|
|
file_url = f"{domain}/api/v4/projects/{encoded_identifier}/repository/files/{item_path}/raw?ref={branch}"
|
|
|
|
|
else:
|
|
|
|
|
file_url = (
|
|
|
|
|
f"{domain}/api/v4/projects/{project_id}/repository/files/{item_path}/raw?ref={branch}"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
file_response = requests.get(file_url, headers=headers)
|
|
|
|
|
file_response.raise_for_status()
|
|
|
|
|
file_content = file_response.text
|
|
|
|
|
@ -88,3 +84,17 @@ class GitlabFilesTool(BuiltinTool):
|
|
|
|
|
print(f"Error fetching data from GitLab: {e}")
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
def get_project_id(self, site_url: str, access_token: str, project_name: str) -> Union[str, None]:
|
|
|
|
|
headers = {"PRIVATE-TOKEN": access_token}
|
|
|
|
|
try:
|
|
|
|
|
url = f"{site_url}/api/v4/projects?search={project_name}"
|
|
|
|
|
response = requests.get(url, headers=headers)
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
projects = response.json()
|
|
|
|
|
for project in projects:
|
|
|
|
|
if project["name"] == project_name:
|
|
|
|
|
return project["id"]
|
|
|
|
|
except requests.RequestException as e:
|
|
|
|
|
print(f"Error fetching project ID from GitLab: {e}")
|
|
|
|
|
return None
|
|
|
|
|
|