Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle cloning issues when repo is in an unexpected state #395

Merged
merged 1 commit into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/macaron/slsa_analyzer/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,7 @@ def _prepare_repo(
try:
git_service.check_out_repo(git_obj, branch_name, digest, not is_remote)
except RepoCheckOutError as error:
logger.error("Failed to check out repository at %s", resolved_local_path)
logger.error(error)
return None

Expand Down
35 changes: 30 additions & 5 deletions src/macaron/slsa_analyzer/git_service/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from abc import abstractmethod
from urllib.parse import ParseResult, urlunparse

from git import GitError
from pydriller.git import Git

from macaron.errors import CloneError, ConfigurationError, RepoCheckOutError
Expand Down Expand Up @@ -129,7 +130,7 @@ def clone_repo(self, clone_dir: str, url: str) -> None:
# Therefore, we don't need to catch and handle the CloneError exceptions here.
repo = git_url.clone_remote_repo(clone_dir, clone_url)

# If ``git_url.clone_remote_repo`` returns an Repo instance, this means that the repository is freshly cloned
# If ``git_url.clone_remote_repo`` returns a Repo instance, this means that the repository is freshly cloned
# with the token embedded URL. We will set its value back to the original non-token URL.
# If ``git_url.clone_remote_repo`` returns None, it means that the repository already exists so we don't need
# to do anything.
Expand All @@ -139,7 +140,16 @@ def clone_repo(self, clone_dir: str, url: str) -> None:
except ValueError as error:
raise CloneError("Cannot find the remote origin for this repository.") from error

origin_remote.set_url(url)
try:
# Even though the documentation of ``set_url`` function does not explicitly mention
# ``ValueError`` or ``GitError`` as raised errors, these errors might be raised based
# on the implementation.
origin_remote.set_url(url)
except (ValueError, GitError) as error:
raise CloneError(
"Failed to set the remote origin URL because this repository is in an unexpected state."
f" Consider removing the cloned repository at {clone_dir}."
) from error

def check_out_repo(self, git_obj: Git, branch: str, digest: str, offline_mode: bool) -> Git:
"""Checkout the branch and commit specified by the user of a repository.
Expand Down Expand Up @@ -168,7 +178,7 @@ def check_out_repo(self, git_obj: Git, branch: str, digest: str, offline_mode: b

Raises
------
RepoError
RepoCheckOutError
If there is error while checkout the specific branch and digest.
"""
remote_origin_url = git_url.get_remote_origin_of_local_repo(git_obj)
Expand All @@ -183,11 +193,26 @@ def check_out_repo(self, git_obj: Git, branch: str, digest: str, offline_mode: b
except CloneError as error:
raise RepoCheckOutError("Cannot parse the remote origin URL of this repository.") from error

origin_remote.set_url(reconstructed_url, remote_origin_url)
try:
# Even though the documentation of ``set_url`` function does not explicitly mention
# ``ValueError`` or ``GitError`` as raised errors, these errors might be raised based
# on the implementation.
origin_remote.set_url(reconstructed_url, remote_origin_url)
except (ValueError, GitError) as error:
raise RepoCheckOutError(
"Failed to set the remote origin URL because this repository is in an unexpected state."
" Consider removing the cloned repository."
) from error

check_out_status = git_url.check_out_repo_target(git_obj, branch, digest, offline_mode)

origin_remote.set_url(remote_origin_url, reconstructed_url)
try:
origin_remote.set_url(remote_origin_url, reconstructed_url)
except (ValueError, GitError) as error:
raise RepoCheckOutError(
"Failed to set the remote origin URL because this repository is in an unexpected state."
" Consider removing the cloned repository."
) from error

if not check_out_status:
raise RepoCheckOutError(
Expand Down
Loading