From 3f99d91e7ab0b4131080b98bc15ab2c179775beb Mon Sep 17 00:00:00 2001 From: ludeeus Date: Sun, 2 Nov 2025 14:09:09 +0000 Subject: [PATCH 1/4] Refactor tree retrieval to use a non deprecated method --- custom_components/hacs/repositories/base.py | 29 ++++++++++++++------- custom_components/hacs/utils/workarounds.py | 26 ++++++++++++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/custom_components/hacs/repositories/base.py b/custom_components/hacs/repositories/base.py index 950f52facd3..03adfe1d15d 100644 --- a/custom_components/hacs/repositories/base.py +++ b/custom_components/hacs/repositories/base.py @@ -14,6 +14,7 @@ from aiogithubapi import ( AIOGitHubAPIException, AIOGitHubAPINotModifiedException, + GitHubException, GitHubReleaseModel, ) from aiogithubapi.objects.repository import AIOGitHubAPIRepository @@ -46,7 +47,7 @@ version_left_higher_or_equal_then_right, version_left_higher_then_right, ) -from ..utils.workarounds import DOMAIN_OVERRIDES +from ..utils.workarounds import DOMAIN_OVERRIDES, LegacyTreeFile if TYPE_CHECKING: from ..base import HacsBase @@ -1020,14 +1021,17 @@ async def async_get_legacy_repository_object( def update_filenames(self) -> None: """Get the filename to target.""" - async def get_tree(self, ref: str): + async def get_tree(self, ref: str) -> list[LegacyTreeFile] | None: """Return the repository tree.""" - if self.repository_object is None: - raise HacsException("No repository_object") try: - tree = await self.repository_object.get_tree(ref) - return tree - except (ValueError, AIOGitHubAPIException) as exception: + response = await self.hacs.async_github_api_method( + method=self.hacs.githubapi.repos.git.get_tree, + repository=self.data.full_name, + tree_sha=ref, + kwargs={"recursive": True}, + ) + return response.data.tree + except GitHubException as exception: raise HacsException(exception) from exception async def get_releases(self, prerelease=False, returnlimit=5) -> list[GitHubReleaseModel]: @@ -1144,13 +1148,18 @@ async def common_update_data( ) try: - self.tree = await self.get_tree(self.ref) - if not self.tree: + tree = await self.get_tree(self.ref) + if not tree: raise HacsException("No files in tree") + self.tree = [ + LegacyTreeFile(entry, repository=self.data.full_name, ref=self.ref) + for entry in tree + ] + self.treefiles = [] for treefile in self.tree: self.treefiles.append(treefile.full_path) - except (AIOGitHubAPIException, HacsException) as exception: + except HacsException as exception: if ( not retry and self.ref is not None diff --git a/custom_components/hacs/utils/workarounds.py b/custom_components/hacs/utils/workarounds.py index 4d7867ca35f..92d5145768b 100644 --- a/custom_components/hacs/utils/workarounds.py +++ b/custom_components/hacs/utils/workarounds.py @@ -1,5 +1,6 @@ """Workarounds.""" +from aiogithubapi.models.git_tree import GitHubGitTreeEntryModel from homeassistant.core import HomeAssistant DOMAIN_OVERRIDES = { @@ -35,3 +36,28 @@ async def async_register_static_path( https://developers.home-assistant.io/blog/2024/06/18/async_register_static_paths/ """ hass.http.register_static_path(url_path, path, cache_headers) + + +class LegacyTreeFile: + """Legacy TreeFile representation + + This serves as a compatibility layer for code expecting + the older TreeFile structure. + """ + + def __init__(self, model: GitHubGitTreeEntryModel, repository: str, ref: str): + """Initialize.""" + self.model = model + self.repository = repository + self.ref = ref + + # Calculated attributes + split_path = self.model.path.rsplit("/", 1) + self.full_path = self.model.path + self.is_directory = self.model.type == "tree" + self.path = split_path[0] if "/" in self.model.path else "" + self.filename = split_path[-1] if "/" in self.model.path else self.model.path + self.url = self.model.url + self.download_url = ( + f"https://raw.githubusercontent.com/{self.repository}/{self.ref}/{self.model.path}" + ) From 287396b2f353b1aa7b22df97f058950a74b7a140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Sun, 2 Nov 2025 15:13:41 +0100 Subject: [PATCH 2/4] Update custom_components/hacs/utils/workarounds.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- custom_components/hacs/utils/workarounds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/hacs/utils/workarounds.py b/custom_components/hacs/utils/workarounds.py index 92d5145768b..e87e13da80f 100644 --- a/custom_components/hacs/utils/workarounds.py +++ b/custom_components/hacs/utils/workarounds.py @@ -39,7 +39,7 @@ async def async_register_static_path( class LegacyTreeFile: - """Legacy TreeFile representation + """Legacy TreeFile representation. This serves as a compatibility layer for code expecting the older TreeFile structure. From dce1ed2dc99d7e596b0f301a0864a4da7bb2b34f Mon Sep 17 00:00:00 2001 From: ludeeus Date: Sun, 2 Nov 2025 14:25:47 +0000 Subject: [PATCH 3/4] Refactor LegacyTreeFile to simplify path and filename calculations --- custom_components/hacs/repositories/base.py | 8 +++++--- custom_components/hacs/utils/workarounds.py | 21 ++++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/custom_components/hacs/repositories/base.py b/custom_components/hacs/repositories/base.py index 03adfe1d15d..d3eda33ce3d 100644 --- a/custom_components/hacs/repositories/base.py +++ b/custom_components/hacs/repositories/base.py @@ -15,9 +15,7 @@ AIOGitHubAPIException, AIOGitHubAPINotModifiedException, GitHubException, - GitHubReleaseModel, ) -from aiogithubapi.objects.repository import AIOGitHubAPIRepository import attr from homeassistant.helpers import device_registry as dr, issue_registry as ir @@ -50,6 +48,10 @@ from ..utils.workarounds import DOMAIN_OVERRIDES, LegacyTreeFile if TYPE_CHECKING: + from aiogithubapi.models.git_tree import GitHubGitTreeEntryModel + from aiogithubapi.models.release import GitHubReleaseModel + from aiogithubapi.objects.repository import AIOGitHubAPIRepository + from ..base import HacsBase @@ -1021,7 +1023,7 @@ async def async_get_legacy_repository_object( def update_filenames(self) -> None: """Get the filename to target.""" - async def get_tree(self, ref: str) -> list[LegacyTreeFile] | None: + async def get_tree(self, ref: str) -> list[GitHubGitTreeEntryModel] | None: """Return the repository tree.""" try: response = await self.hacs.async_github_api_method( diff --git a/custom_components/hacs/utils/workarounds.py b/custom_components/hacs/utils/workarounds.py index e87e13da80f..87211e2b3c7 100644 --- a/custom_components/hacs/utils/workarounds.py +++ b/custom_components/hacs/utils/workarounds.py @@ -51,13 +51,24 @@ def __init__(self, model: GitHubGitTreeEntryModel, repository: str, ref: str): self.repository = repository self.ref = ref - # Calculated attributes - split_path = self.model.path.rsplit("/", 1) + # Simple calculated attributes self.full_path = self.model.path self.is_directory = self.model.type == "tree" - self.path = split_path[0] if "/" in self.model.path else "" - self.filename = split_path[-1] if "/" in self.model.path else self.model.path self.url = self.model.url self.download_url = ( - f"https://raw.githubusercontent.com/{self.repository}/{self.ref}/{self.model.path}" + f"https://raw.githubusercontent.com/{self.repository}/{self.ref}/{self.full_path}" ) + + @property + def path(self): + path = "" + if "/" in self.full_path: + path = self.full_path.split(f"/{self.full_path.split('/')[-1]}")[0] + return path + + @property + def filename(self): + filename = self.full_path + if "/" in self.full_path: + filename = self.full_path.split("/")[-1] + return filename From 793f163679bc2290427d1d8dabf5d8c50c24191f Mon Sep 17 00:00:00 2001 From: ludeeus Date: Sun, 2 Nov 2025 14:35:23 +0000 Subject: [PATCH 4/4] Fix parameter name in GitHub API call for tree retrieval --- custom_components/hacs/repositories/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/hacs/repositories/base.py b/custom_components/hacs/repositories/base.py index d3eda33ce3d..1920143afe6 100644 --- a/custom_components/hacs/repositories/base.py +++ b/custom_components/hacs/repositories/base.py @@ -1030,7 +1030,7 @@ async def get_tree(self, ref: str) -> list[GitHubGitTreeEntryModel] | None: method=self.hacs.githubapi.repos.git.get_tree, repository=self.data.full_name, tree_sha=ref, - kwargs={"recursive": True}, + params={"recursive": "true"}, ) return response.data.tree except GitHubException as exception: