Added tests
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# GitHub Integration Tool
|
||||
|
||||
The GitHub Integration Tool provides a simple interface to interact with the GitHub repository for the Cyclop project. This tool allows reading files, creating branches, committing changes, and creating pull requests.
|
||||
|
||||
## Functions
|
||||
|
||||
The tool provides the following functions:
|
||||
|
||||
1. `read_file`: Read a file from the repository
|
||||
2. `create_branch`: Create a new branch in the repository
|
||||
3. `commit_file`: Commit a file to a branch (not main)
|
||||
4. `create_pull_request`: Create a pull request
|
||||
|
||||
## Usage
|
||||
|
||||
To use this tool, you need to have the `GITHUB_TOKEN` environment variable set with your GitHub personal access token.
|
||||
|
||||
### Read File
|
||||
|
||||
Reads the content of a file from the repository.
|
||||
|
||||
Parameters:
|
||||
- `path`: The path to the file in the repository
|
||||
|
||||
Example:
|
||||
```python
|
||||
result = github_tool.execute("read_file", path="README.md")
|
||||
print(result) # Prints the content of README.md
|
||||
```
|
||||
|
||||
### Create Branch
|
||||
|
||||
Creates a new branch in the repository.
|
||||
|
||||
Parameters:
|
||||
- `branch_name`: Name of the new branch
|
||||
- `base_branch` (optional): Name of the base branch (default is "main")
|
||||
|
||||
Example:
|
||||
```python
|
||||
result = github_tool.execute("create_branch", branch_name="feature-branch")
|
||||
print(result) # Prints a success message if the branch was created
|
||||
```
|
||||
|
||||
### Commit File
|
||||
|
||||
Commits a file to a specified branch (not main).
|
||||
|
||||
Parameters:
|
||||
- `branch_name`: Name of the branch to commit to
|
||||
- `file_path`: Path to the file in the repository
|
||||
- `content`: Content of the file
|
||||
- `commit_message`: Commit message
|
||||
|
||||
Example:
|
||||
```python
|
||||
result = github_tool.execute(
|
||||
"commit_file",
|
||||
branch_name="feature-branch",
|
||||
file_path="docs/NEW_FEATURE.md",
|
||||
content="# New Feature\n\nThis document describes the new feature.",
|
||||
commit_message="Add documentation for new feature"
|
||||
)
|
||||
print(result) # Prints a success message if the file was committed
|
||||
```
|
||||
|
||||
### Create Pull Request
|
||||
|
||||
Creates a pull request from one branch to another.
|
||||
|
||||
Parameters:
|
||||
- `title`: Title of the pull request
|
||||
- `body`: Body of the pull request
|
||||
- `head`: The name of the branch where your changes are implemented
|
||||
- `base` (optional): The name of the branch you want the changes pulled into (default is "main")
|
||||
|
||||
Example:
|
||||
```python
|
||||
result = github_tool.execute(
|
||||
"create_pull_request",
|
||||
title="Add new feature documentation",
|
||||
body="This PR adds documentation for the new feature.",
|
||||
head="feature-branch"
|
||||
)
|
||||
print(result) # Prints the URL of the created pull request
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
If an error occurs during the execution of any function, an error message will be returned instead of the expected result. Always check the returned value to ensure the operation was successful.
|
||||
|
||||
## Notes
|
||||
|
||||
- This tool uses the GitHub API v3.
|
||||
- Make sure your GitHub token has the necessary permissions to perform these operations.
|
||||
- Committing directly to the main branch is not allowed for safety reasons.
|
||||
@@ -0,0 +1,194 @@
|
||||
# tools/github_tool.py
|
||||
from .base_tool import BaseTool
|
||||
import requests
|
||||
import os
|
||||
|
||||
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")
|
||||
|
||||
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": {
|
||||
"branch_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the branch to commit to"
|
||||
},
|
||||
"file_path": {
|
||||
"type": "string",
|
||||
"description": "Path to the file in the repository"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Content of the file"
|
||||
},
|
||||
"commit_message": {
|
||||
"type": "string",
|
||||
"description": "Commit message"
|
||||
}
|
||||
},
|
||||
"required": ["branch_name", "file_path", "content", "commit_message"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"head": {
|
||||
"type": "string",
|
||||
"description": "The name of the branch where your changes are implemented"
|
||||
},
|
||||
"base": {
|
||||
"type": "string",
|
||||
"description": "The name of the branch you want the changes pulled into",
|
||||
"default": "main"
|
||||
}
|
||||
},
|
||||
"required": ["title", "body", "head"]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
def execute(self, function_name, **kwargs):
|
||||
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["branch_name"], kwargs["file_path"], kwargs["content"], kwargs["commit_message"])
|
||||
elif function_name == "push_branch":
|
||||
return self._push_branch(kwargs["branch_name"])
|
||||
elif function_name == "create_pull_request":
|
||||
return self._create_pull_request(kwargs["title"], kwargs["body"], kwargs["head"], kwargs.get("base", "main"))
|
||||
else:
|
||||
return f"Unknown function: {function_name}"
|
||||
|
||||
|
||||
def _read_file(self, path):
|
||||
url = f"{self.base_url}/repos/{self.repo}/contents/{path}"
|
||||
response = requests.get(url, headers=self.headers)
|
||||
if response.status_code == 200:
|
||||
content = response.json()["content"]
|
||||
return content
|
||||
else:
|
||||
return f"Error reading file: {response.status_code}"
|
||||
|
||||
def _create_branch(self, branch_name, 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:
|
||||
return f"Error getting base branch: {response.status_code}"
|
||||
|
||||
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:
|
||||
return f"Branch '{branch_name}' created successfully"
|
||||
else:
|
||||
return f"Error creating branch: {response.status_code}"
|
||||
|
||||
def _commit_file(self, branch_name, file_path, content, commit_message):
|
||||
if branch_name == "main":
|
||||
return "Cannot commit directly to main branch"
|
||||
|
||||
url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
|
||||
data = {
|
||||
"message": commit_message,
|
||||
"content": content,
|
||||
"branch": branch_name
|
||||
}
|
||||
response = requests.put(url, headers=self.headers, json=data)
|
||||
if response.status_code in [200, 201]:
|
||||
return f"File committed successfully to branch '{branch_name}'"
|
||||
else:
|
||||
return f"Error committing file: {response.status_code}"
|
||||
|
||||
def _create_pull_request(self, title, body, head, base):
|
||||
url = f"{self.base_url}/repos/{self.repo}/pulls"
|
||||
data = {
|
||||
"title": title,
|
||||
"body": body,
|
||||
"head": head,
|
||||
"base": base
|
||||
}
|
||||
response = requests.post(url, headers=self.headers, json=data)
|
||||
if response.status_code == 201:
|
||||
return f"Pull request created successfully: {response.json()['html_url']}"
|
||||
else:
|
||||
return f"Error creating pull request: {response.status_code}\nResponse: {response.text}"
|
||||
|
||||
def _push_branch(self, branch_name):
|
||||
url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch_name}"
|
||||
response = requests.get(url, headers=self.headers)
|
||||
if response.status_code != 200:
|
||||
return f"Error getting branch information: {response.status_code}"
|
||||
|
||||
sha = response.json()["object"]["sha"]
|
||||
|
||||
push_url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch_name}"
|
||||
data = {
|
||||
"sha": sha,
|
||||
"force": True
|
||||
}
|
||||
response = requests.patch(push_url, headers=self.headers, json=data)
|
||||
if response.status_code == 200:
|
||||
return f"Branch '{branch_name}' pushed successfully"
|
||||
else:
|
||||
return f"Error pushing branch: {response.status_code}\nResponse: {response.text}"
|
||||
Reference in New Issue
Block a user