# 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)