From b5f71c0e7dca37ea87586022eb0d4c3deda5a451 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:41:59 -0500 Subject: [PATCH 01/22] Create github_tool_functions subdirectory --- tools/github_tool_functions/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/github_tool_functions/.gitkeep diff --git a/tools/github_tool_functions/.gitkeep b/tools/github_tool_functions/.gitkeep new file mode 100644 index 0000000..e69de29 From 12dbd9505c41a4581496eb5456af11e84787c455 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:42:13 -0500 Subject: [PATCH 02/22] Add ReadFile class for read_file function --- tools/github_tool_functions/read_file.py | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tools/github_tool_functions/read_file.py diff --git a/tools/github_tool_functions/read_file.py b/tools/github_tool_functions/read_file.py new file mode 100644 index 0000000..34f7d62 --- /dev/null +++ b/tools/github_tool_functions/read_file.py @@ -0,0 +1,49 @@ +import base64 +import requests +import os +import logging + +class ReadFile: + def __init__(self, base_url, token, repo, current_branch): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('read_file.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 __call__(self, path): + self.logger.info(f"Reading file: {path} from branch: {self.current_branch}") + url = f"{self.base_url}/repos/{self.repo}/contents/{path}" + response = requests.get(url, headers=self.headers, params={"ref": self.current_branch}) + if response.status_code == 200: + content = response.json()["content"] + decoded_content = base64.b64decode(content).decode('utf-8') + self.logger.info(f"Successfully read file: {path}") + return decoded_content + else: + error_message = f"Error reading file: {response.status_code}" + self.logger.error(error_message) + return error_message From c8f128fa00578e033bf42c00c79e5cc45fd51f53 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:42:27 -0500 Subject: [PATCH 03/22] Add CreateBranch class for create_branch function --- tools/github_tool_functions/create_branch.py | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tools/github_tool_functions/create_branch.py diff --git a/tools/github_tool_functions/create_branch.py b/tools/github_tool_functions/create_branch.py new file mode 100644 index 0000000..b103179 --- /dev/null +++ b/tools/github_tool_functions/create_branch.py @@ -0,0 +1,58 @@ +import requests +import logging + +class CreateBranch: + def __init__(self, base_url, token, repo, current_branch): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('create_branch.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 __call__(self, branch_name, base_branch="main"): + self.logger.info(f"Creating branch: {branch_name} from base: {base_branch}") + url = f"{self.base_url}/repos/{self.repo}/git/refs" + response = requests.get(f"{url}/heads/{base_branch}", headers=self.headers) + if response.status_code != 200: + error_message = f"Error getting base branch: {response.status_code}" + self.logger.error(error_message) + return error_message + + sha = response.json()["object"]["sha"] + data = { + "ref": f"refs/heads/{branch_name}", + "sha": sha + } + response = requests.post(url, headers=self.headers, json=data) + if response.status_code == 201: + self.current_branch = branch_name + success_message = f"Branch '{branch_name}' created successfully and set as current branch" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error creating branch: {response.status_code}" + self.logger.error(error_message) + return error_message From 385e74be026a9da73b862f6c675a899947eef227 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:44:45 -0500 Subject: [PATCH 04/22] Add CommitFile class for commit_file function with JSON definition --- tools/github_tool_functions/commit_file.py | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tools/github_tool_functions/commit_file.py diff --git a/tools/github_tool_functions/commit_file.py b/tools/github_tool_functions/commit_file.py new file mode 100644 index 0000000..a31d36a --- /dev/null +++ b/tools/github_tool_functions/commit_file.py @@ -0,0 +1,94 @@ +import base64 +import requests +import logging + +class CommitFile: + def __init__(self, base_url, token, repo, current_branch): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('commit_file.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 __call__(self, file_path, content, commit_message): + self.logger.info(f"Committing file: {file_path} to branch: {self.current_branch}") + if self.current_branch == "main": + error_message = "Cannot commit directly to main branch" + self.logger.error(error_message) + return error_message + + url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}" + + self.logger.info("Checking if file already exists") + response = requests.get(url, headers=self.headers, params={"ref": self.current_branch}) + + data = { + "message": commit_message, + "content": base64.b64encode(content.encode()).decode(), + "branch": self.current_branch + } + + if response.status_code == 200: + self.logger.info("File exists, updating") + file_sha = response.json()["sha"] + data["sha"] = file_sha + else: + self.logger.info("File does not exist, creating new file") + + response = requests.put(url, headers=self.headers, json=data) + + if response.status_code in [200, 201]: + success_message = f"File committed successfully to branch '{self.current_branch}'" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error committing file: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the commit_file function +commit_file_definition = { + "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"] + } +} \ No newline at end of file From c657c9e87b90a1d61a37b1c47434a2d632212ea6 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:46:03 -0500 Subject: [PATCH 05/22] Add CreatePullRequest class for create_pull_request function with JSON definition --- .../create_pull_request.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tools/github_tool_functions/create_pull_request.py diff --git a/tools/github_tool_functions/create_pull_request.py b/tools/github_tool_functions/create_pull_request.py new file mode 100644 index 0000000..84304e5 --- /dev/null +++ b/tools/github_tool_functions/create_pull_request.py @@ -0,0 +1,77 @@ +import requests +import logging + +class CreatePullRequest: + def __init__(self, base_url, token, repo, current_branch): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('create_pull_request.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 __call__(self, title, body, base="main"): + self.logger.info(f"Creating pull request: {title} from {self.current_branch} to {base}") + url = f"{self.base_url}/repos/{self.repo}/pulls" + data = { + "title": title, + "body": body, + "head": self.current_branch, + "base": base + } + response = requests.post(url, headers=self.headers, json=data) + if response.status_code == 201: + success_message = f"Pull request created successfully: {response.json()['html_url']}" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error creating pull request: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the create_pull_request function +create_pull_request_definition = { + "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"] + } +} \ No newline at end of file From fea5ea117e209f0f099e9b2e2963fea2ad0c38b9 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:46:17 -0500 Subject: [PATCH 06/22] Add ListFiles class for list_files function with JSON definition --- tools/github_tool_functions/list_files.py | 63 +++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tools/github_tool_functions/list_files.py diff --git a/tools/github_tool_functions/list_files.py b/tools/github_tool_functions/list_files.py new file mode 100644 index 0000000..d9aa572 --- /dev/null +++ b/tools/github_tool_functions/list_files.py @@ -0,0 +1,63 @@ +import requests +import logging + +class ListFiles: + def __init__(self, base_url, token, repo, current_branch): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('list_files.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 __call__(self, path): + self.logger.info(f"Listing files in: {path} on branch: {self.current_branch}") + url = f"{self.base_url}/repos/{self.repo}/contents/{path}" + response = requests.get(url, headers=self.headers, params={"ref": self.current_branch}) + if response.status_code == 200: + files = [item["name"] for item in response.json() if item["type"] == "file"] + directories = [item["name"] for item in response.json() if item["type"] == "dir"] + self.logger.info(f"Successfully listed files and directories in {path}") + return {"files": files, "directories": directories} + else: + error_message = f"Error listing files: {response.status_code}" + self.logger.error(error_message) + return error_message + +# JSON definition for the list_files function +list_files_definition = { + "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"] + } +} \ No newline at end of file From 0e7b9834736767ec481e50684ac3dd05005d4795 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:46:28 -0500 Subject: [PATCH 07/22] Add SearchCode class for search_code function with JSON definition --- tools/github_tool_functions/search_code.py | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tools/github_tool_functions/search_code.py diff --git a/tools/github_tool_functions/search_code.py b/tools/github_tool_functions/search_code.py new file mode 100644 index 0000000..ec06a4e --- /dev/null +++ b/tools/github_tool_functions/search_code.py @@ -0,0 +1,65 @@ +import requests +import logging + +class SearchCode: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('search_code.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 __call__(self, query): + self.logger.info(f"Searching code with query: {query}") + url = f"{self.base_url}/search/code" + params = { + "q": f"{query} repo:{self.repo}", + "per_page": 10 + } + response = requests.get(url, headers=self.headers, params=params) + if response.status_code == 200: + results = [{"file": item["path"], "url": item["html_url"]} for item in response.json()["items"]] + self.logger.info(f"Successfully searched code. Found {len(results)} results.") + return results + else: + error_message = f"Error searching code: {response.status_code}" + self.logger.error(error_message) + return error_message + +# JSON definition for the search_code function +search_code_definition = { + "name": "search_code", + "description": "Search for code in the repository", + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "Search query" + } + }, + "required": ["query"] + } +} \ No newline at end of file From bcea167299cd9b37fe4567ad72cac6d4b7dc3ecd Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:46:42 -0500 Subject: [PATCH 08/22] Add GetCommitHistory class for get_commit_history function with JSON definition --- .../get_commit_history.py | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tools/github_tool_functions/get_commit_history.py diff --git a/tools/github_tool_functions/get_commit_history.py b/tools/github_tool_functions/get_commit_history.py new file mode 100644 index 0000000..a6d47d2 --- /dev/null +++ b/tools/github_tool_functions/get_commit_history.py @@ -0,0 +1,70 @@ +import requests +import logging + +class GetCommitHistory: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('get_commit_history.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 __call__(self, file_path, num_commits=10): + self.logger.info(f"Getting commit history for file: {file_path}, number of commits: {num_commits}") + url = f"{self.base_url}/repos/{self.repo}/commits" + params = { + "path": file_path, + "per_page": num_commits + } + response = requests.get(url, headers=self.headers, params=params) + if response.status_code == 200: + commits = [{"sha": commit["sha"], "message": commit["commit"]["message"], "date": commit["commit"]["author"]["date"]} for commit in response.json()] + self.logger.info(f"Successfully retrieved commit history. Found {len(commits)} commits.") + return commits + else: + error_message = f"Error getting commit history: {response.status_code}" + self.logger.error(error_message) + return error_message + +# JSON definition for the get_commit_history function +get_commit_history_definition = { + "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"] + } +} \ No newline at end of file From 033a9e7fc691c201fea587e21f2d5c05dadbc16d Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:46:50 -0500 Subject: [PATCH 09/22] Add GetCurrentBranch class for get_current_branch function with JSON definition --- .../get_current_branch.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tools/github_tool_functions/get_current_branch.py diff --git a/tools/github_tool_functions/get_current_branch.py b/tools/github_tool_functions/get_current_branch.py new file mode 100644 index 0000000..18c3139 --- /dev/null +++ b/tools/github_tool_functions/get_current_branch.py @@ -0,0 +1,37 @@ +import logging + +class GetCurrentBranch: + def __init__(self, current_branch): + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('get_current_branch.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 __call__(self): + self.logger.info(f"Getting current branch: {self.current_branch}") + return self.current_branch + +# JSON definition for the get_current_branch function +get_current_branch_definition = { + "name": "get_current_branch", + "description": "Get the name of the current branch", + "parameters": {} +} \ No newline at end of file From 9aa00dd302de4fbb7518dba0129d184682617bf0 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:46:59 -0500 Subject: [PATCH 10/22] Add SetCurrentBranch class for set_current_branch function with JSON definition --- .../set_current_branch.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tools/github_tool_functions/set_current_branch.py diff --git a/tools/github_tool_functions/set_current_branch.py b/tools/github_tool_functions/set_current_branch.py new file mode 100644 index 0000000..f4460ae --- /dev/null +++ b/tools/github_tool_functions/set_current_branch.py @@ -0,0 +1,47 @@ +import logging + +class SetCurrentBranch: + def __init__(self, current_branch): + self.current_branch = current_branch + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('set_current_branch.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 __call__(self, branch_name): + self.logger.info(f"Setting current branch from {self.current_branch} to {branch_name}") + self.current_branch = branch_name + return f"Current branch set to: {self.current_branch}" + +# JSON definition for the set_current_branch function +set_current_branch_definition = { + "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"] + } +} \ No newline at end of file From eb3506ed782b94311161d7ec3d5450607edee789 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:47:14 -0500 Subject: [PATCH 11/22] Add GetFileAtCommit class for get_file_at_commit function with JSON definition --- .../get_file_at_commit.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tools/github_tool_functions/get_file_at_commit.py diff --git a/tools/github_tool_functions/get_file_at_commit.py b/tools/github_tool_functions/get_file_at_commit.py new file mode 100644 index 0000000..0234d74 --- /dev/null +++ b/tools/github_tool_functions/get_file_at_commit.py @@ -0,0 +1,67 @@ +import base64 +import requests +import logging + +class GetFileAtCommit: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('get_file_at_commit.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 __call__(self, file_path, commit_sha): + self.logger.info(f"Getting file: {file_path} at commit: {commit_sha}") + url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}" + response = requests.get(url, headers=self.headers, params={"ref": commit_sha}) + if response.status_code == 200: + content = response.json()["content"] + decoded_content = base64.b64decode(content).decode('utf-8') + self.logger.info(f"Successfully retrieved file at commit") + return decoded_content + else: + error_message = f"Error reading file at commit: {response.status_code}" + self.logger.error(error_message) + return error_message + +# JSON definition for the get_file_at_commit function +get_file_at_commit_definition = { + "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"] + } +} \ No newline at end of file From 6352bee7b8dc40a6fe85edb6dfc86e36cb6f0491 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:47:29 -0500 Subject: [PATCH 12/22] Add ListBranches class for list_branches function with JSON definition --- tools/github_tool_functions/list_branches.py | 82 ++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tools/github_tool_functions/list_branches.py diff --git a/tools/github_tool_functions/list_branches.py b/tools/github_tool_functions/list_branches.py new file mode 100644 index 0000000..7b9c4fd --- /dev/null +++ b/tools/github_tool_functions/list_branches.py @@ -0,0 +1,82 @@ +import requests +import logging + +class ListBranches: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('list_branches.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 __call__(self, per_page=100, all_pages=True): + self.logger.info(f"Listing branches. Per page: {per_page}, All pages: {all_pages}") + url = f"{self.base_url}/repos/{self.repo}/branches" + params = {"per_page": min(per_page, 100)} # GitHub API max is 100 per page + all_branches = [] + + while url: + self.logger.info(f"Fetching branches from: {url}") + response = requests.get(url, headers=self.headers, params=params) + if response.status_code != 200: + error_message = f"Error listing branches: {response.status_code}" + self.logger.error(error_message) + return error_message + + branches = [branch["name"] for branch in response.json()] + all_branches.extend(branches) + self.logger.info(f"Fetched {len(branches)} branches") + + if not all_pages: + break + + # Check if there's a next page + url = response.links.get('next', {}).get('url') + if url: + params = {} # Remove per_page for subsequent requests + + self.logger.info(f"Successfully listed all branches. Total: {len(all_branches)}") + return all_branches + +# JSON definition for the list_branches function +list_branches_definition = { + "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 + } + } + } +} \ No newline at end of file From 648949e49212418a018db344d5193e42d37ae07e Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:47:39 -0500 Subject: [PATCH 13/22] Add GetBranchSHA class for get_branch_sha function with JSON definition --- tools/github_tool_functions/get_branch_sha.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tools/github_tool_functions/get_branch_sha.py diff --git a/tools/github_tool_functions/get_branch_sha.py b/tools/github_tool_functions/get_branch_sha.py new file mode 100644 index 0000000..f981d11 --- /dev/null +++ b/tools/github_tool_functions/get_branch_sha.py @@ -0,0 +1,56 @@ +import requests +import logging + +class GetBranchSHA: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('get_branch_sha.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 __call__(self, branch): + url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch}" + response = requests.get(url, headers=self.headers) + if response.status_code == 200: + return response.json()["object"]["sha"] + else: + return f"Error getting branch SHA: {response.status_code}" + +# JSON definition for the get_branch_sha function +get_branch_sha_definition = { + "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"] + } +} \ No newline at end of file From 36e837d3424434c957fc1af27062a4f56fca1d74 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:47:50 -0500 Subject: [PATCH 14/22] Add ApprovePullRequest class for approve_pull_request function with JSON definition --- .../approve_pull_request.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tools/github_tool_functions/approve_pull_request.py diff --git a/tools/github_tool_functions/approve_pull_request.py b/tools/github_tool_functions/approve_pull_request.py new file mode 100644 index 0000000..66b27c4 --- /dev/null +++ b/tools/github_tool_functions/approve_pull_request.py @@ -0,0 +1,64 @@ +import requests +import logging + +class ApprovePullRequest: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('approve_pull_request.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 __call__(self, pull_number): + self.logger.info(f"Approving pull request: {pull_number}") + url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/reviews" + data = { + "event": "APPROVE" + } + response = requests.post(url, headers=self.headers, json=data) + if response.status_code == 200: + success_message = f"Pull request {pull_number} approved successfully" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error approving pull request: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the approve_pull_request function +approve_pull_request_definition = { + "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"] + } +} \ No newline at end of file From b67ab7a8475d11982e796469869cf73b5eaa126f Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:48:01 -0500 Subject: [PATCH 15/22] Add ClosePullRequest class for close_pull_request function with JSON definition --- .../close_pull_request.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tools/github_tool_functions/close_pull_request.py diff --git a/tools/github_tool_functions/close_pull_request.py b/tools/github_tool_functions/close_pull_request.py new file mode 100644 index 0000000..96ef53d --- /dev/null +++ b/tools/github_tool_functions/close_pull_request.py @@ -0,0 +1,64 @@ +import requests +import logging + +class ClosePullRequest: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('close_pull_request.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 - %(levellevel)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 __call__(self, pull_number): + self.logger.info(f"Closing pull request: {pull_number}") + url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}" + data = { + "state": "closed" + } + response = requests.patch(url, headers=this.headers, json=data) + if response.status_code == 200: + success_message = f"Pull request {pull_number} closed successfully" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error closing pull request: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the close_pull_request function +close_pull_request_definition = { + "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"] + } +} \ No newline at end of file From 28b793a2ef85645de83ccd3883365b6e931cbd38 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:48:17 -0500 Subject: [PATCH 16/22] Add MergePullRequest class for merge_pull_request function with JSON definition --- .../merge_pull_request.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tools/github_tool_functions/merge_pull_request.py diff --git a/tools/github_tool_functions/merge_pull_request.py b/tools/github_tool_functions/merge_pull_request.py new file mode 100644 index 0000000..9f00b58 --- /dev/null +++ b/tools/github_tool_functions/merge_pull_request.py @@ -0,0 +1,82 @@ +import requests +import logging + +class MergePullRequest: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('merge_pull_request.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 - %(levellevel)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 __call__(self, pull_number, commit_title, commit_message, merge_method): + self.logger.info(f"Merging pull request: {pull_number}") + url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/merge" + data = { + "commit_title": commit_title, + "commit_message": commit_message, + "merge_method": merge_method + } + response =.requests.put(url, headers=self.headers, json=data) + if response.status_code == 200: + success_message = f"Pull request {pull_number} merged successfully" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error merging pull request: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the merge_pull_request function +merge_pull_request_definition = { + "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"] + } +} \ No newline at end of file From bf7ed4a60425e31f1b43fdf280dc42caa23da2d1 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:48:29 -0500 Subject: [PATCH 17/22] Add DeleteBranch class for delete_branch function with JSON definition --- tools/github_tool_functions/delete_branch.py | 61 ++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tools/github_tool_functions/delete_branch.py diff --git a/tools/github_tool_functions/delete_branch.py b/tools/github_tool_functions/delete_branch.py new file mode 100644 index 0000000..438112e --- /dev/null +++ b/tools/github_tool_functions/delete_branch.py @@ -0,0 +1,61 @@ +import requests +import logging + +class DeleteBranch: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('delete_branch.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 - %(levellevel)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 __call__(self, branch_name): + self.logger.info(f"Deleting branch: {branch_name}") + url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch_name}" + response = requests.delete(url, headers=self.headers) + if response.status_code == 204: + success_message = f"Branch {branch_name} deleted successfully" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error deleting branch: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the delete_branch function +delete_branch_definition = { + "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"] + } +} \ No newline at end of file From 995a485071c34ca91c7b1fa6b1caded54a640f53 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:48:45 -0500 Subject: [PATCH 18/22] Add GetIssueDetails class for get_issue_details function with JSON definition --- .../get_issue_details.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tools/github_tool_functions/get_issue_details.py diff --git a/tools/github_tool_functions/get_issue_details.py b/tools/github_tool_functions/get_issue_details.py new file mode 100644 index 0000000..3ae6d3d --- /dev/null +++ b/tools/github_tool_functions/get_issue_details.py @@ -0,0 +1,72 @@ +import requests +import logging + +class GetIssueDetails: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('get_issue_details.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 - %(levellevel)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 __call__(self, issue_number): + self.logger.info(f"Getting details for issue: {issue_number}") + url = f"{self.base_url}/repos/{self.repo}/issues/{issue_number}" + response = requests.get(url, headers=self.headers) + if response.status_code == 200: + issue_data = response.json() + issue_details = { + "number": issue_data["number"], + "title": issue_data["title"], + "state": issue_data["state"], + "body": issue_data["body"], + "created_at": issue_data["created_at"], + "updated_at": issue_data["updated_at"], + "labels": [label["name"] for label in issue_data["labels"]], + "assignees": [assignee["login"] for assignee in issue_data["assignees"]], + "comments": issue_data["comments"] + } + self.logger.info(f"Successfully retrieved details for issue {issue_number}") + return issue_details + else: + error_message = f"Error getting issue details: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the get_issue_details function +get_issue_details_definition = { + "name": "get_issue_details", + "description": "Get details of a specific issue", + "parameters": { + "type": "object", + "properties": { + "issue_number": { + "type": "integer", + "description": "The number of the issue" + } + }, + "required": ["issue_number"] + } +} \ No newline at end of file From 8a9b08313fc5c4a7ff027ea75e27ad3ffdbb5be7 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:48:56 -0500 Subject: [PATCH 19/22] Add CreateIssue class for create_issue function with JSON definition --- tools/github_tool_functions/create_issue.py | 79 +++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tools/github_tool_functions/create_issue.py diff --git a/tools/github_tool_functions/create_issue.py b/tools/github_tool_functions/create_issue.py new file mode 100644 index 0000000..4892e7f --- /dev/null +++ b/tools/github_tool_functions/create_issue.py @@ -0,0 +1,79 @@ +import requests +import logging + +class CreateIssue: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('create_issue.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 - %(levellevel)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 __call__(self, title, body, labels=None): + self.logger.info(f"Creating issue: {title}") + url = f"{self.base_url}/repos/{self.repo}/issues" + data = { + "title": title, + "body": body + } + if labels: + data["labels"] = labels + response = requests.post(url, headers=self.headers, json=data) + if response.status_code == 201: + issue = response.json() + success_message = f"Issue created successfully: {issue['html_url']}" + self.logger.info(success_message) + return success_message + else: + error_message = f"Error creating issue: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the create_issue function +create_issue_definition = { + "name": "create_issue", + "description": "Create a new issue in the repository", + "parameters": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the issue" + }, + "body": { + "type": "string", + "description": "Body of the issue" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels to apply to the issue" + } + }, + "required": ["title", "body"] + } +} \ No newline at end of file From 68a30cf5e188b83290add0ebda08fc6099a882f2 Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:49:12 -0500 Subject: [PATCH 20/22] Add ListIssues class for list_issues function with JSON definition --- tools/github_tool_functions/list_issues.py | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 tools/github_tool_functions/list_issues.py diff --git a/tools/github_tool_functions/list_issues.py b/tools/github_tool_functions/list_issues.py new file mode 100644 index 0000000..0a5c36b --- /dev/null +++ b/tools/github_tool_functions/list_issues.py @@ -0,0 +1,83 @@ +import requests +import logging + +class ListIssues: + def __init__(self, base_url, token, repo): + self.base_url = base_url + self.headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json" + } + self.repo = repo + + # Set up logging + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.INFO) + + # Create a file handler + file_handler = logging.FileHandler('list_issues.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 - %(levellevel)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 __call__(self, state="open", per_page=30, page=1): + self.logger.info(f"Listing issues. State: {state}, Per page: {per_page}, Page: {page}") + url = f"{self.base_url}/repos/{self.repo}/issues" + params = { + "state": state, + "per_page": per_page, + "page": page + } + response = requests.get(url, headers=this.headers, params=params) + if response.status_code == 200: + issues = [{ + "number": issue["number"], + "title": issue["title"], + "state": issue["state"], + "created_at": issue["created_at"], + "url": issue["html_url"] + } for issue in response.json()] + self.logger.info(f"Successfully listed issues. Found {len(issues)} issues.") + return issues + else: + error_message = f"Error listing issues: {response.status_code}\nResponse: {response.text}" + self.logger.error(error_message) + return error_message + +# JSON definition for the list_issues function +list_issues_definition = { + "name": "list_issues", + "description": "List issues in the repository", + "parameters": { + "type": "object", + "properties": { + "state": { + "type": "string", + "enum": ["open", "closed", "all"], + "default": "open", + "description": "State of the issues to retrieve" + }, + "per_page": { + "type": "integer", + "default": 30, + "description": "Number of issues to return per page" + }, + "page": { + "type": "integer", + "default": 1, + "description": "Page number of the results to fetch" + } + } + } +} \ No newline at end of file From bd19895e9035dea334cd3eda77249761b8252ccc Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 15:49:31 -0500 Subject: [PATCH 21/22] Refactor github_tool.py to utilize new class-based functions --- tools/github_tool.py | 836 ++++--------------------------------------- 1 file changed, 69 insertions(+), 767 deletions(-) diff --git a/tools/github_tool.py b/tools/github_tool.py index f838a5b..ac38afa 100644 --- a/tools/github_tool.py +++ b/tools/github_tool.py @@ -1,778 +1,80 @@ -# tools/github_tool.py -from .base_tool import BaseTool -from .metrics import metrics -import requests -import os -import base64 -import logging +from .github_tool_functions.read_file import ReadFile, read_file_definition +from .github_tool_functions.create_branch import CreateBranch, create_branch_definition +from .github_tool_functions.commit_file import CommitFile, commit_file_definition +from .github_tool_functions.create_pull_request import CreatePullRequest, create_pull_request_definition +from .github_tool_functions.list_files import ListFiles, list_files_definition +from .github_tool_functions.search_code import SearchCode, search_code_definition +from .github_tool_functions.get_commit_history import GetCommitHistory, get_commit_history_definition +from .github_tool_functions.get_current_branch import GetCurrentBranch, get_current_branch_definition +from .github_tool_functions.set_current_branch import SetCurrentBranch, set_current_branch_definition +from .github_tool_functions.get_file_at_commit import GetFileAtCommit, get_file_at_commit_definition +from .github_tool_functions.list_branches import ListBranches, list_branches_definition +from .github_tool_functions.get_branch_sha import GetBranchSHA, get_branch_sha_definition +from .github_tool_functions.approve_pull_request import ApprovePullRequest, approve_pull_request_definition +from .github_tool_functions.close_pull_request import ClosePullRequest, close_pull_request_definition +from .github_tool_functions.merge_pull_request import MergePullRequest, merge_pull_request_definition +from .github_tool_functions.delete_branch import DeleteBranch, delete_branch_definition +from .github_tool_functions.get_issue_details import GetIssueDetails, get_issue_details_definition +from .github_tool_functions.create_issue import CreateIssue, create_issue_definition +from .github_tool_functions.list_issues import ListIssues, list_issues_definition -class GitHubTool(BaseTool): + +class GitHubTool: 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) + self.instances = { + "read_file": ReadFile(self.base_url, self.token, self.repo, self.current_branch), + "create_branch": CreateBranch(self.base_url, self.token, self.repo, self.current_branch), + "commit_file": CommitFile(self.base_url, self.token, self.repo, self.current_branch), + "create_pull_request": CreatePullRequest(self.base_url, self.token, self.repo, self.current_branch), + "list_files": ListFiles(self.base_url, self.token, self.repo, self.current_branch), + "search_code": SearchCode(self.base_url, self.token, self.repo), + "get_commit_history": GetCommitHistory(self.base_url, self.token, self.repo), + "get_current_branch": GetCurrentBranch(self.current_branch), + "set_current_branch": SetCurrentBranch(self.current_branch), + "get_file_at_commit": GetFileAtCommit(self.base_url, self.token, self.repo), + "list_branches": ListBranches(self.base_url, self.token, self.repo), + "get_branch_sha": GetBranchSHA(self.base_url, self.token, self.repo), + "approve_pull_request": ApprovePullRequest(self.base_url, self.token, self.repo), + "close_pull_request": ClosePullRequest(self.base_url, self.token, self.repo), + "merge_pull_request": MergePullRequest(self.base_url, self.token, self.repo), + "delete_branch": DeleteBranch(self.base_url, self.token, self.repo), + "get_issue_details": GetIssueDetails(self.base_url, self.token, self.repo), + "create_issue": CreateIssue(self.base_url, self.token, self.repo), + "list_issues": ListIssues(self.base_url, self.token, self.repo) + } + + def execute(self, function_name, **kwargs): + if function_name in self.instances: + return self.instances[function_name](**kwargs) + else: + error_message = f"Unknown function: {function_name}" + return {"error": error_message} - 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"] - } - }, - { - "name": "get_issue_details", - "description": "Get details of a specific issue", - "parameters": { - "type": "object", - "properties": { - "issue_number": { - "type": "integer", - "description": "The number of the issue" - } - }, - "required": ["issue_number"] - } - }, - { - "name": "create_issue", - "description": "Create a new issue in the repository", - "parameters": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "Title of the issue" - }, - "body": { - "type": "string", - "description": "Body of the issue" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels to apply to the issue" - } - }, - "required": ["title", "body"] - } - }, - { - "name": "list_issues", - "description": "List issues in the repository", - "parameters": { - "type": "object", - "properties": { - "state": { - "type": "string", - "enum": ["open", "closed", "all"], - "default": "open", - "description": "State of the issues to retrieve" - }, - "per_page": { - "type": "integer", - "default": 30, - "description": "Number of issues to return per page" - }, - "page": { - "type": "integer", - "default": 1, - "description": "Page number of the results to fetch" - } - } - } - } - ] - - @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"]) - elif function_name == "get_issue_details": - return self._get_issue_details(kwargs["issue_number"]) - elif function_name == "create_issue": - return self._create_issue(kwargs["title"], kwargs["body"], kwargs.get("labels", [])) - elif function_name == "list_issues": - return self._list_issues(kwargs.get("state", "open"), kwargs.get("per_page", 30), kwargs.get("page", 1)) - else: - error_message = f"Unknown function: {function_name}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _read_file(self, path): - self.logger.info(f"Reading file: {path} from branch: {self.current_branch}") - url = f"{self.base_url}/repos/{self.repo}/contents/{path}" - response = requests.get(url, headers=self.headers, params={"ref": self.current_branch}) - if response.status_code == 200: - content = response.json()["content"] - decoded_content = base64.b64decode(content).decode('utf-8') - self.logger.info(f"Successfully read file: {path}") - return decoded_content - else: - error_message = f"Error reading file: {response.status_code}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _create_branch(self, branch_name, base_branch): - self.logger.info(f"Creating branch: {branch_name} from base: {base_branch}") - url = f"{self.base_url}/repos/{self.repo}/git/refs" - response = requests.get(f"{url}/heads/{base_branch}", headers=self.headers) - if response.status_code != 200: - error_message = f"Error getting base branch: {response.status_code}" - self.logger.error(error_message) - return error_message - - sha = response.json()["object"]["sha"] - data = { - "ref": f"refs/heads/{branch_name}", - "sha": sha - } - response = requests.post(url, headers=self.headers, json=data) - if response.status_code == 201: - self.current_branch = branch_name - success_message = f"Branch '{branch_name}' created successfully and set as current branch" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error creating branch: {response.status_code}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _commit_file(self, file_path, content, commit_message): - self.logger.info(f"Committing file: {file_path} to branch: {self.current_branch}") - if self.current_branch == "main": - error_message = "Cannot commit directly to main branch" - self.logger.error(error_message) - return error_message - - url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}" - - self.logger.info("Checking if file already exists") - response = requests.get(url, headers=self.headers, params={"ref": self.current_branch}) - - data = { - "message": commit_message, - "content": base64.b64encode(content.encode()).decode(), - "branch": self.current_branch - } - - if response.status_code == 200: - self.logger.info("File exists, updating") - file_sha = response.json()["sha"] - data["sha"] = file_sha - else: - self.logger.info("File does not exist, creating new file") - - response = requests.put(url, headers=self.headers, json=data) - - if response.status_code in [200, 201]: - success_message = f"File committed successfully to branch '{self.current_branch}'" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error committing file: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _create_pull_request(self, title, body, base): - self.logger.info(f"Creating pull request: {title} from {self.current_branch} to {base}") - url = f"{self.base_url}/repos/{self.repo}/pulls" - data = { - "title": title, - "body": body, - "head": self.current_branch, - "base": base - } - response = requests.post(url, headers=self.headers, json=data) - if response.status_code == 201: - success_message = f"Pull request created successfully: {response.json()['html_url']}" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error creating pull request: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _get_branch_sha(self, branch): - url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch}" - response = requests.get(url, headers=self.headers) - if response.status_code == 200: - return response.json()["object"]["sha"] - else: - return f"Error getting branch SHA: {response.status_code}" - - @metrics.measure - def _list_files(self, path): - self.logger.info(f"Listing files in: {path} on branch: {self.current_branch}") - url = f"{self.base_url}/repos/{self.repo}/contents/{path}" - response = requests.get(url, headers=self.headers, params={"ref": self.current_branch}) - if response.status_code == 200: - files = [item["name"] for item in response.json() if item["type"] == "file"] - directories = [item["name"] for item in response.json() if item["type"] == "dir"] - self.logger.info(f"Successfully listed files and directories in {path}") - return {"files": files, "directories": directories} - else: - error_message = f"Error listing files: {response.status_code}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _search_code(self, query): - self.logger.info(f"Searching code with query: {query}") - url = f"{self.base_url}/search/code" - params = { - "q": f"{query} repo:{self.repo}", - "per_page": 10 - } - response = requests.get(url, headers=self.headers, params=params) - if response.status_code == 200: - results = [{"file": item["path"], "url": item["html_url"]} for item in response.json()["items"]] - self.logger.info(f"Successfully searched code. Found {len(results)} results.") - return results - else: - error_message = f"Error searching code: {response.status_code}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _get_commit_history(self, file_path, num_commits): - self.logger.info(f"Getting commit history for file: {file_path}, number of commits: {num_commits}") - url = f"{self.base_url}/repos/{self.repo}/commits" - params = { - "path": file_path, - "per_page": num_commits - } - response = requests.get(url, headers=self.headers, params=params) - if response.status_code == 200: - commits = [{"sha": commit["sha"], "message": commit["commit"]["message"], "date": commit["commit"]["author"]["date"]} for commit in response.json()] - self.logger.info(f"Successfully retrieved commit history. Found {len(commits)} commits.") - return commits - else: - error_message = f"Error getting commit history: {response.status_code}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _get_current_branch(self): - self.logger.info(f"Getting current branch: {self.current_branch}") - return self.current_branch - - @metrics.measure - def _set_current_branch(self, branch_name): - self.logger.info(f"Setting current branch from {self.current_branch} to {branch_name}") - self.current_branch = branch_name - return f"Current branch set to: {self.current_branch}" - - @metrics.measure - def _get_file_at_commit(self, file_path, commit_sha): - self.logger.info(f"Getting file: {file_path} at commit: {commit_sha}") - url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}" - response = requests.get(url, headers=self.headers, params={"ref": commit_sha}) - if response.status_code == 200: - content = response.json()["content"] - decoded_content = base64.b64decode(content).decode('utf-8') - self.logger.info(f"Successfully retrieved file at commit") - return decoded_content - else: - error_message = f"Error reading file at commit: {response.status_code}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _list_branches(self, per_page=100, all_pages=True): - self.logger.info(f"Listing branches. Per page: {per_page}, All pages: {all_pages}") - url = f"{self.base_url}/repos/{self.repo}/branches" - params = {"per_page": min(per_page, 100)} # GitHub API max is 100 per page - all_branches = [] - - while url: - self.logger.info(f"Fetching branches from: {url}") - response = requests.get(url, headers=self.headers, params=params) - if response.status_code != 200: - error_message = f"Error listing branches: {response.status_code}" - self.logger.error(error_message) - return error_message - - branches = [branch["name"] for branch in response.json()] - all_branches.extend(branches) - self.logger.info(f"Fetched {len(branches)} branches") - - if not all_pages: - break - - # Check if there's a next page - url = response.links.get('next', {}).get('url') - if url: - params = {} # Remove per_page for subsequent requests - - self.logger.info(f"Successfully listed all branches. Total: {len(all_branches)}") - return all_branches - - @metrics.measure - def _approve_pull_request(self, pull_number): - self.logger.info(f"Approving pull request: {pull_number}") - url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/reviews" - data = { - "event": "APPROVE" - } - response = requests.post(url, headers=self.headers, json=data) - if response.status_code == 200: - success_message = f"Pull request {pull_number} approved successfully" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error approving pull request: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _close_pull_request(self, pull_number): - self.logger.info(f"Closing pull request: {pull_number}") - url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}" - data = { - "state": "closed" - } - response = requests.patch(url, headers=self.headers, json=data) - if response.status_code == 200: - success_message = f"Pull request {pull_number} closed successfully" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error closing pull request: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _merge_pull_request(self, pull_number, commit_title, commit_message, merge_method): - self.logger.info(f"Merging pull request: {pull_number}") - url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/merge" - data = { - "commit_title": commit_title, - "commit_message": commit_message, - "merge_method": merge_method - } - response = requests.put(url, headers=self.headers, json=data) - if response.status_code == 200: - success_message = f"Pull request {pull_number} merged successfully" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error merging pull request: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _delete_branch(self, branch_name): - self.logger.info(f"Deleting branch: {branch_name}") - url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch_name}" - response = requests.delete(url, headers=self.headers) - if response.status_code == 204: - success_message = f"Branch {branch_name} deleted successfully" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error deleting branch: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - @metrics.measure - def _get_issue_details(self, issue_number): - self.logger.info(f"Getting details for issue: {issue_number}") - url = f"{self.base_url}/repos/{self.repo}/issues/{issue_number}" - response = requests.get(url, headers=self.headers) - if response.status_code == 200: - issue_data = response.json() - issue_details = { - "number": issue_data["number"], - "title": issue_data["title"], - "state": issue_data["state"], - "body": issue_data["body"], - "created_at": issue_data["created_at"], - "updated_at": issue_data["updated_at"], - "labels": [label["name"] for label in issue_data["labels"]], - "assignees": [assignee["login"] for assignee in issue_data["assignees"]], - "comments": issue_data["comments"] - } - self.logger.info(f"Successfully retrieved details for issue {issue_number}") - return issue_details - else: - error_message = f"Error getting issue details: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _create_issue(self, title, body, labels=None): - self.logger.info(f"Creating issue: {title}") - url = f"{self.base_url}/repos/{self.repo}/issues" - data = { - "title": title, - "body": body - } - if labels: - data["labels"] = labels - response = requests.post(url, headers=self.headers, json=data) - if response.status_code == 201: - issue = response.json() - success_message = f"Issue created successfully: {issue['html_url']}" - self.logger.info(success_message) - return success_message - else: - error_message = f"Error creating issue: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message - - @metrics.measure - def _list_issues(self, state="open", per_page=30, page=1): - self.logger.info(f"Listing issues. State: {state}, Per page: {per_page}, Page: {page}") - url = f"{self.base_url}/repos/{self.repo}/issues" - params = { - "state": state, - "per_page": per_page, - "page": page - } - response = requests.get(url, headers=self.headers, params=params) - if response.status_code == 200: - issues = [{ - "number": issue["number"], - "title": issue["title"], - "state": issue["state"], - "created_at": issue["created_at"], - "url": issue["html_url"] - } for issue in response.json()] - self.logger.info(f"Successfully listed issues. Found {len(issues)} issues.") - return issues - else: - error_message = f"Error listing issues: {response.status_code}\nResponse: {response.text}" - self.logger.error(error_message) - return error_message \ No newline at end of file + read_file_definition, + create_branch_definition, + commit_file_definition, + create_pull_request_definition, + list_files_definition, + search_code_definition, + get_commit_history_definition, + get_current_branch_definition, + set_current_branch_definition, + get_file_at_commit_definition, + list_branches_definition, + get_branch_sha_definition, + approve_pull_request_definition, + close_pull_request_definition, + merge_pull_request_definition, + delete_branch_definition, + get_issue_details_definition, + create_issue_definition, + list_issues_definition + ] \ No newline at end of file From 7271c5da8475061f90a2b0afc8373eff3727b5ed Mon Sep 17 00:00:00 2001 From: bucolucas Date: Mon, 19 Aug 2024 16:01:24 -0500 Subject: [PATCH 22/22] Refactor github_tool.py to use consistent JSON definitions --- tools/github_tool.py | 86 ++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 63 deletions(-) diff --git a/tools/github_tool.py b/tools/github_tool.py index ac38afa..4cbb8f8 100644 --- a/tools/github_tool.py +++ b/tools/github_tool.py @@ -1,23 +1,5 @@ -from .github_tool_functions.read_file import ReadFile, read_file_definition -from .github_tool_functions.create_branch import CreateBranch, create_branch_definition -from .github_tool_functions.commit_file import CommitFile, commit_file_definition -from .github_tool_functions.create_pull_request import CreatePullRequest, create_pull_request_definition -from .github_tool_functions.list_files import ListFiles, list_files_definition -from .github_tool_functions.search_code import SearchCode, search_code_definition -from .github_tool_functions.get_commit_history import GetCommitHistory, get_commit_history_definition -from .github_tool_functions.get_current_branch import GetCurrentBranch, get_current_branch_definition -from .github_tool_functions.set_current_branch import SetCurrentBranch, set_current_branch_definition -from .github_tool_functions.get_file_at_commit import GetFileAtCommit, get_file_at_commit_definition -from .github_tool_functions.list_branches import ListBranches, list_branches_definition -from .github_tool_functions.get_branch_sha import GetBranchSHA, get_branch_sha_definition -from .github_tool_functions.approve_pull_request import ApprovePullRequest, approve_pull_request_definition -from .github_tool_functions.close_pull_request import ClosePullRequest, close_pull_request_definition -from .github_tool_functions.merge_pull_request import MergePullRequest, merge_pull_request_definition -from .github_tool_functions.delete_branch import DeleteBranch, delete_branch_definition -from .github_tool_functions.get_issue_details import GetIssueDetails, get_issue_details_definition -from .github_tool_functions.create_issue import CreateIssue, create_issue_definition -from .github_tool_functions.list_issues import ListIssues, list_issues_definition - +import os +import json class GitHubTool: def __init__(self): @@ -26,27 +8,26 @@ class GitHubTool: self.repo = os.environ.get("GITHUB_REPOSITORY") self.current_branch = "main" # Default to main branch - self.instances = { - "read_file": ReadFile(self.base_url, self.token, self.repo, self.current_branch), - "create_branch": CreateBranch(self.base_url, self.token, self.repo, self.current_branch), - "commit_file": CommitFile(self.base_url, self.token, self.repo, self.current_branch), - "create_pull_request": CreatePullRequest(self.base_url, self.token, self.repo, self.current_branch), - "list_files": ListFiles(self.base_url, self.token, self.repo, self.current_branch), - "search_code": SearchCode(self.base_url, self.token, self.repo), - "get_commit_history": GetCommitHistory(self.base_url, self.token, self.repo), - "get_current_branch": GetCurrentBranch(self.current_branch), - "set_current_branch": SetCurrentBranch(self.current_branch), - "get_file_at_commit": GetFileAtCommit(self.base_url, self.token, self.repo), - "list_branches": ListBranches(self.base_url, self.token, self.repo), - "get_branch_sha": GetBranchSHA(self.base_url, self.token, self.repo), - "approve_pull_request": ApprovePullRequest(self.base_url, self.token, self.repo), - "close_pull_request": ClosePullRequest(self.base_url, self.token, self.repo), - "merge_pull_request": MergePullRequest(self.base_url, self.token, self.repo), - "delete_branch": DeleteBranch(self.base_url, self.token, self.repo), - "get_issue_details": GetIssueDetails(self.base_url, self.token, self.repo), - "create_issue": CreateIssue(self.base_url, self.token, self.repo), - "list_issues": ListIssues(self.base_url, self.token, self.repo) - } + self.instances = {} + self.functions = [] + self._load_functions() + + def _load_functions(self): + function_dir = os.path.join(os.path.dirname(__file__), "github_tool_functions") + for filename in os.listdir(function_dir): + if filename.endswith(".py") and filename != "__init__.py": + function_name = filename[:-3] + module = __import__(f"tools.github_tool_functions.{function_name}", fromlist=[function_name.capitalize()]) + class_name = getattr(module, function_name.capitalize()) + self.instances[function_name] = class_name(self.base_url, self.token, self.repo, self.current_branch) + + with open(os.path.join(function_dir, filename), 'r') as f: + content = f.read() + json_start = content.find('{') + json_end = content.rfind('}') + 1 + if json_start != -1 and json_end != -1: + json_def = json.loads(content[json_start:json_end]) + self.functions.append(json_def) def execute(self, function_name, **kwargs): if function_name in self.instances: @@ -55,26 +36,5 @@ class GitHubTool: error_message = f"Unknown function: {function_name}" return {"error": error_message} - def get_functions(self): - return [ - read_file_definition, - create_branch_definition, - commit_file_definition, - create_pull_request_definition, - list_files_definition, - search_code_definition, - get_commit_history_definition, - get_current_branch_definition, - set_current_branch_definition, - get_file_at_commit_definition, - list_branches_definition, - get_branch_sha_definition, - approve_pull_request_definition, - close_pull_request_definition, - merge_pull_request_definition, - delete_branch_definition, - get_issue_details_definition, - create_issue_definition, - list_issues_definition - ] \ No newline at end of file + return self.functions \ No newline at end of file