diff --git a/docs/extras/integrations/toolkits/gitlab.ipynb b/docs/extras/integrations/toolkits/gitlab.ipynb new file mode 100644 index 00000000000..a8f28f09fa3 --- /dev/null +++ b/docs/extras/integrations/toolkits/gitlab.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Gitlab\n", + "\n", + "The `Gitlab` toolkit contains tools that enable an LLM agent to interact with a gitlab repository. \n", + "The tool is a wrapper for the [python-gitlab](https://github.com/python-gitlab/python-gitlab) library. \n", + "\n", + "## Quickstart\n", + "1. Install the python-gitlab library\n", + "2. Create a Gitlab personal access token\n", + "3. Set your environmental variables\n", + "4. Pass the tools to your agent with `toolkit.get_tools()`\n", + "\n", + "Each of these steps will be explained in greate detail below.\n", + "\n", + "1. **Get Issues**- fetches issues from the repository.\n", + "\n", + "2. **Get Issue**- feteches details about a specific issue.\n", + "\n", + "3. **Comment on Issue**- posts a comment on a specific issue.\n", + "\n", + "4. **Create Pull Request**- creates a pull request from the bot's working branch to the base branch.\n", + "\n", + "5. **Create File**- creates a new file in the repository.\n", + "\n", + "6. **Read File**- reads a file from the repository.\n", + "\n", + "7. **Update File**- updates a file in the repository.\n", + "\n", + "8. **Delete File**- deletes a file from the repository.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Install the `python-gitlab` library " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "%pip install python-gitlab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Create a Gitlab personal access token\n", + "\n", + "[Follow the instructions here](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) to create a Gitlab personal access token. Make sure your app has the following repository permissions:\n", + "* read_api\n", + "* read_repository\n", + "* write_repository\n", + "\n", + "### 3. Set Environmental Variables\n", + "\n", + "Before initializing your agent, the following environmental variables need to be set:\n", + "\n", + "* **GITLAB_PERSONAL_ACCESS_TOKEN**- The personal access token you created in the last step\n", + "* **GITLAB_REPOSITORY**- The name of the Gitlab repository you want your bot to act upon. Must follow the format {username}/{repo-name}.\n", + "* **GITLAB_BRANCH**- The branch where the bot will make its commits. Defaults to 'main.'\n", + "* **GITLAB_BASE_BRANCH**- The base branch of your repo, usually either 'main' or 'master.' This is where pull requests will base from. Defaults to 'main.'\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example: Simple Agent" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from langchain.agents import AgentType\n", + "from langchain.agents import initialize_agent\n", + "from langchain.agents.agent_toolkits.gitlab.toolkit import GitLabToolkit\n", + "from langchain.llms import OpenAI\n", + "from langchain.utilities.gitlab import GitLabAPIWrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "# Set your environment variables using os.environ\n", + "os.environ[\"GITLAB_PERSONAL_ACCESS_TOKEN\"] = \"\"\n", + "os.environ[\"GITLAB_REPOSITORY\"] = \"username/repo-name\"\n", + "os.environ[\"GITLAB_BRANCH\"] = \"bot-branch-name\"\n", + "os.environ[\"GITLAB_BASE_BRANCH\"] = \"main\"\n", + "\n", + "# This example also requires an OpenAI API key\n", + "os.environ[\"OPENAI_API_KEY\"] = \"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "llm = OpenAI(temperature=0)\n", + "gitlab = GitLabAPIWrapper()\n", + "toolkit = GitLabToolkit.from_gitlab_api_wrapper(gitlab)\n", + "agent = initialize_agent(\n", + " toolkit.get_tools(), llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", + "\u001b[32;1m\u001b[1;3m I need to look at the open issues and figure out how to solve them.\n", + "Action: Get Issues\n", + "Action Input: N/A\u001b[0m\n", + "Observation: \u001b[36;1m\u001b[1;3mFound 1 issues:\n", + "[{'title': 'Add tic-tac-toe game', 'number': 15}]\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m I need to look at the details of this issue to figure out how to solve it.\n", + "Action: Get Issue\n", + "Action Input: 15\u001b[0m\n", + "Observation: \u001b[33;1m\u001b[1;3m{\"title\": \"Add tic-tac-toe game\", \"body\": \"Create a tic-tac-toe game using HTML, CSS, and JavaScript. Create a new file called game.html and store the code there.\", \"comments\": \"[]\"}\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m I need to create the game.html file and add the code.\n", + "Action: Create File\n", + "Action Input: game.html\n", + "\n", + "test contents\u001b[0m\n", + "Observation: \u001b[33;1m\u001b[1;3mCreated file game.html\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m I need to add the code to the game.html file.\n", + "Action: Update File\n", + "Action Input: game.html\n", + "\n", + "OLD <<<<\n", + "test contents\n", + ">>>> OLD\n", + "NEW <<<<\n", + "\n", + " \n", + " Tic-Tac-Toe\n", + " \n", + " \n", + "

Tic-Tac-Toe

\n", + "
\n", + " \n", + "
\n", + " \n", + "\n", + ">>>> NEW\u001b[0m\n", + "Observation: \u001b[36;1m\u001b[1;3mUpdated file game.html\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m I need to create a pull request to submit my changes.\n", + "Action: Create Pull Request\n", + "Action Input: Add tic-tac-toe game\n", + "\n", + "added tic-tac-toe game, closes issue #15\u001b[0m\n", + "Observation: \u001b[36;1m\u001b[1;3mSuccessfully created PR number 12\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n", + "Final Answer: I have created a pull request with number 12 that solves issue 15.\u001b[0m\n", + "\n", + "\u001b[1m> Finished chain.\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "'I have created a pull request with number 12 that solves issue 15.'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "agent.run(\n", + " \"You have the software engineering capabilities of a Google Principle engineer. You are tasked with completing issues on a gitlab repository. Please look at the open issues and complete them by creating pull requests that solve the issues.\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/libs/langchain/langchain/agents/agent_toolkits/gitlab/__init__.py b/libs/langchain/langchain/agents/agent_toolkits/gitlab/__init__.py new file mode 100644 index 00000000000..7d3ca720636 --- /dev/null +++ b/libs/langchain/langchain/agents/agent_toolkits/gitlab/__init__.py @@ -0,0 +1 @@ +"""GitLab Toolkit.""" diff --git a/libs/langchain/langchain/agents/agent_toolkits/gitlab/toolkit.py b/libs/langchain/langchain/agents/agent_toolkits/gitlab/toolkit.py new file mode 100644 index 00000000000..87e83756cc5 --- /dev/null +++ b/libs/langchain/langchain/agents/agent_toolkits/gitlab/toolkit.py @@ -0,0 +1,84 @@ +"""GitHub Toolkit.""" +from typing import Dict, List + +from langchain.agents.agent_toolkits.base import BaseToolkit +from langchain.tools import BaseTool +from langchain.tools.gitlab.prompt import ( + COMMENT_ON_ISSUE_PROMPT, + CREATE_FILE_PROMPT, + CREATE_PULL_REQUEST_PROMPT, + DELETE_FILE_PROMPT, + GET_ISSUE_PROMPT, + GET_ISSUES_PROMPT, + READ_FILE_PROMPT, + UPDATE_FILE_PROMPT, +) +from langchain.tools.gitlab.tool import GitLabAction +from langchain.utilities.gitlab import GitLabAPIWrapper + + +class GitLabToolkit(BaseToolkit): + """GitLab Toolkit.""" + + tools: List[BaseTool] = [] + + @classmethod + def from_gitlab_api_wrapper( + cls, gitlab_api_wrapper: GitLabAPIWrapper + ) -> "GitLabToolkit": + operations: List[Dict] = [ + { + "mode": "get_issues", + "name": "Get Issues", + "description": GET_ISSUES_PROMPT, + }, + { + "mode": "get_issue", + "name": "Get Issue", + "description": GET_ISSUE_PROMPT, + }, + { + "mode": "comment_on_issue", + "name": "Comment on Issue", + "description": COMMENT_ON_ISSUE_PROMPT, + }, + { + "mode": "create_pull_request", + "name": "Create Pull Request", + "description": CREATE_PULL_REQUEST_PROMPT, + }, + { + "mode": "create_file", + "name": "Create File", + "description": CREATE_FILE_PROMPT, + }, + { + "mode": "read_file", + "name": "Read File", + "description": READ_FILE_PROMPT, + }, + { + "mode": "update_file", + "name": "Update File", + "description": UPDATE_FILE_PROMPT, + }, + { + "mode": "delete_file", + "name": "Delete File", + "description": DELETE_FILE_PROMPT, + }, + ] + tools = [ + GitLabAction( + name=action["name"], + description=action["description"], + mode=action["mode"], + api_wrapper=gitlab_api_wrapper, + ) + for action in operations + ] + return cls(tools=tools) + + def get_tools(self) -> List[BaseTool]: + """Get the tools in the toolkit.""" + return self.tools diff --git a/libs/langchain/langchain/tools/gitlab/__init__.py b/libs/langchain/langchain/tools/gitlab/__init__.py new file mode 100644 index 00000000000..4b6d6367663 --- /dev/null +++ b/libs/langchain/langchain/tools/gitlab/__init__.py @@ -0,0 +1 @@ +""" GitLab Tool """ diff --git a/libs/langchain/langchain/tools/gitlab/prompt.py b/libs/langchain/langchain/tools/gitlab/prompt.py new file mode 100644 index 00000000000..3f303155cd4 --- /dev/null +++ b/libs/langchain/langchain/tools/gitlab/prompt.py @@ -0,0 +1,70 @@ +# flake8: noqa +GET_ISSUES_PROMPT = """ +This tool will fetch a list of the repository's issues. It will return the title, and issue number of 5 issues. It takes no input. +""" + +GET_ISSUE_PROMPT = """ +This tool will fetch the title, body, and comment thread of a specific issue. **VERY IMPORTANT**: You must specify the issue number as an integer. +""" + +COMMENT_ON_ISSUE_PROMPT = """ +This tool is useful when you need to comment on a GitLab issue. Simply pass in the issue number and the comment you would like to make. Please use this sparingly as we don't want to clutter the comment threads. **VERY IMPORTANT**: Your input to this tool MUST strictly follow these rules: + +- First you must specify the issue number as an integer +- Then you must place two newlines +- Then you must specify your comment +""" +CREATE_PULL_REQUEST_PROMPT = """ +This tool is useful when you need to create a new pull request in a GitLab repository. **VERY IMPORTANT**: Your input to this tool MUST strictly follow these rules: + +- First you must specify the title of the pull request +- Then you must place two newlines +- Then you must write the body or description of the pull request + +To reference an issue in the body, put its issue number directly after a #. +For example, if you would like to create a pull request called "README updates" with contents "added contributors' names, closes issue #3", you would pass in the following string: + +README updates + +added contributors' names, closes issue #3 +""" +CREATE_FILE_PROMPT = """ +This tool is a wrapper for the GitLab API, useful when you need to create a file in a GitLab repository. **VERY IMPORTANT**: Your input to this tool MUST strictly follow these rules: + +- First you must specify which file to create by passing a full file path (**IMPORTANT**: the path must not start with a slash) +- Then you must specify the contents of the file + +For example, if you would like to create a file called /test/test.txt with contents "test contents", you would pass in the following string: + +test/test.txt + +test contents +""" + +READ_FILE_PROMPT = """ +This tool is a wrapper for the GitLab API, useful when you need to read the contents of a file in a GitLab repository. Simply pass in the full file path of the file you would like to read. **IMPORTANT**: the path must not start with a slash +""" + +UPDATE_FILE_PROMPT = """ +This tool is a wrapper for the GitLab API, useful when you need to update the contents of a file in a GitLab repository. **VERY IMPORTANT**: Your input to this tool MUST strictly follow these rules: + +- First you must specify which file to modify by passing a full file path (**IMPORTANT**: the path must not start with a slash) +- Then you must specify the old contents which you would like to replace wrapped in OLD <<<< and >>>> OLD +- Then you must specify the new contents which you would like to replace the old contents with wrapped in NEW <<<< and >>>> NEW + +For example, if you would like to replace the contents of the file /test/test.txt from "old contents" to "new contents", you would pass in the following string: + +test/test.txt + +This is text that will not be changed +OLD <<<< +old contents +>>>> OLD +NEW <<<< +new contents +>>>> NEW +""" + +DELETE_FILE_PROMPT = """ +This tool is a wrapper for the GitLab API, useful when you need to delete a file in a GitLab repository. Simply pass in the full file path of the file you would like to delete. **IMPORTANT**: the path must not start with a slash +""" diff --git a/libs/langchain/langchain/tools/gitlab/tool.py b/libs/langchain/langchain/tools/gitlab/tool.py new file mode 100644 index 00000000000..fc8105c50af --- /dev/null +++ b/libs/langchain/langchain/tools/gitlab/tool.py @@ -0,0 +1,32 @@ +""" +This tool allows agents to interact with the python-gitlab library +and operate on a GitLab repository. + +To use this tool, you must first set as environment variables: + GITLAB_PRIVATE_ACCESS_TOKEN + GITLAB_REPOSITORY -> format: {owner}/{repo} + +""" +from typing import Optional + +from langchain.callbacks.manager import CallbackManagerForToolRun +from langchain.pydantic_v1 import Field +from langchain.tools.base import BaseTool +from langchain.utilities.gitlab import GitLabAPIWrapper + + +class GitLabAction(BaseTool): + """Tool for interacting with the GitLab API.""" + + api_wrapper: GitLabAPIWrapper = Field(default_factory=GitLabAPIWrapper) + mode: str + name: str = "" + description: str = "" + + def _run( + self, + instructions: str, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the GitLab API to run an operation.""" + return self.api_wrapper.run(self.mode, instructions) diff --git a/libs/langchain/langchain/utilities/gitlab.py b/libs/langchain/langchain/utilities/gitlab.py new file mode 100644 index 00000000000..0ad8db3c995 --- /dev/null +++ b/libs/langchain/langchain/utilities/gitlab.py @@ -0,0 +1,319 @@ +"""Util that calls gitlab.""" +from __future__ import annotations + +import json +from typing import TYPE_CHECKING, Any, Dict, List, Optional + +from langchain.pydantic_v1 import BaseModel, Extra, root_validator +from langchain.utils import get_from_dict_or_env + +if TYPE_CHECKING: + from gitlab.v4.objects import Issue + + +class GitLabAPIWrapper(BaseModel): + """Wrapper for GitLab API.""" + + gitlab: Any #: :meta private: + gitlab_repo_instance: Any #: :meta private: + gitlab_repository: Optional[str] = None + """The name of the GitLab repository, in the form {username}/{repo-name}.""" + gitlab_personal_access_token: Optional[str] = None + """Personal access token for the GitLab service, used for authentication.""" + gitlab_branch: Optional[str] = None + """The specific branch in the GitLab repository where the bot will make + its commits. Defaults to 'main'. + """ + gitlab_base_branch: Optional[str] = None + """The base branch in the GitLab repository, used for comparisons. + Usually 'main' or 'master'. Defaults to 'main'. + """ + + class Config: + """Configuration for this pydantic object.""" + + extra = Extra.forbid + + @root_validator() + def validate_environment(cls, values: Dict) -> Dict: + """Validate that api key and python package exists in environment.""" + gitlab_repository = get_from_dict_or_env( + values, "gitlab_repository", "GITLAB_REPOSITORY" + ) + + gitlab_personal_access_token = get_from_dict_or_env( + values, "gitlab_personal_access_token", "GITLAB_PERSONAL_ACCESS_TOKEN" + ) + + gitlab_branch = get_from_dict_or_env( + values, "gitlab_branch", "GITLAB_BRANCH", default="main" + ) + gitlab_base_branch = get_from_dict_or_env( + values, "gitlab_base_branch", "GITLAB_BASE_BRANCH", default="main" + ) + + try: + import gitlab + + except ImportError: + raise ImportError( + "python-gitlab is not installed. " + "Please install it with `pip install python-gitlab`" + ) + + g = gitlab.Gitlab(private_token=gitlab_personal_access_token) + + g.auth() + + values["gitlab"] = g + values["gitlab_repo_instance"] = g.projects.get(gitlab_repository) + values["gitlab_repository"] = gitlab_repository + values["gitlab_personal_access_token"] = gitlab_personal_access_token + values["gitlab_branch"] = gitlab_branch + values["gitlab_base_branch"] = gitlab_base_branch + + return values + + def parse_issues(self, issues: List[Issue]) -> List[dict]: + """ + Extracts title and number from each Issue and puts them in a dictionary + Parameters: + issues(List[Issue]): A list of gitlab Issue objects + Returns: + List[dict]: A dictionary of issue titles and numbers + """ + parsed = [] + for issue in issues: + title = issue.title + number = issue.iid + parsed.append({"title": title, "number": number}) + return parsed + + def get_issues(self) -> str: + """ + Fetches all open issues from the repo + + Returns: + str: A plaintext report containing the number of issues + and each issue's title and number. + """ + issues = self.gitlab_repo_instance.issues.list(state="opened") + if len(issues) > 0: + parsed_issues = self.parse_issues(issues) + parsed_issues_str = ( + "Found " + str(len(parsed_issues)) + " issues:\n" + str(parsed_issues) + ) + return parsed_issues_str + else: + return "No open issues available" + + def get_issue(self, issue_number: int) -> Dict[str, Any]: + """ + Fetches a specific issue and its first 10 comments + Parameters: + issue_number(int): The number for the gitlab issue + Returns: + dict: A dictionary containing the issue's title, + body, and comments as a string + """ + issue = self.gitlab_repo_instance.issues.get(issue_number) + page = 0 + comments: List[dict] = [] + while len(comments) <= 10: + comments_page = issue.notes.list(page=page) + if len(comments_page) == 0: + break + for comment in comments_page: + comment = issue.notes.get(comment.id) + comments.append( + {"body": comment.body, "user": comment.author["username"]} + ) + page += 1 + + return { + "title": issue.title, + "body": issue.description, + "comments": str(comments), + } + + def create_pull_request(self, pr_query: str) -> str: + """ + Makes a pull request from the bot's branch to the base branch + Parameters: + pr_query(str): a string which contains the PR title + and the PR body. The title is the first line + in the string, and the body are the rest of the string. + For example, "Updated README\nmade changes to add info" + Returns: + str: A success or failure message + """ + if self.gitlab_base_branch == self.gitlab_branch: + return """Cannot make a pull request because + commits are already in the master branch""" + else: + try: + title = pr_query.split("\n")[0] + body = pr_query[len(title) + 2 :] + pr = self.gitlab_repo_instance.mergerequests.create( + { + "source_branch": self.gitlab_branch, + "target_branch": self.gitlab_base_branch, + "title": title, + "description": body, + "labels": ["created-by-agent"], + } + ) + return f"Successfully created PR number {pr.iid}" + except Exception as e: + return "Unable to make pull request due to error:\n" + str(e) + + def comment_on_issue(self, comment_query: str) -> str: + """ + Adds a comment to a gitlab issue + Parameters: + comment_query(str): a string which contains the issue number, + two newlines, and the comment. + for example: "1\n\nWorking on it now" + adds the comment "working on it now" to issue 1 + Returns: + str: A success or failure message + """ + issue_number = int(comment_query.split("\n\n")[0]) + comment = comment_query[len(str(issue_number)) + 2 :] + try: + issue = self.gitlab_repo_instance.issues.get(issue_number) + issue.notes.create({"body": comment}) + return "Commented on issue " + str(issue_number) + except Exception as e: + return "Unable to make comment due to error:\n" + str(e) + + def create_file(self, file_query: str) -> str: + """ + Creates a new file on the gitlab repo + Parameters: + file_query(str): a string which contains the file path + and the file contents. The file path is the first line + in the string, and the contents are the rest of the string. + For example, "hello_world.md\n# Hello World!" + Returns: + str: A success or failure message + """ + file_path = file_query.split("\n")[0] + file_contents = file_query[len(file_path) + 2 :] + try: + self.gitlab_repo_instance.files.get(file_path, self.gitlab_branch) + return f"File already exists at {file_path}. Use update_file instead" + except Exception: + data = { + "branch": self.gitlab_branch, + "commit_message": "Create " + file_path, + "file_path": file_path, + "content": file_contents, + } + + self.gitlab_repo_instance.files.create(data) + + return "Created file " + file_path + + def read_file(self, file_path: str) -> str: + """ + Reads a file from the gitlab repo + Parameters: + file_path(str): the file path + Returns: + str: The file decoded as a string + """ + file = self.gitlab_repo_instance.files.get(file_path, self.gitlab_branch) + return file.decode().decode("utf-8") + + def update_file(self, file_query: str) -> str: + """ + Updates a file with new content. + Parameters: + file_query(str): Contains the file path and the file contents. + The old file contents is wrapped in OLD <<<< and >>>> OLD + The new file contents is wrapped in NEW <<<< and >>>> NEW + For example: + test/hello.txt + OLD <<<< + Hello Earth! + >>>> OLD + NEW <<<< + Hello Mars! + >>>> NEW + Returns: + A success or failure message + """ + try: + file_path = file_query.split("\n")[0] + old_file_contents = ( + file_query.split("OLD <<<<")[1].split(">>>> OLD")[0].strip() + ) + new_file_contents = ( + file_query.split("NEW <<<<")[1].split(">>>> NEW")[0].strip() + ) + + file_content = self.read_file(file_path) + updated_file_content = file_content.replace( + old_file_contents, new_file_contents + ) + + if file_content == updated_file_content: + return ( + "File content was not updated because old content was not found." + "It may be helpful to use the read_file action to get " + "the current file contents." + ) + + commit = { + "branch": self.gitlab_branch, + "commit_message": "Create " + file_path, + "actions": [ + { + "action": "update", + "file_path": file_path, + "content": updated_file_content, + } + ], + } + + self.gitlab_repo_instance.commits.create(commit) + return "Updated file " + file_path + except Exception as e: + return "Unable to update file due to error:\n" + str(e) + + def delete_file(self, file_path: str) -> str: + """ + Deletes a file from the repo + Parameters: + file_path(str): Where the file is + Returns: + str: Success or failure message + """ + try: + self.gitlab_repo_instance.files.delete( + file_path, self.gitlab_branch, "Delete " + file_path + ) + return "Deleted file " + file_path + except Exception as e: + return "Unable to delete file due to error:\n" + str(e) + + def run(self, mode: str, query: str) -> str: + if mode == "get_issues": + return self.get_issues() + elif mode == "get_issue": + return json.dumps(self.get_issue(int(query))) + elif mode == "comment_on_issue": + return self.comment_on_issue(query) + elif mode == "create_file": + return self.create_file(query) + elif mode == "create_pull_request": + return self.create_pull_request(query) + elif mode == "read_file": + return self.read_file(query) + elif mode == "update_file": + return self.update_file(query) + elif mode == "delete_file": + return self.delete_file(query) + else: + raise ValueError("Invalid mode" + mode)