Skip to content

Commit 4409157

Browse files
committed
Fix for clones of private repositories
1 parent 4489e39 commit 4409157

File tree

3 files changed

+91
-40
lines changed

3 files changed

+91
-40
lines changed

continuous_delivery_scripts/utils/git_helpers.py

Lines changed: 90 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from pathlib import Path
1111
from typing import Optional, List, Union, Any, Tuple
1212

13-
from git import Repo, Actor
13+
from git import Repo, Actor, GitCommandError
1414
from packaging import version
1515

1616
from .configuration import configuration, ConfigurationVariable
@@ -48,7 +48,8 @@ def _git_url_ssh_to_https(self, url: str) -> str:
4848
path = url.split("github.com", 1)[1][1:].strip()
4949
new = "https://{GITHUB_TOKEN}:[email protected]/%s" % path
5050
logger.info("rewriting git url to: %s" % new)
51-
return new.format(GITHUB_TOKEN=configuration.get_value(ConfigurationVariable.GIT_TOKEN))
51+
return new.format(GITHUB_TOKEN=configuration.get_value(
52+
ConfigurationVariable.GIT_TOKEN))
5253

5354
def clone(self, path: Path) -> "GitWrapper":
5455
"""Clones this repository to the path.
@@ -59,9 +60,20 @@ def clone(self, path: Path) -> "GitWrapper":
5960
Returns:
6061
a wrapper over the cloned repository
6162
"""
62-
git_clone = self.repo.clone_from(
63-
url=self.get_remote_url(), to_path=str(path), multi_options=["--recurse-submodules"]
64-
)
63+
try:
64+
git_clone = self.repo.clone_from(
65+
url=self.get_remote_url(), to_path=str(path),
66+
multi_options=["--recurse-submodules"]
67+
)
68+
except GitCommandError as e:
69+
logger.info("failed cloning repository: %s" % e)
70+
logger.info("trying with authentication")
71+
git_clone = self.repo.clone_from(
72+
url=self._git_url_ssh_to_https(self.get_remote_url()),
73+
to_path=str(path),
74+
multi_options=["--recurse-submodules"]
75+
)
76+
6577
clone = GitWrapper(path=path, repo=git_clone)
6678
clone.set_remote_url(self.get_remote_url())
6779
clone.fetch()
@@ -78,8 +90,10 @@ def root(self) -> Path:
7890

7991
def configure_author(self) -> None:
8092
"""Sets the author."""
81-
self.repo.config_writer().set_value("user", "name", self.author.name).release()
82-
self.repo.config_writer().set_value("user", "email", self.author.email).release()
93+
self.repo.config_writer().set_value("user", "name",
94+
self.author.name).release()
95+
self.repo.config_writer().set_value("user", "email",
96+
self.author.email).release()
8397

