422 lines
16 KiB
Python
422 lines
16 KiB
Python
# tools/github_tool.py
|
|
from .base_tool import BaseTool
|
|
from .metrics import metrics
|
|
import requests
|
|
import os
|
|
import base64
|
|
import logging
|
|
|
|
class GitHubTool(BaseTool):
|
|
def __init__(self):
|
|
self.base_url = "https://api.github.com"
|
|
self.token = os.environ.get("GITHUB_TOKEN")
|
|
self.headers = {
|
|
"Authorization": f"token {self.token}",
|
|
"Accept": "application/vnd.github.v3+json"
|
|
}
|
|
self.repo = os.environ.get("GITHUB_REPOSITORY")
|
|
self.current_branch = "main" # Default to main branch
|
|
|
|
# Set up logging
|
|
self.logger = logging.getLogger(__name__)
|
|
self.logger.setLevel(logging.INFO)
|
|
|
|
# Create a file handler
|
|
file_handler = logging.FileHandler('github_tool.log')
|
|
file_handler.setLevel(logging.INFO)
|
|
|
|
# Create a console handler
|
|
console_handler = logging.StreamHandler()
|
|
console_handler.setLevel(logging.INFO)
|
|
|
|
# Create a formatting for the logs
|
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
file_handler.setFormatter(formatter)
|
|
console_handler.setFormatter(formatter)
|
|
|
|
# Add the handlers to the logger
|
|
self.logger.addHandler(file_handler)
|
|
self.logger.addHandler(console_handler)
|
|
|
|
def clear(self):
|
|
if (self.current_branch != "main"):
|
|
self._set_current_branch("main")
|
|
pass
|
|
|
|
def get_functions(self):
|
|
return [
|
|
{
|
|
"name": "read_file",
|
|
"description": "Read a file from the repository",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"path": {
|
|
"type": "string",
|
|
"description": "Path to the file in the repository"
|
|
}
|
|
},
|
|
"required": ["path"]
|
|
}
|
|
},
|
|
{
|
|
"name": "create_branch",
|
|
"description": "Create a new branch in the repository",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"branch_name": {
|
|
"type": "string",
|
|
"description": "Name of the new branch"
|
|
},
|
|
"base_branch": {
|
|
"type": "string",
|
|
"description": "Name of the base branch",
|
|
"default": "main"
|
|
}
|
|
},
|
|
"required": ["branch_name"]
|
|
}
|
|
},
|
|
{
|
|
"name": "commit_file",
|
|
"description": "Commit a file to a branch (not main)",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"file_path": {
|
|
"type": "string",
|
|
"description": "Path to the file in the repository"
|
|
},
|
|
"commit_message": {
|
|
"type": "string",
|
|
"description": "Commit message"
|
|
},
|
|
"content": {
|
|
"type": "string",
|
|
"description": "Content of the file"
|
|
}
|
|
},
|
|
"required": ["file_path", "commit_message", "content"]
|
|
}
|
|
},
|
|
{
|
|
"name": "create_pull_request",
|
|
"description": "Create a pull request",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"title": {
|
|
"type": "string",
|
|
"description": "Title of the pull request"
|
|
},
|
|
"body": {
|
|
"type": "string",
|
|
"description": "Body of the pull request"
|
|
},
|
|
"base": {
|
|
"type": "string",
|
|
"description": "The name of the branch you want the changes pulled into",
|
|
"default": "main"
|
|
}
|
|
},
|
|
"required": ["title", "body"]
|
|
}
|
|
},
|
|
{
|
|
"name": "list_files",
|
|
"description": "List files in a directory of the repository",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"path": {
|
|
"type": "string",
|
|
"description": "Path to the directory in the repository"
|
|
}
|
|
},
|
|
"required": ["path"]
|
|
}
|
|
},
|
|
{
|
|
"name": "search_code",
|
|
"description": "Search for code in the repository",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"query": {
|
|
"type": "string",
|
|
"description": "Search query"
|
|
}
|
|
},
|
|
"required": ["query"]
|
|
}
|
|
},
|
|
{
|
|
"name": "get_commit_history",
|
|
"description": "Get commit history for a file",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"file_path": {
|
|
"type": "string",
|
|
"description": "Path to the file in the repository"
|
|
},
|
|
"num_commits": {
|
|
"type": "integer",
|
|
"description": "Number of commits to retrieve",
|
|
"default": 10
|
|
}
|
|
},
|
|
"required": ["file_path"]
|
|
}
|
|
},
|
|
{
|
|
"name": "get_branch_sha",
|
|
"description": "Get the SHA of the latest commit on a branch",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"branch": {
|
|
"type": "string",
|
|
"description": "Name of the branch"
|
|
}
|
|
},
|
|
"required": ["branch"]
|
|
}
|
|
},
|
|
{
|
|
"name": "get_current_branch",
|
|
"description": "Get the name of the current branch",
|
|
"parameters": {}
|
|
},
|
|
{
|
|
"name": "set_current_branch",
|
|
"description": "Set the current branch",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"branch_name": {
|
|
"type": "string",
|
|
"description": "Name of the branch to set as current"
|
|
}
|
|
},
|
|
"required": ["branch_name"]
|
|
}
|
|
},
|
|
{
|
|
"name": "get_file_at_commit",
|
|
"description": "Get the contents of a file at a specific commit",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"file_path": {
|
|
"type": "string",
|
|
"description": "Path to the file in the repository"
|
|
},
|
|
"commit_sha": {
|
|
"type": "string",
|
|
"description": "SHA of the commit to retrieve the file from"
|
|
}
|
|
},
|
|
"required": ["file_path", "commit_sha"]
|
|
}
|
|
},
|
|
{
|
|
"name": "list_branches",
|
|
"description": "List all branches in the repository",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"per_page": {
|
|
"type": "integer",
|
|
"description": "Number of branches to return per page (max 100)",
|
|
"default": 100
|
|
},
|
|
"all_pages": {
|
|
"type": "boolean",
|
|
"description": "Whether to fetch all pages of results",
|
|
"default": True
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"name": "approve_pull_request",
|
|
"description": "Approve a pull request",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pull_number": {
|
|
"type": "integer",
|
|
"description": "The number of the pull request"
|
|
}
|
|
},
|
|
"required": ["pull_number"]
|
|
}
|
|
},
|
|
{
|
|
"name": "close_pull_request",
|
|
"description": "Close a pull request",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pull_number": {
|
|
"type": "integer",
|
|
"description": "The number of the pull request"
|
|
}
|
|
},
|
|
"required": ["pull_number"]
|
|
}
|
|
},
|
|
{
|
|
"name": "merge_pull_request",
|
|
"description": "Merge a pull request",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pull_number": {
|
|
"type": "integer",
|
|
"description": "The number of the pull request"
|
|
},
|
|
"commit_title": {
|
|
"type": "string",
|
|
"description": "Title for the automatic commit message",
|
|
"default": "Merge pull request"
|
|
},
|
|
"commit_message": {
|
|
"type": "string",
|
|
"description": "Extra detail to append to automatic commit message",
|
|
"default": ""
|
|
},
|
|
"merge_method": {
|
|
"type": "string",
|
|
"description": "Merge method to use",
|
|
"enum": ["merge", "squash", "rebase"],
|
|
"default": "merge"
|
|
}
|
|
},
|
|
"required": ["pull_number"]
|
|
}
|
|
},
|
|
{
|
|
"name": "delete_branch",
|
|
"description": "Delete a branch",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"branch_name": {
|
|
"type": "string",
|
|
"description": "Name of the branch to delete"
|
|
}
|
|
},
|
|
"required": ["branch_name"]
|
|
}
|
|
}
|
|
]
|
|
|
|
@metrics.measure
|
|
def execute(self, function_name, **kwargs):
|
|
self.logger.info(f"Executing: {function_name}")
|
|
|
|
if function_name == "read_file":
|
|
return self._read_file(kwargs["path"])
|
|
elif function_name == "create_branch":
|
|
return self._create_branch(kwargs["branch_name"], kwargs.get("base_branch", "main"))
|
|
elif function_name == "commit_file":
|
|
return self._commit_file(kwargs["file_path"], kwargs["content"], kwargs["commit_message"])
|
|
elif function_name == "create_pull_request":
|
|
return self._create_pull_request(kwargs["title"], kwargs["body"], kwargs.get("base", "main"))
|
|
elif function_name == "list_files":
|
|
return self._list_files(kwargs["path"])
|
|
elif function_name == "search_code":
|
|
return self._search_code(kwargs["query"])
|
|
elif function_name == "get_commit_history":
|
|
return self._get_commit_history(kwargs["file_path"], kwargs.get("num_commits", 10))
|
|
elif function_name == "get_current_branch":
|
|
return self._get_current_branch()
|
|
elif function_name == "set_current_branch":
|
|
return self._set_current_branch(kwargs["branch_name"])
|
|
elif function_name == "get_file_at_commit":
|
|
return self._get_file_at_commit(kwargs["file_path"], kwargs["commit_sha"])
|
|
elif function_name == "list_branches":
|
|
return self._list_branches(kwargs.get("per_page", 100), kwargs.get("all_pages", True))
|
|
elif function_name == "get_branch_sha":
|
|
return self._get_branch_sha(kwargs["branch"])
|
|
elif function_name == "approve_pull_request":
|
|
return self._approve_pull_request(kwargs["pull_number"])
|
|
elif function_name == "close_pull_request":
|
|
return self._close_pull_request(kwargs["pull_number"])
|
|
elif function_name == "merge_pull_request":
|
|
return self._merge_pull_request(kwargs["pull_number"], kwargs.get("commit_title", "Merge pull request"),
|
|
kwargs.get("commit_message", ""), kwargs.get("merge_method", "merge"))
|
|
elif function_name == "delete_branch":
|
|
return self._delete_branch(kwargs["branch_name"])
|
|
else:
|
|
error_message = f"Unknown function: {function_name}"
|
|
self.logger.error(error_message)
|
|
return error_message
|
|
|
|
@metrics.measure
|
|
def _read_file(self, path):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _create_branch(self, branch_name, base_branch):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _commit_file(self, file_path, content, commit_message):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _create_pull_request(self, title, body, base):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _get_branch_sha(self, branch):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _list_files(self, path):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _search_code(self, query):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _get_commit_history(self, file_path, num_commits):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _get_current_branch(self):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _set_current_branch(self, branch_name):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _get_file_at_commit(self, file_path, commit_sha):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _list_branches(self, per_page=100, all_pages=True):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _approve_pull_request(self, pull_number):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _close_pull_request(self, pull_number):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _merge_pull_request(self, pull_number, commit_title, commit_message, merge_method):
|
|
# ... (rest of the method remains unchanged)
|
|
|
|
@metrics.measure
|
|
def _delete_branch(self, branch_name):
|
|
# ... (rest of the method remains unchanged)
|