Files
netsec/env/lib/python3.12/site-packages/gitlab/v4/objects/repositories.py
2024-12-09 18:22:38 +09:00

294 lines
11 KiB
Python

"""
GitLab API: https://docs.gitlab.com/ee/api/repositories.html
Currently this module only contains repository-related methods for projects.
"""
from typing import Any, Callable, Dict, Iterator, List, Optional, TYPE_CHECKING, Union
import requests
import gitlab
from gitlab import cli
from gitlab import exceptions as exc
from gitlab import types, utils
if TYPE_CHECKING:
# When running mypy we use these as the base classes
_RestObjectBase = gitlab.base.RESTObject
else:
_RestObjectBase = object
class RepositoryMixin(_RestObjectBase):
@cli.register_custom_action(
cls_names="Project", required=("submodule", "branch", "commit_sha")
)
@exc.on_http_error(exc.GitlabUpdateError)
def update_submodule(
self, submodule: str, branch: str, commit_sha: str, **kwargs: Any
) -> Union[Dict[str, Any], requests.Response]:
"""Update a project submodule
Args:
submodule: Full path to the submodule
branch: Name of the branch to commit into
commit_sha: Full commit SHA to update the submodule to
commit_message: Commit message. If no message is provided, a
default one will be set (optional)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabPutError: If the submodule could not be updated
"""
submodule = utils.EncodedId(submodule)
path = f"/projects/{self.encoded_id}/repository/submodules/{submodule}"
data = {"branch": branch, "commit_sha": commit_sha}
if "commit_message" in kwargs:
data["commit_message"] = kwargs["commit_message"]
return self.manager.gitlab.http_put(path, post_data=data)
@cli.register_custom_action(
cls_names="Project", optional=("path", "ref", "recursive")
)
@exc.on_http_error(exc.GitlabGetError)
def repository_tree(
self, path: str = "", ref: str = "", recursive: bool = False, **kwargs: Any
) -> Union[gitlab.client.GitlabList, List[Dict[str, Any]]]:
"""Return a list of files in the repository.
Args:
path: Path of the top folder (/ by default)
ref: Reference to a commit or branch
recursive: Whether to get the tree recursively
all: If True, return all the items, without pagination
per_page: Number of items to retrieve per request
page: ID of the page to return (starts with page 1)
iterator: If set to True and no pagination option is
defined, return a generator instead of a list
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGetError: If the server failed to perform the request
Returns:
The representation of the tree
"""
gl_path = f"/projects/{self.encoded_id}/repository/tree"
query_data: Dict[str, Any] = {"recursive": recursive}
if path:
query_data["path"] = path
if ref:
query_data["ref"] = ref
return self.manager.gitlab.http_list(gl_path, query_data=query_data, **kwargs)
@cli.register_custom_action(cls_names="Project", required=("sha",))
@exc.on_http_error(exc.GitlabGetError)
def repository_blob(
self, sha: str, **kwargs: Any
) -> Union[Dict[str, Any], requests.Response]:
"""Return a file by blob SHA.
Args:
sha: ID of the blob
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGetError: If the server failed to perform the request
Returns:
The blob content and metadata
"""
path = f"/projects/{self.encoded_id}/repository/blobs/{sha}"
return self.manager.gitlab.http_get(path, **kwargs)
@cli.register_custom_action(cls_names="Project", required=("sha",))
@exc.on_http_error(exc.GitlabGetError)
def repository_raw_blob(
self,
sha: str,
streamed: bool = False,
action: Optional[Callable[..., Any]] = None,
chunk_size: int = 1024,
*,
iterator: bool = False,
**kwargs: Any,
) -> Optional[Union[bytes, Iterator[Any]]]:
"""Return the raw file contents for a blob.
Args:
sha: ID of the blob
streamed: If True the data will be processed by chunks of
`chunk_size` and each chunk is passed to `action` for
treatment
iterator: If True directly return the underlying response
iterator
action: Callable responsible of dealing with chunk of
data
chunk_size: Size of each chunk
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGetError: If the server failed to perform the request
Returns:
The blob content if streamed is False, None otherwise
"""
path = f"/projects/{self.encoded_id}/repository/blobs/{sha}/raw"
result = self.manager.gitlab.http_get(
path, streamed=streamed, raw=True, **kwargs
)
if TYPE_CHECKING:
assert isinstance(result, requests.Response)
return utils.response_content(
result, streamed, action, chunk_size, iterator=iterator
)
@cli.register_custom_action(cls_names="Project", required=("from_", "to"))
@exc.on_http_error(exc.GitlabGetError)
def repository_compare(
self, from_: str, to: str, **kwargs: Any
) -> Union[Dict[str, Any], requests.Response]:
"""Return a diff between two branches/commits.
Args:
from_: Source branch/SHA
to: Destination branch/SHA
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGetError: If the server failed to perform the request
Returns:
The diff
"""
path = f"/projects/{self.encoded_id}/repository/compare"
query_data = {"from": from_, "to": to}
return self.manager.gitlab.http_get(path, query_data=query_data, **kwargs)
@cli.register_custom_action(cls_names="Project")
@exc.on_http_error(exc.GitlabGetError)
def repository_contributors(
self, **kwargs: Any
) -> Union[gitlab.client.GitlabList, List[Dict[str, Any]]]:
"""Return a list of contributors for the project.
Args:
all: If True, return all the items, without pagination
per_page: Number of items to retrieve per request
page: ID of the page to return (starts with page 1)
iterator: If set to True and no pagination option is
defined, return a generator instead of a list
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGetError: If the server failed to perform the request
Returns:
The contributors
"""
path = f"/projects/{self.encoded_id}/repository/contributors"
return self.manager.gitlab.http_list(path, **kwargs)
@cli.register_custom_action(cls_names="Project", optional=("sha", "format"))
@exc.on_http_error(exc.GitlabListError)
def repository_archive(
self,
sha: Optional[str] = None,
streamed: bool = False,
action: Optional[Callable[..., Any]] = None,
chunk_size: int = 1024,
format: Optional[str] = None,
path: Optional[str] = None,
*,
iterator: bool = False,
**kwargs: Any,
) -> Optional[Union[bytes, Iterator[Any]]]:
"""Return an archive of the repository.
Args:
sha: ID of the commit (default branch by default)
streamed: If True the data will be processed by chunks of
`chunk_size` and each chunk is passed to `action` for
treatment
iterator: If True directly return the underlying response
iterator
action: Callable responsible of dealing with chunk of
data
chunk_size: Size of each chunk
format: file format (tar.gz by default)
path: The subpath of the repository to download (all files by default)
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabListError: If the server failed to perform the request
Returns:
The binary data of the archive
"""
url_path = f"/projects/{self.encoded_id}/repository/archive"
if format:
url_path += "." + format
query_data = {}
if sha:
query_data["sha"] = sha
if path is not None:
query_data["path"] = path
result = self.manager.gitlab.http_get(
url_path, query_data=query_data, raw=True, streamed=streamed, **kwargs
)
if TYPE_CHECKING:
assert isinstance(result, requests.Response)
return utils.response_content(
result, streamed, action, chunk_size, iterator=iterator
)
@cli.register_custom_action(cls_names="Project", required=("refs",))
@exc.on_http_error(exc.GitlabGetError)
def repository_merge_base(
self, refs: List[str], **kwargs: Any
) -> Union[Dict[str, Any], requests.Response]:
"""Return a diff between two branches/commits.
Args:
refs: The refs to find the common ancestor of. Multiple refs can be passed.
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGetError: If the server failed to perform the request
Returns:
The common ancestor commit (*not* a RESTObject)
"""
path = f"/projects/{self.encoded_id}/repository/merge_base"
query_data, _ = utils._transform_types(
data={"refs": refs},
custom_types={"refs": types.ArrayAttribute},
transform_data=True,
)
return self.manager.gitlab.http_get(path, query_data=query_data, **kwargs)
@cli.register_custom_action(cls_names="Project")
@exc.on_http_error(exc.GitlabDeleteError)
def delete_merged_branches(self, **kwargs: Any) -> None:
"""Delete merged branches.
Args:
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabDeleteError: If the server failed to perform the request
"""
path = f"/projects/{self.encoded_id}/repository/merged_branches"
self.manager.gitlab.http_delete(path, **kwargs)