diff --git a/src/ahriman/core/build_tools/sources.py b/src/ahriman/core/build_tools/sources.py index f3dfd4b5..e09ac3d1 100644 --- a/src/ahriman/core/build_tools/sources.py +++ b/src/ahriman/core/build_tools/sources.py @@ -64,8 +64,9 @@ class Sources(LazyLogging): return None # no previous reference found instance = Sources() - instance.fetch_until(source_dir, commit_sha=last_commit_sha) - return instance.diff(source_dir, last_commit_sha) + if instance.fetch_until(source_dir, commit_sha=last_commit_sha) is not None: + return instance.diff(source_dir, last_commit_sha) + return None @staticmethod def extend_architectures(sources_dir: Path, architecture: str) -> list[PkgbuildPatch]: @@ -298,7 +299,8 @@ class Sources(LazyLogging): args.append(sha) return check_output(*self.git(), "diff", *args, cwd=sources_dir, logger=self.logger) - def fetch_until(self, sources_dir: Path, *, branch: str | None = None, commit_sha: str | None = None) -> None: + def fetch_until(self, sources_dir: Path, *, branch: str | None = None, commit_sha: str | None = None, + max_depth: int = 10) -> str | None: """ fetch repository until commit sha @@ -307,11 +309,16 @@ class Sources(LazyLogging): branch(str | None, optional): use specified branch (Default value = None) commit_sha(str | None, optional): commit hash to fetch. If none set, only one will be fetched (Default value = None) + max_depth(int, optional): maximal amount of commits to fetch if ``commit_sha`` is set (Default value = 10) + + Returns: + str | None: fetched ``commit_sha`` (if set) and ``None`` in case if commit wasn't found or + ``commit_sha`` is not set """ commit_sha = commit_sha or "HEAD" # if none set we just fetch the last commit commits_count = 1 - while commit_sha is not None: + while commits_count <= max_depth: command = self.git() + ["fetch", "--quiet", "--depth", str(commits_count)] if branch is not None: command += ["origin", branch] @@ -320,10 +327,13 @@ class Sources(LazyLogging): try: # check if there is an object in current git directory check_output(*self.git(), "cat-file", "-e", commit_sha, cwd=sources_dir, logger=self.logger) - commit_sha = None # reset search + return commit_sha # found the required commit except CalledProcessError: commits_count += 1 # increase depth + # no commits found at the requested depth + return None + def git(self, gitconfig: dict[str, str] | None = None) -> list[str]: """ git command prefix diff --git a/tests/ahriman/core/build_tools/test_sources.py b/tests/ahriman/core/build_tools/test_sources.py index 41d1b8f6..62484a03 100644 --- a/tests/ahriman/core/build_tools/test_sources.py +++ b/tests/ahriman/core/build_tools/test_sources.py @@ -39,6 +39,17 @@ def test_changes_skip(mocker: MockerFixture) -> None: diff_mock.assert_not_called() +def test_changes_unknown_commit(mocker: MockerFixture) -> None: + """ + must return none in case if commit sha wasn't found at the required depth + """ + mocker.patch("ahriman.core.build_tools.sources.Sources.fetch_until", return_value=None) + diff_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.diff") + + assert Sources.changes(Path("local"), "sha") is None + diff_mock.assert_not_called() + + def test_extend_architectures(mocker: MockerFixture) -> None: """ must update available architecture list @@ -435,16 +446,17 @@ def test_fetch_until(sources: Sources, mocker: MockerFixture) -> None: "", "", ]) - local = Path("local") - sources.fetch_until(local, branch="master", commit_sha="sha") + last_commit_sha = "sha" + + assert sources.fetch_until(local, branch="master", commit_sha="sha") == last_commit_sha check_output_mock.assert_has_calls([ MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", "origin", "master", cwd=local, logger=sources.logger), - MockCall(*sources.git(), "cat-file", "-e", "sha", cwd=local, logger=sources.logger), + MockCall(*sources.git(), "cat-file", "-e", last_commit_sha, cwd=local, logger=sources.logger), MockCall(*sources.git(), "fetch", "--quiet", "--depth", "2", "origin", "master", cwd=local, logger=sources.logger), - MockCall(*sources.git(), "cat-file", "-e", "sha", cwd=local, logger=sources.logger), + MockCall(*sources.git(), "cat-file", "-e", last_commit_sha, cwd=local, logger=sources.logger), ]) @@ -453,9 +465,9 @@ def test_fetch_until_first(sources: Sources, mocker: MockerFixture) -> None: must fetch first commit only """ check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output") - local = Path("local") - sources.fetch_until(local, branch="master") + + assert sources.fetch_until(local, branch="master") == "HEAD" check_output_mock.assert_has_calls([ MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", "origin", "master", cwd=local, logger=sources.logger), @@ -468,15 +480,28 @@ def test_fetch_until_all_branches(sources: Sources, mocker: MockerFixture) -> No must fetch all branches """ check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output") - local = Path("local") - sources.fetch_until(local) + + assert sources.fetch_until(local) == "HEAD" check_output_mock.assert_has_calls([ MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", cwd=local, logger=sources.logger), MockCall(*sources.git(), "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger), ]) +def test_fetch_until_not_found(sources: Sources, mocker: MockerFixture) -> None: + """ + must return None in case if no commit found at the required maximal depth + """ + mocker.patch("ahriman.core.build_tools.sources.check_output", side_effect=[ + "", + CalledProcessError(1, ["command"], "error"), + "", + CalledProcessError(1, ["command"], "error"), + ]) + assert sources.fetch_until(Path("local"), branch="master", commit_sha="sha", max_depth=2) is None + + def test_git(sources: Sources) -> None: """ must correctly generate git command