From eecb4dfa352457b51a5bdf1c2bd3d38ed88c1715 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Mon, 8 Dec 2025 10:20:18 +0530 Subject: [PATCH 01/12] feat: add rate limit checking on 403 errors (#298) Add _check_rate_limit() method to query GitHub API rate limit status and log remaining/limit/reset information when 403 errors are encountered. This helps distinguish between rate limiting and permission issues. --- tagbot/action/repo.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 02d99f3..cd71e37 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -661,6 +661,20 @@ def create_release(self, version: str, sha: str) -> None: version_tag, version_tag, log, target_commitish=target, draft=self._draft ) + def _check_rate_limit(self) -> None: + """Check and log GitHub API rate limit status.""" + try: + rate_limit = self._gh.get_rate_limit() + remaining = rate_limit.core[0] + limit = rate_limit.core[1] + reset_time = rate_limit.core[2] + logger.info( + f"GitHub API rate limit: {remaining}/{limit} remaining " + f"(reset at {reset_time})" + ) + except Exception as e: + logger.debug(f"Could not check rate limit: {e}") + def handle_error(self, e: Exception) -> None: """Handle an unexpected error.""" allowed = False @@ -677,10 +691,12 @@ def handle_error(self, e: Exception) -> None: logger.info(trace) allowed = True elif e.status == 403: + self._check_rate_limit() logger.error( - """GitHub returned a 403 permissions-related error. - Please check that your ssh key and TagBot permissions are up to date - https://github.com/JuliaRegistries/TagBot#setup + """GitHub returned a 403 error. This may indicate: + 1. Rate limiting - check the rate limit status above + 2. Insufficient permissions - verify your token & repo access + 3. Resource not accessible - see setup documentation """ ) internal = False From a28bfb69645276ace728347b471354ddb0a2edf9 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Mon, 8 Dec 2025 10:30:19 +0530 Subject: [PATCH 02/12] fix: normalize UUID to lowercase for registry lookup (#315) TagBot now normalizes UUIDs to lowercase when looking them up in the registry, matching the registry's behavior. This fixes the issue where packages with uppercase UUIDs were being ignored by TagBot. - Normalize UUID in _registry_path property - Normalize UUID in _registry_pr method - Add test for uppercase UUID handling --- tagbot/action/repo.py | 4 ++-- test/action/test_repo.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index cd71e37..dc01e8f 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -191,7 +191,7 @@ def _registry_path(self) -> Optional[str]: if self.__registry_path is not None: return self.__registry_path try: - uuid = self._project("uuid") + uuid = self._project("uuid").lower() except KeyError: raise InvalidProject("Project file has no UUID") if self._clone_registry: @@ -268,7 +268,7 @@ def _registry_pr(self, version: str) -> Optional[PullRequest]: # I think this is actually possible, but it looks pretty complicated. return None name = self._project("name") - uuid = self._project("uuid") + uuid = self._project("uuid").lower() url = self._registry_url if not url: logger.info("Could not find url of package in registry") diff --git a/test/action/test_repo.py b/test/action/test_repo.py index a538435..8c413f2 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -129,6 +129,22 @@ def test_registry_path(): assert r._registry.get_contents.call_count == 2 +def test_registry_path_with_uppercase_uuid(): + """Test that uppercase UUIDs are normalized to lowercase for registry lookup.""" + r = _repo() + r._registry = Mock() + r._registry.get_contents.return_value.sha = "123" + r._registry.get_git_blob.return_value.content = b64encode( + b""" + [packages] + abc-def = { path = "B/Bar" } + """ + ) + # Test with uppercase UUID + r._project = lambda _k: "ABC-DEF" + assert r._registry_path == "B/Bar" + + def test_registry_url(): r = _repo() r._Repo__registry_path = "E/Example" From e1622a8fcff3864117d71352adf13e5b76d5a2fd Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 09:38:46 +0530 Subject: [PATCH 03/12] fix: handle subdirectory tree SHA lookups properly (#241) TagBot was not properly handling tree SHA lookups for packages in subdirectories. The registry stores the tree SHA for the subdirectory, but TagBot was comparing it against the root repository tree SHA, causing it to fail to find matching commits. This fixes the issue where TagBot would report "tag missing" errors for packages in subdirectories even when tags had already been created. Changes: - Add subdirectory support to _commit_sha_of_tree_from_branch method - Add subdirectory support to _commit_sha_of_tree fallback method --- tagbot/action/repo.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index dc01e8f..89cefcb 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -331,8 +331,17 @@ def _commit_sha_of_tree_from_branch( ) -> Optional[str]: """Look up the commit SHA of a tree with the given SHA on one branch.""" for commit in self._repo.get_commits(sha=branch, since=since): - if commit.commit.tree.sha == tree: - return cast(str, commit.sha) + if self.__subdir: + arg = f"{commit.sha}:{self.__subdir}" + try: + subdir_tree_hash = self._git.command("rev-parse", arg) + if subdir_tree_hash == tree: + return cast(str, commit.sha) + except Exception: + continue + else: + if commit.commit.tree.sha == tree: + return cast(str, commit.sha) return None def _commit_sha_of_tree(self, tree: str) -> Optional[str]: @@ -350,7 +359,20 @@ def _commit_sha_of_tree(self, tree: str) -> Optional[str]: # For a valid tree SHA, the only time that we reach here is when a release # has been made long after the commit was made, which is reasonably rare. # Fall back to cloning the repo in that case. - return self._git.commit_sha_of_tree(tree) + if self.__subdir: + # For subdirectories, we need to check the subdirectory tree hash + for line in self._git.command("log", "--all", "--format=%H").splitlines(): + arg = f"{line}:{self.__subdir}" + try: + subdir_tree_hash = self._git.command("rev-parse", arg) + if subdir_tree_hash == tree: + return line + except Exception: + # If rev-parse fails, skip this commit + continue + return None + else: + return self._git.commit_sha_of_tree(tree) def _commit_sha_of_tag(self, version_tag: str) -> Optional[str]: """Look up the commit SHA of a given tag.""" From 642db7fcc97a191561f9f4d7c7d9a7f85f49ab9c Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:07:11 +0530 Subject: [PATCH 04/12] Added subdirectory tree hash coverage in test_repo.py: test_commit_sha_of_tree_from_branch_subdir verifies matching when __subdir is set and the correct rev-parse calls are made. test_commit_sha_of_tree_from_branch_subdir_rev_parse_failure checks that an Abort from rev-parse is handled, logged, and iteration continues to later commits. --- tagbot/action/repo.py | 52 ++++++++++++++++++++++------------------ test/action/test_repo.py | 38 ++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 1dbba80..09e0820 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -50,8 +50,8 @@ GitlabClient = _GitlabClient GitlabUnknown = _GitlabUnknown -except Exception: - # Optional import: ignore errors if .gitlab is not available or fails to import. +except ImportError: + # Optional import: ignore errors if .gitlab is not available. pass # Build a tuple of UnknownObjectException classes for both GitHub and GitLab @@ -128,10 +128,10 @@ def __init__( self._registry_ssh_key = registry_ssh logger.debug("Will access registry via Git clone") self._clone_registry = True - except Exception: + except (GithubException, RequestException) as exc: # This is an awful hack to let me avoid properly fixing the tests... if "pytest" in sys.modules: - logger.warning("'awful hack' in use") + logger.warning("'awful hack' in use", exc_info=exc) self._registry = self._gh.get_repo(registry, lazy=True) self._clone_registry = False else: @@ -312,8 +312,7 @@ def _commit_sha_from_registry_pr(self, version: str, tree: str) -> Optional[str] # Handle special case of tagging packages in a repo subdirectory, in which # case the Julia package tree hash does not match the git commit tree hash if self.__subdir: - arg = f"{commit.sha}:{self.__subdir}" - subdir_tree_hash = self._git.command("rev-parse", arg) + subdir_tree_hash = self._subdir_tree_hash(commit.sha, suppress_abort=False) if subdir_tree_hash == tree: return cast(str, commit.sha) else: @@ -333,13 +332,11 @@ def _commit_sha_of_tree_from_branch( """Look up the commit SHA of a tree with the given SHA on one branch.""" for commit in self._repo.get_commits(sha=branch, since=since): if self.__subdir: - arg = f"{commit.sha}:{self.__subdir}" - try: - subdir_tree_hash = self._git.command("rev-parse", arg) - if subdir_tree_hash == tree: - return cast(str, commit.sha) - except Exception: - continue + subdir_tree_hash = self._subdir_tree_hash( + commit.sha, suppress_abort=True + ) + if subdir_tree_hash == tree: + return cast(str, commit.sha) else: if commit.commit.tree.sha == tree: return cast(str, commit.sha) @@ -363,18 +360,28 @@ def _commit_sha_of_tree(self, tree: str) -> Optional[str]: if self.__subdir: # For subdirectories, we need to check the subdirectory tree hash for line in self._git.command("log", "--all", "--format=%H").splitlines(): - arg = f"{line}:{self.__subdir}" - try: - subdir_tree_hash = self._git.command("rev-parse", arg) - if subdir_tree_hash == tree: - return line - except Exception: - # If rev-parse fails, skip this commit - continue + subdir_tree_hash = self._subdir_tree_hash( + line, suppress_abort=True + ) + if subdir_tree_hash == tree: + return line return None else: return self._git.commit_sha_of_tree(tree) + def _subdir_tree_hash(self, commit_sha: str, *, suppress_abort: bool) -> Optional[str]: + """Return the tree hash for a subdirectory of a commit, optionally suppressing Abort.""" + if not self.__subdir: + return None + arg = f"{commit_sha}:{self.__subdir}" + try: + return self._git.command("rev-parse", arg) + except Abort: + if suppress_abort: + logger.debug("rev-parse failed while inspecting %s", arg) + return None + raise + def _commit_sha_of_tag(self, version_tag: str) -> Optional[str]: """Look up the commit SHA of a given tag.""" try: @@ -728,8 +735,7 @@ def handle_error(self, e: Exception) -> None: try: self._report_error(trace) except Exception: - logger.error("Issue reporting failed") - logger.info(traceback.format_exc()) + logger.error("Issue reporting failed", exc_info=True) finally: raise Abort("Cannot continue due to internal failure") diff --git a/test/action/test_repo.py b/test/action/test_repo.py index 5deac34..c54ced9 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -269,6 +269,42 @@ def test_commit_sha_of_tree_from_branch(): assert r._commit_sha_of_tree_from_branch("master", "tree", since) is None +@patch("tagbot.action.repo.logger") +def test_commit_sha_of_tree_from_branch_subdir(logger): + r = _repo(subdir="path/to/package") + since = datetime.now(timezone.utc) + commits = [Mock(sha="abc"), Mock(sha="sha")] + r._repo.get_commits = Mock(return_value=commits) + r._git.command = Mock(side_effect=["other", "tree_hash"]) + + assert r._commit_sha_of_tree_from_branch("master", "tree_hash", since) == "sha" + + r._repo.get_commits.assert_called_with(sha="master", since=since) + r._git.command.assert_has_calls( + [call("rev-parse", "abc:path/to/package"), call("rev-parse", "sha:path/to/package")] + ) + logger.debug.assert_not_called() + + +@patch("tagbot.action.repo.logger") +def test_commit_sha_of_tree_from_branch_subdir_rev_parse_failure(logger): + r = _repo(subdir="path/to/package") + since = datetime.now(timezone.utc) + commits = [Mock(sha="abc"), Mock(sha="sha")] + r._repo.get_commits = Mock(return_value=commits) + r._git.command = Mock(side_effect=[Abort("missing"), "tree_hash"]) + + assert r._commit_sha_of_tree_from_branch("master", "tree_hash", since) == "sha" + + r._repo.get_commits.assert_called_with(sha="master", since=since) + logger.debug.assert_called_with( + "rev-parse failed while inspecting %s", "abc:path/to/package" + ) + r._git.command.assert_has_calls( + [call("rev-parse", "abc:path/to/package"), call("rev-parse", "sha:path/to/package")] + ) + + def test_commit_sha_of_tree(): r = _repo() now = datetime.now(timezone.utc) @@ -720,7 +756,7 @@ def test_handle_error(logger, format_exc): else: assert False r._report_error.assert_called_with("ahh") - logger.error.assert_called_with("Issue reporting failed") + logger.error.assert_called_with("Issue reporting failed", exc_info=True) @patch("traceback.format_exc", return_value="ahh") From adbe5f4a0a1044fc7cc524b2710994267b7ee3d0 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:10:22 +0530 Subject: [PATCH 05/12] formatting: utf-8 --- tagbot/action/repo.py | 10 +++++----- test/action/test_repo.py | 10 ++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 7dfd216..02c435d 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -360,17 +360,17 @@ def _commit_sha_of_tree(self, tree: str) -> Optional[str]: if self.__subdir: # For subdirectories, we need to check the subdirectory tree hash for line in self._git.command("log", "--all", "--format=%H").splitlines(): - subdir_tree_hash = self._subdir_tree_hash( - line, suppress_abort=True - ) + subdir_tree_hash = self._subdir_tree_hash(line, suppress_abort=True) if subdir_tree_hash == tree: return line return None else: return self._git.commit_sha_of_tree(tree) - def _subdir_tree_hash(self, commit_sha: str, *, suppress_abort: bool) -> Optional[str]: - """Return the tree hash for a subdirectory of a commit, optionally suppressing Abort.""" + def _subdir_tree_hash( + self, commit_sha: str, *, suppress_abort: bool + ) -> Optional[str]: + """Return subdir tree hash for a commit; optionally suppress Abort.""" if not self.__subdir: return None arg = f"{commit_sha}:{self.__subdir}" diff --git a/test/action/test_repo.py b/test/action/test_repo.py index c54ced9..d967391 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -281,7 +281,10 @@ def test_commit_sha_of_tree_from_branch_subdir(logger): r._repo.get_commits.assert_called_with(sha="master", since=since) r._git.command.assert_has_calls( - [call("rev-parse", "abc:path/to/package"), call("rev-parse", "sha:path/to/package")] + [ + call("rev-parse", "abc:path/to/package"), + call("rev-parse", "sha:path/to/package"), + ] ) logger.debug.assert_not_called() @@ -301,7 +304,10 @@ def test_commit_sha_of_tree_from_branch_subdir_rev_parse_failure(logger): "rev-parse failed while inspecting %s", "abc:path/to/package" ) r._git.command.assert_has_calls( - [call("rev-parse", "abc:path/to/package"), call("rev-parse", "sha:path/to/package")] + [ + call("rev-parse", "abc:path/to/package"), + call("rev-parse", "sha:path/to/package"), + ] ) From 1da14ca8f84ecc601b93e95aae7613f543a8a03d Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:12:52 +0530 Subject: [PATCH 06/12] Fix logger error assertion in test_repo.py --- test/action/test_repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/action/test_repo.py b/test/action/test_repo.py index d967391..7c62664 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -762,7 +762,7 @@ def test_handle_error(logger, format_exc): else: assert False r._report_error.assert_called_with("ahh") - logger.error.assert_called_with("Issue reporting failed", exc_info=True) + logger.error.assert_called_with("Issue reporting failed") @patch("traceback.format_exc", return_value="ahh") From 1059877f972554cc995950dc9ebe5aeed41944e4 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:13:36 +0530 Subject: [PATCH 07/12] Update tagbot/action/repo.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tagbot/action/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 02c435d..74ecea2 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -131,7 +131,7 @@ def __init__( except (GithubException, RequestException) as exc: # This is an awful hack to let me avoid properly fixing the tests... if "pytest" in sys.modules: - logger.warning("'awful hack' in use", exc_info=exc) + logger.warning("'awful hack' in use", exc_info=True) self._registry = self._gh.get_repo(registry, lazy=True) self._clone_registry = False else: From e75c3a10e3b116873065fe21639f34ec8aca57c9 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:14:46 +0530 Subject: [PATCH 08/12] Simplify warning log for hack in tests Remove exception info from warning log for hack usage. --- tagbot/action/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 74ecea2..1363c3a 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -131,7 +131,7 @@ def __init__( except (GithubException, RequestException) as exc: # This is an awful hack to let me avoid properly fixing the tests... if "pytest" in sys.modules: - logger.warning("'awful hack' in use", exc_info=True) + logger.warning("'awful hack' in use") self._registry = self._gh.get_repo(registry, lazy=True) self._clone_registry = False else: From 2e2033dae46b94163047b701cdd3a99bbc7538df Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:19:50 +0530 Subject: [PATCH 09/12] Update repo.py --- tagbot/action/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 1363c3a..02c435d 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -131,7 +131,7 @@ def __init__( except (GithubException, RequestException) as exc: # This is an awful hack to let me avoid properly fixing the tests... if "pytest" in sys.modules: - logger.warning("'awful hack' in use") + logger.warning("'awful hack' in use", exc_info=exc) self._registry = self._gh.get_repo(registry, lazy=True) self._clone_registry = False else: From a249a1e47af3f018c3cf000100cd4aad76f14c01 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:27:56 +0530 Subject: [PATCH 10/12] copilot test coverage --- test/action/test_repo.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/action/test_repo.py b/test/action/test_repo.py index 7c62664..5ff16ec 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -332,6 +332,43 @@ def test_commit_sha_of_tree(): assert r._commit_sha_of_tree("tree") is None +@patch("tagbot.action.repo.logger") +def test_commit_sha_of_tree_subdir_fallback(logger): + """Test subdirectory fallback when branch lookups fail.""" + r = _repo(subdir="path/to/package") + now = datetime.now(timezone.utc) + r._repo = Mock(default_branch="master") + branches = r._repo.get_branches.return_value = [Mock()] + branches[0].name = "master" + r._lookback = Mock(__rsub__=lambda x, y: now) + # Branch lookups return None (fail) + r._commit_sha_of_tree_from_branch = Mock(return_value=None) + # git log returns commit SHAs + r._git.command = Mock(return_value="abc123\ndef456\nghi789") + # _subdir_tree_hash called via helper, simulate finding match on second commit + with patch.object(r, "_subdir_tree_hash", side_effect=[None, "tree_hash", "other"]): + assert r._commit_sha_of_tree("tree_hash") == "def456" + # Verify it iterated through commits + assert r._subdir_tree_hash.call_count == 2 + + +@patch("tagbot.action.repo.logger") +def test_commit_sha_of_tree_subdir_fallback_no_match(logger): + """Test subdirectory fallback returns None when no match found.""" + r = _repo(subdir="path/to/package") + now = datetime.now(timezone.utc) + r._repo = Mock(default_branch="master") + branches = r._repo.get_branches.return_value = [Mock()] + branches[0].name = "master" + r._lookback = Mock(__rsub__=lambda x, y: now) + r._commit_sha_of_tree_from_branch = Mock(return_value=None) + r._git.command = Mock(return_value="abc123\ndef456") + # No matches found + with patch.object(r, "_subdir_tree_hash", return_value=None): + assert r._commit_sha_of_tree("tree_hash") is None + assert r._subdir_tree_hash.call_count == 2 + + def test_commit_sha_of_tag(): r = _repo() r._repo.get_git_ref = Mock() From 7b4621fd775a91995cb6de51f0da83f0320cf1c2 Mon Sep 17 00:00:00 2001 From: Arnav Kapoor Date: Tue, 9 Dec 2025 15:34:55 +0530 Subject: [PATCH 11/12] Update tagbot/action/repo.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tagbot/action/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 02c435d..ea633fb 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -51,7 +51,7 @@ GitlabClient = _GitlabClient GitlabUnknown = _GitlabUnknown except ImportError: - # Optional import: ignore errors if .gitlab is not available. + # Optional import: ignore import errors if .gitlab is not available. pass # Build a tuple of UnknownObjectException classes for both GitHub and GitLab From c87fb112c614bbc9736468498600ca8c95b20358 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 9 Dec 2025 13:32:27 -0500 Subject: [PATCH 12/12] Improve subdirectory tree SHA lookup performance and cleanup tests - Add -n 10000 limit to git log fallback to prevent perf issues on large repos - Remove unused logger mock decorators from subdir fallback tests Co-authored-by: Claude --- tagbot/action/repo.py | 7 +++++-- test/action/test_repo.py | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index ea633fb..38f60e1 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -358,8 +358,11 @@ def _commit_sha_of_tree(self, tree: str) -> Optional[str]: # has been made long after the commit was made, which is reasonably rare. # Fall back to cloning the repo in that case. if self.__subdir: - # For subdirectories, we need to check the subdirectory tree hash - for line in self._git.command("log", "--all", "--format=%H").splitlines(): + # For subdirectories, we need to check the subdirectory tree hash. + # Limit to 10000 commits to avoid performance issues on large repos. + for line in self._git.command( + "log", "--all", "--format=%H", "-n", "10000" + ).splitlines(): subdir_tree_hash = self._subdir_tree_hash(line, suppress_abort=True) if subdir_tree_hash == tree: return line diff --git a/test/action/test_repo.py b/test/action/test_repo.py index 5ff16ec..c6a744b 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -332,8 +332,7 @@ def test_commit_sha_of_tree(): assert r._commit_sha_of_tree("tree") is None -@patch("tagbot.action.repo.logger") -def test_commit_sha_of_tree_subdir_fallback(logger): +def test_commit_sha_of_tree_subdir_fallback(): """Test subdirectory fallback when branch lookups fail.""" r = _repo(subdir="path/to/package") now = datetime.now(timezone.utc) @@ -352,8 +351,7 @@ def test_commit_sha_of_tree_subdir_fallback(logger): assert r._subdir_tree_hash.call_count == 2 -@patch("tagbot.action.repo.logger") -def test_commit_sha_of_tree_subdir_fallback_no_match(logger): +def test_commit_sha_of_tree_subdir_fallback_no_match(): """Test subdirectory fallback returns None when no match found.""" r = _repo(subdir="path/to/package") now = datetime.now(timezone.utc)