8498
def checkout_branch(self, branch_name: str) -> Any:
8599
"""Checks out a branch from its name.
@@ -114,7 +128,8 @@ def _add_one_path(self, path_model: Path) -> None:
114128
if not path_model.is_absolute():
115129
path_model = Path(self.root).joinpath(path_model)
116130
if not path_model.exists():
117-
logger.warning(f"[Git] {path_model} cannot be added because not found.")
131+
logger.warning(
132+
f"[Git] {path_model} cannot be added because not found.")
118133
return
119134
relative_path = str(path_model.relative_to(self.root))
120135
unix_relative_path = relative_path.replace("\\", "/")
@@ -135,7 +150,8 @@ def add(self, path: Union[list, set, str]) -> None:
135150
else:
136151
self._add_one_file_or_one_dir(path)
137152

138-
def commit(self, message: str, **kwargs: Optional[Tuple[str, Any]]) -> None:
153+
def commit(self, message: str,
154+
**kwargs: Optional[Tuple[str, Any]]) -> None:
139155
"""Commits changes to the repository.
140156
141157
Args:
@@ -151,15 +167,17 @@ def get_master_branch(self) -> Any:
151167
Returns:
152168
corresponding branch
153169
"""
154-
return self.get_branch(configuration.get_value(ConfigurationVariable.MASTER_BRANCH))
170+
return self.get_branch(
171+
configuration.get_value(ConfigurationVariable.MASTER_BRANCH))
155172

156173
def get_beta_branch(self) -> Any:
157174
"""Gets the `beta` branch.
158175
159176
Returns:
160177
corresponding branch
161178
"""
162-
return self.get_branch(configuration.get_value(ConfigurationVariable.BETA_BRANCH))
179+
return self.get_branch(
180+
configuration.get_value(ConfigurationVariable.BETA_BRANCH))
163181

164182
def is_release_branch(self, branch_name: Optional[str]) -> bool:
165183
"""Checks whether the branch is a `release` branch or not.
@@ -170,7 +188,8 @@ def is_release_branch(self, branch_name: Optional[str]) -> bool:
170188
Returns:
171189
True if the branch is used for `release` code; False otherwise
172190
"""
173-
branch_pattern = configuration.get_value(ConfigurationVariable.RELEASE_BRANCH_PATTERN)
191+
branch_pattern = configuration.get_value(
192+
ConfigurationVariable.RELEASE_BRANCH_PATTERN)
174193
if not branch_pattern or not branch_name:
175194
return False
176195
is_release: Optional[Any] = re.search(branch_pattern, str(branch_name))
@@ -213,7 +232,8 @@ def get_current_branch(self) -> Any:
213232
try:
214233
return self.repo.active_branch
215234
except TypeError as e:
216-
logger.warning(f"Could not determine the branch name using GitPython: {e}")
235+
logger.warning(
236+
f"Could not determine the branch name using GitPython: {e}")
217237
current_branch = self._get_branch_from_advanced_feature()
218238
if not current_branch:
219239
current_branch = self._get_branch_from_abbreviation("HEAD")
@@ -222,13 +242,17 @@ def get_current_branch(self) -> Any:
222242
def _get_branch_from_advanced_feature(self) -> Any:
223243
if version.parse(self.git_version()) >= version.parse("2.22"):
224244
current_branch = self.repo.git.branch(show_current=True)
225-
current_branch = current_branch if isinstance(current_branch, str) else current_branch.decode("utf-8")
245+
current_branch = current_branch if isinstance(current_branch,
246+
str) else current_branch.decode(
247+
"utf-8")
226248
return self.get_branch(current_branch)
227249
return None
228250

229251
def _get_branch_from_abbreviation(self, abbreviation: str) -> Any:
230252
current_branch = self.repo.git.rev_parse("--abbrev-ref", abbreviation)
231-
current_branch = current_branch if isinstance(current_branch, str) else current_branch.decode("utf-8")
253+
current_branch = current_branch if isinstance(current_branch,
254+
str) else current_branch.decode(
255+
"utf-8")
232256
return self.get_branch(current_branch.strip())
233257

234258
def get_commit_count(self) -> int:
@@ -282,7 +306,8 @@ def merge(self, branch: Any) -> None:
282306
current_branch = self.get_current_branch()
283307
merge_base = self.repo.merge_base(branch, current_branch)
284308
self.repo.index.merge_tree(current_branch, base=merge_base)
285-
self.commit(f"Merge from {str(branch)}", parent_commits=(branch.commit, current_branch.commit))
309+
self.commit(f"Merge from {str(branch)}",
310+
parent_commits=(branch.commit, current_branch.commit))
286311

287312
def get_remote_url(self) -> str:
288313
"""Gets the URL of the remote repository.
@@ -315,7 +340,9 @@ def set_remote_url(self, url: str) -> None:
315340
remote = self._get_remote()
316341
if remote:
317342
self.repo.delete_remote(str(remote))
318-
self.repo.create_remote(configuration.get_value(ConfigurationVariable.REMOTE_ALIAS), url=url)
343+
self.repo.create_remote(
344+
configuration.get_value(ConfigurationVariable.REMOTE_ALIAS),
345+
url=url)
319346

320347
def get_remote_branch(self, branch_name: str) -> Optional[Any]:
321348
"""Gets the branch present in the remote repository.
@@ -342,7 +369,8 @@ def set_upstream_branch(self, branch_name: str) -> None:
342369
branch_name: name of the remote branch.
343370
"""
344371
if self.remote_branch_exists(branch_name):
345-
self.repo.git.branch("--set-upstream-to", self.get_remote_branch(branch_name))
372+
self.repo.git.branch("--set-upstream-to",
373+
self.get_remote_branch(branch_name))
346374

