Skip to content

github_repository

appimage_updater.repositories.github_repository

GitHub repository implementation for the repositories package.

This module re-exports the GitHubRepository class from the github package to maintain the repository abstraction pattern.

GitHubRepository(timeout=30, user_agent=None, auth=None, token=None, **kwargs)

GitHub repository implementation.

Parameters:

Name Type Description Default
timeout int

Request timeout in seconds

30
user_agent str | None

Custom user agent string

None
auth GitHubAuth | None

GitHubAuth instance for authentication

None
token str | None

Explicit GitHub token (creates auth if provided)

None
**kwargs Any

Additional configuration options

{}
Source code in src/appimage_updater/github/repository.py
def __init__(
    self,
    timeout: int = 30,
    user_agent: str | None = None,
    auth: GitHubAuth | None = None,
    token: str | None = None,
    **kwargs: Any,
) -> None:
    """Initialize GitHub repository client.

    Args:
        timeout: Request timeout in seconds
        user_agent: Custom user agent string
        auth: GitHubAuth instance for authentication
        token: Explicit GitHub token (creates auth if provided)
        **kwargs: Additional configuration options
    """
    super().__init__(timeout=timeout, user_agent=user_agent, **kwargs)

    # Initialize GitHub client with the same parameters
    self._github_client = GitHubClient(
        timeout=timeout,
        user_agent=user_agent,
        auth=auth,
        token=token,
    )

github_client property

Get the underlying GitHub client for backward compatibility.

repository_type property

Get the repository type identifier.

detect_repository_type(url)

Check if this is a GitHub repository URL.

Source code in src/appimage_updater/github/repository.py
def detect_repository_type(self, url: str) -> bool:
    """Check if this is a GitHub repository URL."""
    try:
        parsed = urllib.parse.urlparse(url)
        return parsed.netloc.lower() in ("github.com", "www.github.com")
    except Exception:
        return False

fetch_appimage_pattern_from_github(url) async

Async function to fetch AppImage pattern from repository releases.

Looks for both direct AppImage files and ZIP files that might contain AppImages. Prioritizes stable releases over prereleases for better pattern generation.

Source code in src/appimage_updater/github/repository.py
async def fetch_appimage_pattern_from_github(self, url: str) -> str | None:
    """Async function to fetch AppImage pattern from repository releases.

    Looks for both direct AppImage files and ZIP files that might contain AppImages.
    Prioritizes stable releases over prereleases for better pattern generation.
    """
    try:
        releases = await self.get_releases(url, limit=20)
        groups = self._collect_release_files(releases)
        target_files = self._select_target_files(groups)
        if not target_files:
            logger.debug("No AppImage or ZIP files found in any releases")
            return None
        return self._create_pattern_from_filenames(target_files, include_both_formats=True)
    except Exception as e:
        logger.debug(f"Error fetching releases: {e}")
        return None

generate_pattern_from_releases(url) async

Generate file pattern from actual GitHub releases.

Source code in src/appimage_updater/github/repository.py
async def generate_pattern_from_releases(self, url: str) -> str | None:
    """Generate file pattern from actual GitHub releases."""
    return await self.fetch_appimage_pattern_from_github(url)

get_latest_release(repo_url) async

Get the latest stable release for a GitHub repository.

Source code in src/appimage_updater/github/repository.py
async def get_latest_release(self, repo_url: str) -> Release:
    """Get the latest stable release for a GitHub repository."""
    try:
        release = await self._github_client.get_latest_release(repo_url)
        return self._convert_nightly_version(release)
    except GitHubClientError as e:
        raise RepositoryError(str(e)) from e

get_latest_release_including_prerelease(repo_url) async

Get the latest release including prereleases for a GitHub repository.

Source code in src/appimage_updater/github/repository.py
async def get_latest_release_including_prerelease(self, repo_url: str) -> Release:
    """Get the latest release including prereleases for a GitHub repository."""
    try:
        release = await self._github_client.get_latest_release_including_prerelease(repo_url)
        return self._convert_nightly_version(release)
    except GitHubClientError as e:
        raise RepositoryError(str(e)) from e

get_releases(repo_url, limit=10) async

Get recent releases for a GitHub repository.

Source code in src/appimage_updater/github/repository.py
async def get_releases(self, repo_url: str, limit: int = 10) -> list[Release]:
    """Get recent releases for a GitHub repository."""
    try:
        releases = await self._github_client.get_releases(repo_url, limit=limit)
        # Convert nightly build versions to date-based versions
        return [self._convert_nightly_version(release) for release in releases]
    except GitHubClientError as e:
        raise RepositoryError(str(e)) from e

normalize_github_url(url)

Normalize GitHub URL to repository format and detect if it was corrected.

Detects GitHub download URLs (releases/download/...) and converts them to repository URLs. Returns (normalized_url, was_corrected) tuple.

Source code in src/appimage_updater/github/repository.py
def normalize_github_url(self, url: str) -> tuple[str, bool]:
    """Normalize GitHub URL to repository format and detect if it was corrected.

    Detects GitHub download URLs (releases/download/...) and converts them to repository URLs.
    Returns (normalized_url, was_corrected) tuple.
    """
    try:
        if not self._is_github_url(url):
            return url, False

        parsed = urllib.parse.urlparse(url)
        path_parts = parsed.path.strip("/").split("/")

        if len(path_parts) >= 2:
            owner, repo = path_parts[0], path_parts[1]
            return self._normalize_github_path(path_parts, owner, repo, url)

    except Exception as e:
        logger.debug(f"Error normalizing GitHub URL {url}: {e}")

    return url, False

normalize_repo_url(url)

Normalize GitHub URL to repository format and detect if it was corrected.

Source code in src/appimage_updater/github/repository.py
def normalize_repo_url(self, url: str) -> tuple[str, bool]:
    """Normalize GitHub URL to repository format and detect if it was corrected."""
    return self.normalize_github_url(url)

parse_repo_url(url)

Parse GitHub repository URL to extract owner and repo name.

Source code in src/appimage_updater/github/repository.py
def parse_repo_url(self, url: str) -> tuple[str, str]:
    """Parse GitHub repository URL to extract owner and repo name."""
    try:
        return self._github_client._parse_repo_url(url)
    except GitHubClientError as e:
        raise RepositoryError(str(e)) from e

should_enable_prerelease(url) async

Check if prerelease should be automatically enabled for a repository.

Returns True if the repository only has prerelease versions (like continuous builds) and no stable releases, indicating that prerelease support should be enabled.

Parameters:

Name Type Description Default
url str

Repository URL

required

Returns:

Name Type Description
bool bool

True if only prereleases are found, False if stable releases exist or on error

Source code in src/appimage_updater/github/repository.py
async def should_enable_prerelease(self, url: str) -> bool:
    """Check if prerelease should be automatically enabled for a repository.

    Returns True if the repository only has prerelease versions (like continuous builds)
    and no stable releases, indicating that prerelease support should be enabled.

    Args:
        url: Repository URL

    Returns:
        bool: True if only prereleases are found, False if stable releases exist or on error
    """
    try:
        releases = await self.get_releases(url, limit=20)
        if not releases:
            return False

        valid_releases = self._filter_valid_releases(releases, url)
        if not valid_releases:
            return False

        return self._analyze_prerelease_status(valid_releases, url)

    except Exception as e:
        # Don't fail the add command if prerelease detection fails
        logger.debug(f"Error checking prerelease status for {url}: {e}")
        return False