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

refactor: validate repos with git commands & improve readability #64

Merged
merged 2 commits into from
May 28, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def clone(self, package: Package, path: str) -> None:
package (Package): The package to be cloned.
path (str): The destination path for cloning the package.
"""
repo = None
bra-i-am marked this conversation as resolved.
Show resolved Hide resolved
if "https" == package.extra["protocol"]:
repo = (
f"https://{package.domain}/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
"""


import requests
from __future__ import annotations

import subprocess
from typing import Optional

from tutordistro.distro.share.domain.cloud_package import CloudPackage
from tutordistro.distro.share.domain.cloud_package_repository import CloudPackageRepository
Expand All @@ -16,10 +19,69 @@ class GitPackageRepository(CloudPackageRepository):
"""
Repository class for validating CloudPackages using a Git repository.

It inherits from CloudPackageRepository and provides the implementation for
the validation method.
This class inherits from CloudPackageRepository and provides the implementation for
the validation method. It verifies the existence of the repository and checks
if the specified branch or tag exists.
"""
def validate(self, package: CloudPackage) -> None:
response = requests.get(package.to_url(), timeout=5)
if response.status_code != 200:
raise PackageDoesNotExist(f"The package {package.name} or branch doesn't exist or is private")
package_url = package.to_url()
repo_url, version_name = self._parse_package_url(package_url)

self._verify_repository_exists(repo_url)
if version_name:
self._verify_version_exists(repo_url, version_name)

def _parse_package_url(self, package_url: str) -> tuple[str, Optional[str]]:
"""
Parse the package URL to extract the repository URL and the version name.

Args:
package_url (str): The full URL of the package.

Returns:
tuple: A tuple containing the repository URL and the version name (branch/tag).
"""
split_url = package_url.split('/tree/')
repo_url = split_url[0]
version_name = split_url[1] if len(split_url) > 1 else None
return repo_url, version_name

def _verify_repository_exists(self, repo_url: str) -> None:
"""
Verify that the repository exists.

Args:
repo_url (str): The URL of the repository.

Raises:
PackageDoesNotExist: If the repository does not exist or is private.
"""
result = subprocess.run(
['git', 'ls-remote', repo_url],
capture_output=True, text=True, check=False
)
if result.returncode != 0:
raise PackageDoesNotExist(f'The package "{repo_url}" does not exist or is private')

def _verify_version_exists(self, repo_url: str, version_name: str) -> None:
"""
Verify that the branch or tag exists in the repository.

Args:
repo_url (str): The URL of the repository.
version_name (str): The branch or tag name to verify.

Raises:
PackageDoesNotExist: If neither the branch nor the tag exists.
"""
branch_result = subprocess.run(
['git', 'ls-remote', '--heads', repo_url, version_name],
capture_output=True, text=True, check=False
)
tag_result = subprocess.run(
['git', 'ls-remote', '--tags', repo_url, version_name],
capture_output=True, text=True, check=False
)

if not branch_result.stdout and not tag_result.stdout:
raise PackageDoesNotExist(f'Neither branch nor tag "{version_name}" exists on "{repo_url}"')
30 changes: 11 additions & 19 deletions tutordistro/distro/share/domain/cloud_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from urllib.parse import urlparse

from tutordistro.distro.share.domain.package import Package
from tutordistro.distro.share.domain.package_does_not_exist import PackageDoesNotExist


class CloudPackage:
Expand Down Expand Up @@ -50,36 +49,29 @@ def is_valid_requirement(url) -> bool:

@staticmethod
def __parse_url(url) -> CloudPackage:
version: str = ""
version: str = ''

pattern = r"git\+(https?://\S+?)(?:#|$)"
result = re.search(pattern, url)
url = result.group(1).replace('@', '/tree/').replace('.git', '')
found_package_url = re.search(pattern, url).group(1)
github_url = found_package_url.replace('@', '/tree/').replace('.git', '')

parsed_url = urlparse(url)
parsed_url = urlparse(github_url)
split_path = parsed_url.path.split('/')

protocol = parsed_url.scheme
domain = parsed_url.netloc
path = parsed_url.path
partes_path = path.split('/')
name = partes_path[2]

if len(partes_path) > 5:
raise PackageDoesNotExist(f"The package {url} or branch doesn't exist or is private")

if '/tree/' in url:
version = partes_path[-1]
if len(partes_path) > 3 and '/tree/' not in url:
raise PackageDoesNotExist(f"The package {url} or branch doesn't exist or is private")
org_path = split_path[1]
package_name = split_path[2]

path = partes_path[1]
if '/tree/' in github_url:
version = github_url.split('/tree/')[-1] # This is the branch name or tag

return CloudPackage(
domain=domain,
name=name,
name=package_name,
version=version,
protocol=protocol,
path=path
path=org_path
)

@staticmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def clone(self, theme_settings: type(ThemeSettings)):
Args:
theme_settings (ThemeSettings): Theme settings.
"""
repo = None
bra-i-am marked this conversation as resolved.
Show resolved Hide resolved
if "https" == theme_settings.settings["protocol"]:
repo = (
f"https://{theme_settings.settings['domain']}/"
Expand Down
Loading