from typing import Any import logging import requests from majordome.errors import NoReleaseFound, AssetNotFound, DownloadFailure logger = logging.getLogger(__name__) class GithubConnector: def __init__(self, token: str): self.base_url = "https://api.github.com" self.token = token @property def headers(self) -> dict[str, str]: return { "Accept": "application/vnd.github.v3+json", "Authorization": f"Bearer {self.token}", "X-GitHub-Api-Version": "2022-11-28", } def get_latest_release(self, owner: str, repo: str) -> dict[str, Any]: logger.info("Getting latest release from Github") logger.debug( "GET %s with headers %s", self.latest_release_url(owner, repo), self.headers ) response = requests.get( self.latest_release_url(owner, repo), headers=self.headers ) if response.ok: logger.debug("Latest release found") return response.json()[0] raise NoReleaseFound( f"No release found on Github for the repo {repo} from owner {owner}" ) @staticmethod def latest_release_url(owner: str, repo: str) -> str: return f"https://api.github.com/repos/{owner}/{repo}/releases?per_page=1" def download_asset(self, owner: str, repo: str, asset_id: int) -> bytes: logger.info( "Downloading asset with id %s from Github owner %s and repo %s", asset_id, owner, repo, ) asset_response = requests.get( self.asset_url(owner, repo, asset_id), headers=self.headers ) if asset_response.ok: download_url = asset_response.json().get("browser_download_url") downloaded_response = requests.get(download_url, headers=self.headers) if downloaded_response.ok: return downloaded_response.content raise DownloadFailure( f"The asset {asset_id} was not found on Github for the repo {repo} from owner {owner}" ) raise AssetNotFound( f"The asset {asset_id} was not found on Github for the repo {repo} from owner {owner}" ) @staticmethod def asset_url(owner: str, repo: str, asset_id: int) -> str: return f"https://api.github.com/repos/{owner}/{repo}/releases/assets/{asset_id}"