347375
def delete_branch(self, branch: Any) -> None:
348376
"""Deletes a branch.
@@ -384,17 +412,21 @@ def remote_branch_exists(self, branch_name: str) -> bool:
384412
"""
385413
return self.get_remote_branch(branch_name) is not None
386414

387-
def _get_specific_changes(self, change_type: Optional[str], commit1: Any, commit2: Any) -> List[str]:
415+
def _get_specific_changes(self, change_type: Optional[str], commit1: Any,
416+
commit2: Any) -> List[str]:
388417
diff = commit1.diff(commit2)
389418
if change_type:
390419
change_type = change_type.upper()
391420
change_type = change_type if change_type in diff.change_type else None
392-
diff_iterator = diff.iter_change_type(change_type) if change_type else diff
393-
changes = [change.a_path if change.a_path else change.b_path for change in diff_iterator]
421+
diff_iterator = diff.iter_change_type(
422+
change_type) if change_type else diff
423+
changes = [change.a_path if change.a_path else change.b_path for change
424+
in diff_iterator]
394425
return changes
395426

396427
def get_changes_list(
397-
self, commit1: Any, commit2: Any, change_type: Optional[str] = None, dir: Optional[str] = None
428+
self, commit1: Any, commit2: Any,
429+
change_type: Optional[str] = None, dir: Optional[str] = None
398430
) -> List[str]:
399431
"""Gets change list.
400432
@@ -414,7 +446,8 @@ def get_changes_list(
414446
if dir:
415447
windows_path = dir.replace("/", "\\")
416448
linux_path = dir.replace("\\", "/")
417-
return [change for change in changes if (linux_path in change) or (windows_path in change)]
449+
return [change for change in changes if
450+
(linux_path in change) or (windows_path in change)]
418451
else:
419452
return changes
420453

@@ -425,19 +458,22 @@ def pull_all(self) -> None:
425458
def pull(self) -> None:
426459
"""Pulls changes on current branch from the remote repository."""
427460
if self.remote_branch_exists(self.get_current_branch()):
428-
self.repo.git.pull(self._get_remote(), self.get_current_branch(), quiet=True)
461+
self.repo.git.pull(self._get_remote(), self.get_current_branch(),
462+
quiet=True)
429463

430464
def force_pull(self) -> None:
431465
"""Force pulls changes from the remote repository."""
432-
self.repo.git.pull(self._get_remote(), self.get_current_branch(), quiet=True, force=True)
466+
self.repo.git.pull(self._get_remote(), self.get_current_branch(),
467+
quiet=True, force=True)
433468

434469
def push(self) -> None:
435470
"""Pushes commits.
436471
437472
Pushes changes to the remote repository.
438473
Pushes also relevant annotated tags when pushing branches out.
439474
"""
440-
self.repo.git.push("--follow-tags", "--set-upstream", self._get_remote(), self.get_current_branch())
475+
self.repo.git.push("--follow-tags", "--set-upstream",
476+
self._get_remote(), self.get_current_branch())
441477

442478
def push_tag(self) -> None:
443479
"""Pushes commits and tags.
@@ -500,21 +536,25 @@ def git_version(self) -> str:
500536
Returns:
501537
the version of git in use.
502538
"""
503-
return ".".join([str(element) for element in self.repo.git.version_info])
539+
return ".".join(
540+
[str(element) for element in self.repo.git.version_info])
504541

505542
def _get_remote(self) -> Optional[Any]:
506543
try:
507-
return self.repo.remote(configuration.get_value(ConfigurationVariable.REMOTE_ALIAS))
544+
return self.repo.remote(
545+
configuration.get_value(ConfigurationVariable.REMOTE_ALIAS))
508546
except (IndexError, ValueError) as e:
509547
logger.warning(e)
510548
return None
511549

512550
def list_files_added_on_current_branch(self) -> List[str]:
513551
"""Returns a list of files changed against master branch."""
514-
master_branch_commit = self.repo.commit(configuration.get_value(ConfigurationVariable.MASTER_BRANCH))
552+
master_branch_commit = self.repo.commit(
553+
configuration.get_value(ConfigurationVariable.MASTER_BRANCH))
515554
current_branch_commit = self.repo.commit(self.get_current_branch())
516555
changes = self.get_changes_list(
517-
self.get_branch_point(master_branch_commit, current_branch_commit), current_branch_commit, change_type="a"
556+
self.get_branch_point(master_branch_commit, current_branch_commit),
557+
current_branch_commit, change_type="a"
518558
)
519559
return changes
520560

@@ -537,7 +577,8 @@ def uncommitted_changes(self) -> List[Path]:
537577
if not status:
538578
return []
539579

540-
return [Path(self.root).joinpath(line.strip().split(" ")[-1]) for line in status.splitlines()]
580+
return [Path(self.root).joinpath(line.strip().split(" ")[-1]) for line
581+
in status.splitlines()]
541582

542583
@staticmethod
543584
def _apply_modifications(destination: Path, modified_file: Path) -> None:
@@ -573,8 +614,10 @@ class ProjectGitWrapper(GitWrapper):
573614
def __init__(self) -> None:
574615
"""Creates a Git Wrapper."""
575616
super().__init__(
576-
path=Path(configuration.get_value(ConfigurationVariable.PROJECT_ROOT)),
577-
repo=Repo(configuration.get_value(ConfigurationVariable.PROJECT_ROOT)),
617+
path=Path(
618+
configuration.get_value(ConfigurationVariable.PROJECT_ROOT)),
619+
repo=Repo(
620+
configuration.get_value(ConfigurationVariable.PROJECT_ROOT)),
578621
)
579622

580623

@@ -615,7 +658,8 @@ def __init__(self, path: Path, initial_path: Path, repo: Repo) -> None:
615658
@staticmethod
616659
def wrap(repo: GitWrapper, initial_location: Path) -> "GitClone":
617660
"""Wraps around around a repository."""
618-
return GitClone(repo=repo.repo, path=repo.root, initial_path=initial_location)
661+
return GitClone(repo=repo.repo, path=repo.root,
662+
initial_path=initial_location)
619663

620664
@property
621665
def initial_location(self) -> Path:
@@ -638,26 +682,31 @@ def get_corresponding_path(self, path_in_initial_repo: Path) -> Path:
638682
return Path(self.root).joinpath(path_in_initial_repo)
639683
try:
640684
# Tyring to find if the path corresponds to a file/directory present in intial repository
641-
return Path(self.root).joinpath(path_in_initial_repo.relative_to(self.initial_location))
685+
return Path(self.root).joinpath(
686+
path_in_initial_repo.relative_to(self.initial_location))
642687
except ValueError:
643688
return path_in_initial_repo
644689

645690

646691
class GitTempClone:
647692
"""Context manager providing a temporary cloned repository."""
648693

649-
def __init__(self, desired_branch_name: Optional[str], repository_to_clone: GitWrapper):
694+
def __init__(self, desired_branch_name: Optional[str],
695+
repository_to_clone: GitWrapper):
650696
"""Constructor.
651697
652698
Args:
653699
desired_branch_name: the branch to consider. I
654700
repository_to_clone: the repository to clone. If not specified, the project repository will be used.
655701
"""
656702
self._temporary_dir = TemporaryDirectory()
657-
logger.info(f"Creating a temporary repository in {self._temporary_dir}")
703+
logger.info(
704+
f"Creating a temporary repository in {self._temporary_dir}")
658705
self._repo = repository_to_clone
659-
_current_branch_name = desired_branch_name if desired_branch_name else str(self._repo.get_current_branch())
660-
self._clone = GitClone.wrap(self._repo.clone(self._temporary_dir.path), initial_location=self._repo.root)
706+
_current_branch_name = desired_branch_name if desired_branch_name else str(
707+
self._repo.get_current_branch())
708+
self._clone = GitClone.wrap(self._repo.clone(self._temporary_dir.path),
709+
initial_location=self._repo.root)
661710
self._clone.checkout(_current_branch_name)
662711
self._repo.apply_uncommitted_changes(self._clone)
663712

@@ -688,4 +737,5 @@ def __init__(self, desired_branch_name: Optional[str] = None):
688737
system will try to identify the current branch in the repository which
689738
will work in most cases but probably not on CI.
690739
"""
691-
super().__init__(desired_branch_name=desired_branch_name, repository_to_clone=ProjectGitWrapper())
740+
super().__init__(desired_branch_name=desired_branch_name,
741+
repository_to_clone=ProjectGitWrapper())

news/.keep

Whitespace-only changes.

news/212102041830.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix for clones of private repository

0 commit comments

Comments
 (0)