community: add method to create branch and list files for gitlab tool (#27883)

### About

- **Description:** In the Gitlab utilities used for the Gitlab tool
there are no methods to create branches, list branches and files, as
this is already done for Github
- **Issue:** None
- **Dependencies:** None

This Pull request add the methods:
- create_branch
- list_branches_in_repo
- set_active_branch
- list_files_in_main_branch
- list_files_in_bot_branch
- list_files_from_directory

---------

Co-authored-by: Erick Friis <erick@langchain.dev>
This commit is contained in:
Lorenzo
2024-12-12 20:11:35 +01:00
committed by GitHub
parent ca054ed1b1
commit 4149c0dd8d
3 changed files with 256 additions and 3 deletions

View File

@@ -325,6 +325,161 @@ class GitLabAPIWrapper(BaseModel):
except Exception as e:
return "Unable to delete file due to error:\n" + str(e)
def list_files_in_main_branch(self) -> str:
"""
Get the list of files in the main branch of the repository
Returns:
str: A plaintext report containing the list of files
in the repository in the main branch
"""
if self.gitlab_base_branch is None:
return "No base branch set. Please set a base branch."
return self._list_files(self.gitlab_base_branch)
def list_files_in_bot_branch(self) -> str:
"""
Get the list of files in the active branch of the repository
Returns:
str: A plaintext report containing the list of files
in the repository in the active branch
"""
if self.gitlab_branch is None:
return "No active branch set. Please set a branch."
return self._list_files(self.gitlab_branch)
def list_files_from_directory(self, path: str) -> str:
"""
Get the list of files in the active branch of the repository
from a specific directory
Returns:
str: A plaintext report containing the list of files
in the repository in the active branch from the specified directory
"""
if self.gitlab_branch is None:
return "No active branch set. Please set a branch."
return self._list_files(
branch=self.gitlab_branch,
path=path,
)
def _list_files(self, branch: str, path: str = "") -> str:
try:
files = self._get_repository_files(
branch=branch,
path=path,
)
if files:
files_str = "\n".join(files)
return f"Found {len(files)} files in branch `{branch}`:\n{files_str}"
else:
return f"No files found in branch: `{branch}`"
except Exception as e:
return f"Error: {e}"
def _get_repository_files(self, branch: str, path: str = "") -> List[str]:
repo_contents = self.gitlab_repo_instance.repository_tree(ref=branch, path=path)
files: List[str] = []
for content in repo_contents:
if content["type"] == "tree":
files.extend(self._get_repository_files(branch, content["path"]))
else:
files.append(content["path"])
return files
def create_branch(self, proposed_branch_name: str) -> str:
"""
Create a new branch in the repository and set it as the active branch
Parameters:
proposed_branch_name (str): The name of the new branch to be created
Returns:
str: A success or failure message
"""
from gitlab import GitlabCreateError
max_attempts = 100
new_branch_name = proposed_branch_name
for i in range(max_attempts):
try:
response = self.gitlab_repo_instance.branches.create(
{
"branch": new_branch_name,
"ref": self.gitlab_branch,
}
)
self.gitlab_branch = response.name
return (
f"Branch '{response.name}' "
"created successfully, and set as current active branch."
)
except GitlabCreateError as e:
if (
e.response_code == 400
and "Branch already exists" in e.error_message
):
i += 1
new_branch_name = f"{proposed_branch_name}_v{i}"
else:
# Handle any other exceptions
print(f"Failed to create branch. Error: {e}") # noqa: T201
raise Exception(
"Unable to create branch name from proposed_branch_name: "
f"{proposed_branch_name}"
)
return (
f"Unable to create branch. At least {max_attempts} branches exist "
f"with named derived from "
f"proposed_branch_name: `{proposed_branch_name}`"
)
def list_branches_in_repo(self) -> str:
"""
Get the list of branches in the repository
Returns:
str: A plaintext report containing the number of branches
and each branch name
"""
branches = [
branch.name for branch in self.gitlab_repo_instance.branches.list(all=True)
]
if branches:
branches_str = "\n".join(branches)
return (
f"Found {str(len(branches))} branches in the repository:"
f"\n{branches_str}"
)
return "No branches found in the repository"
def set_active_branch(self, branch_name: str) -> str:
"""Equivalent to `git checkout branch_name` for this Agent.
Clones formatting from Gitlab.
Returns an Error (as a string) if branch doesn't exist.
"""
curr_branches = [
branch.name
for branch in self.gitlab_repo_instance.branches.list(
all=True,
)
]
if branch_name in curr_branches:
self.gitlab_branch = branch_name
return f"Switched to branch `{branch_name}`"
else:
return (
f"Error {branch_name} does not exist,"
f"in repo with current branches: {str(curr_branches)}"
)
def run(self, mode: str, query: str) -> str:
if mode == "get_issues":
return self.get_issues()
@@ -342,5 +497,17 @@ class GitLabAPIWrapper(BaseModel):
return self.update_file(query)
elif mode == "delete_file":
return self.delete_file(query)
elif mode == "create_branch":
return self.create_branch(query)
elif mode == "list_branches_in_repo":
return self.list_branches_in_repo()
elif mode == "set_active_branch":
return self.set_active_branch(query)
elif mode == "list_files_in_main_branch":
return self.list_files_in_main_branch()
elif mode == "list_files_in_bot_branch":
return self.list_files_in_bot_branch()
elif mode == "list_files_from_directory":
return self.list_files_from_directory(query)
else:
raise ValueError("Invalid mode" + mode)