feat: implement local reporter mode (#126)

* implement local reporter mode

* simplify watcher class

* review changes

* do not update unknown status

* allow empty key patches via api

* fix some pylint warnings in tests
This commit is contained in:
2024-05-21 16:27:17 +03:00
parent 2b9880bd3c
commit c8afcbf36a
93 changed files with 2409 additions and 935 deletions

View File

@ -93,8 +93,7 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p
side_effect=lambda *args: packages[args[0].name])
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages",
return_value={"devtools", "python-build", "python-pytest"})
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.package_base_update")
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown")
status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
result = application.with_dependencies([package_ahriman], process_dependencies=True)
assert {package.base: package for package in result} == packages
@ -107,11 +106,6 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p
], any_order=True)
packages_mock.assert_called_once_with()
update_remote_mock.assert_has_calls([
MockCall(package_python_schedule),
MockCall(packages["python"]),
MockCall(packages["python-installer"]),
], any_order=True)
status_client_mock.assert_has_calls([
MockCall(package_python_schedule),
MockCall(packages["python"]),

View File

@ -41,11 +41,11 @@ def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Pac
"""
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.package_base_update")
status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
application_packages._add_aur(package_ahriman.base, "packager")
build_queue_mock.assert_called_once_with(package_ahriman)
update_remote_mock.assert_called_once_with(package_ahriman)
status_client_mock.assert_called_once_with(package_ahriman)
def test_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
@ -153,11 +153,11 @@ def test_add_repository(application_packages: ApplicationPackages, package_ahrim
"""
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.package_base_update")
status_client_mock = mocker.patch("ahriman.core.status.Client.set_unknown")
application_packages._add_repository(package_ahriman.base, "packager")
build_queue_mock.assert_called_once_with(package_ahriman)
update_remote_mock.assert_called_once_with(package_ahriman)
status_client_mock.assert_called_once_with(package_ahriman)
def test_add_add_archive(application_packages: ApplicationPackages, package_ahriman: Package,

View File

@ -1,15 +1,15 @@
from ahriman.application.application.application_properties import ApplicationProperties
def test_create_tree(application_properties: ApplicationProperties) -> None:
"""
must have repository attribute
"""
assert application_properties.repository
def test_architecture(application_properties: ApplicationProperties) -> None:
"""
must return repository architecture
"""
assert application_properties.architecture == application_properties.repository_id.architecture
def test_reporter(application_properties: ApplicationProperties) -> None:
"""
must have reporter attribute
"""
assert application_properties.reporter

View File

@ -17,14 +17,12 @@ def test_changes(application_repository: ApplicationRepository, package_ahriman:
must generate changes for the packages
"""
changes = Changes("hash", "change")
hashes_mock = mocker.patch("ahriman.core.database.SQLite.hashes_get", return_value={
package_ahriman.base: changes.last_commit_sha,
})
hashes_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=changes)
changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes", return_value=changes)
report_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set")
report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
application_repository.changes([package_ahriman])
hashes_mock.assert_called_once_with()
hashes_mock.assert_called_once_with(package_ahriman.base)
changes_mock.assert_called_once_with(package_ahriman, changes.last_commit_sha)
report_mock.assert_called_once_with(package_ahriman.base, changes)
@ -34,9 +32,8 @@ def test_changes_skip(application_repository: ApplicationRepository, package_ahr
"""
must skip change generation if no last commit sha has been found
"""
mocker.patch("ahriman.core.database.SQLite.hashes_get", return_value={})
changes_mock = mocker.patch("ahriman.core.repository.Repository.package_changes")
report_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set")
report_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
application_repository.changes([package_ahriman])
changes_mock.assert_not_called()

View File

@ -62,11 +62,11 @@ def test_run_with_patches(args: argparse.Namespace, configuration: Configuration
args.variable = ["KEY=VALUE"]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.add")
application_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert")
application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_update")
_, repository_id = configuration.check_loaded()
Add.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(args.package[0], [PkgbuildPatch("KEY", "VALUE")])
application_mock.assert_called_once_with(args.package[0], PkgbuildPatch("KEY", "VALUE"))
def test_run_with_updates(args: argparse.Namespace, configuration: Configuration, repository: Repository,

View File

@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_get",
application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get",
return_value=Changes("sha", "change"))
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
@ -54,7 +54,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
args = _default_args(args)
args.exit_code = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.status.client.Client.package_changes_get", return_value=Changes())
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes())
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
_, repository_id = configuration.check_loaded()
@ -70,7 +70,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
args = _default_args(args)
args.action = Action.Remove
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_mock = mocker.patch("ahriman.core.status.client.Client.package_changes_set")
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
_, repository_id = configuration.check_loaded()
Change.run(args, repository_id, configuration, report=False)

View File

@ -160,13 +160,28 @@ def test_patch_set_list(application: Application, mocker: MockerFixture) -> None
"""
must list available patches for the command
"""
get_mock = mocker.patch("ahriman.core.database.SQLite.patches_list",
return_value={"ahriman": PkgbuildPatch(None, "patch")})
get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
return_value=[PkgbuildPatch(None, "patch"), PkgbuildPatch("version", "value")])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Patch.patch_set_list(application, "ahriman", ["version"], False)
get_mock.assert_called_once_with("ahriman", ["version"])
get_mock.assert_called_once_with("ahriman", None)
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ")
check_mock.assert_called_once_with(False, False)
def test_patch_set_list_all(application: Application, mocker: MockerFixture) -> None:
"""
must list all available patches for the command
"""
get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
return_value=[PkgbuildPatch(None, "patch")])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Patch.patch_set_list(application, "ahriman", None, False)
get_mock.assert_called_once_with("ahriman", None)
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator=" = ")
check_mock.assert_called_once_with(False, False)
@ -175,7 +190,7 @@ def test_patch_set_list_empty_exception(application: Application, mocker: Mocker
"""
must raise ExitCode exception on empty patch list
"""
mocker.patch("ahriman.core.database.SQLite.patches_list", return_value={})
mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", return_value={})
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Patch.patch_set_list(application, "ahriman", [], True)
@ -186,18 +201,27 @@ def test_patch_set_create(application: Application, package_ahriman: Package, mo
"""
must create patch set for the package
"""
create_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert")
create_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_update")
Patch.patch_set_create(application, package_ahriman.base, PkgbuildPatch("version", package_ahriman.version))
create_mock.assert_called_once_with(package_ahriman.base, [PkgbuildPatch("version", package_ahriman.version)])
create_mock.assert_called_once_with(package_ahriman.base, PkgbuildPatch("version", package_ahriman.version))
def test_patch_set_remove(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must remove patch set for the package
"""
remove_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove")
remove_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_remove")
Patch.patch_set_remove(application, package_ahriman.base, ["version"])
remove_mock.assert_called_once_with(package_ahriman.base, ["version"])
remove_mock.assert_called_once_with(package_ahriman.base, "version")
def test_patch_set_remove_all(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must remove all patches for the package
"""
remove_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_remove")
Patch.patch_set_remove(application, package_ahriman.base, None)
remove_mock.assert_called_once_with(package_ahriman.base, None)
def test_disallow_multi_architecture_run() -> None:

View File

@ -185,7 +185,7 @@ def test_extract_packages_by_status(application: Application, mocker: MockerFixt
("package2", BuildStatus(BuildStatusEnum.Failed)),
])
assert Rebuild.extract_packages(application, BuildStatusEnum.Failed, from_database=True) == ["package2"]
packages_mock.assert_called_once_with()
packages_mock.assert_called_once_with(application.repository_id)
def test_extract_packages_from_database(application: Application, mocker: MockerFixture) -> None:
@ -194,4 +194,4 @@ def test_extract_packages_from_database(application: Application, mocker: Mocker
"""
packages_mock = mocker.patch("ahriman.core.database.SQLite.packages_get")
Rebuild.extract_packages(application, None, from_database=True)
packages_mock.assert_called_once_with()
packages_mock.assert_called_once_with(application.repository_id)

View File

@ -37,8 +37,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.status.client.Client.status_get")
packages_mock = mocker.patch("ahriman.core.status.client.Client.package_get",
application_mock = mocker.patch("ahriman.core.status.Client.status_get")
packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
@ -63,8 +63,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
args = _default_args(args)
args.exit_code = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.status.client.Client.status_get")
mocker.patch("ahriman.core.status.client.Client.package_get", return_value=[])
mocker.patch("ahriman.core.status.Client.status_get")
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
_, repository_id = configuration.check_loaded()
@ -80,7 +80,7 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep
args = _default_args(args)
args.info = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.status.client.Client.package_get",
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
@ -100,7 +100,7 @@ def test_run_with_package_filter(args: argparse.Namespace, configuration: Config
args = _default_args(args)
args.package = [package_ahriman.base]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
packages_mock = mocker.patch("ahriman.core.status.client.Client.package_get",
packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
_, repository_id = configuration.check_loaded()
@ -115,7 +115,7 @@ def test_run_by_status(args: argparse.Namespace, configuration: Configuration, r
"""
args = _default_args(args)
args.status = BuildStatusEnum.Failed
mocker.patch("ahriman.core.status.client.Client.package_get",
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success)),
(package_python_schedule, BuildStatus(BuildStatusEnum.Failed))])
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)

View File

@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_self_mock = mocker.patch("ahriman.core.status.client.Client.status_update")
update_self_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.status_update")
_, repository_id = configuration.check_loaded()
StatusUpdate.run(args, repository_id, configuration, report=False)
@ -42,20 +42,17 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
def test_run_packages(args: argparse.Namespace, configuration: Configuration, repository: Repository,
package_ahriman: Package, mocker: MockerFixture) -> None:
mocker: MockerFixture) -> None:
"""
must run command with specified packages
"""
args = _default_args(args)
args.package = [package_ahriman.base, "package"]
args.package = ["package"]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
add_mock = mocker.patch("ahriman.core.status.client.Client.package_add")
update_mock = mocker.patch("ahriman.core.status.client.Client.package_update")
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_update")
_, repository_id = configuration.check_loaded()
StatusUpdate.run(args, repository_id, configuration, report=False)
add_mock.assert_called_once_with(package_ahriman, args.status)
update_mock.assert_called_once_with("package", args.status)
@ -68,7 +65,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
args.package = [package_ahriman.base]
args.action = Action.Remove
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_mock = mocker.patch("ahriman.core.status.client.Client.package_remove")
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_remove")
_, repository_id = configuration.check_loaded()
StatusUpdate.run(args, repository_id, configuration, report=False)

View File

@ -27,7 +27,7 @@ def test_path(args: argparse.Namespace, configuration: Configuration) -> None:
with pytest.raises(ValueError):
args.lock = Path("/")
Lock(args, repository_id, configuration).path # special case
assert Lock(args, repository_id, configuration).path # special case
def test_check_user(lock: Lock, mocker: MockerFixture) -> None:
@ -64,7 +64,7 @@ def test_check_version(lock: Lock, mocker: MockerFixture) -> None:
"""
must check version correctly
"""
mocker.patch("ahriman.core.status.client.Client.status_get",
mocker.patch("ahriman.core.status.Client.status_get",
return_value=InternalStatus(status=BuildStatus(), version=__version__))
logging_mock = mocker.patch("logging.Logger.warning")
@ -76,7 +76,7 @@ def test_check_version_mismatch(lock: Lock, mocker: MockerFixture) -> None:
"""
must check mismatched version correctly
"""
mocker.patch("ahriman.core.status.client.Client.status_get",
mocker.patch("ahriman.core.status.Client.status_get",
return_value=InternalStatus(status=BuildStatus(), version="version"))
logging_mock = mocker.patch("logging.Logger.warning")
@ -184,7 +184,7 @@ def test_enter(lock: Lock, mocker: MockerFixture) -> None:
watch_mock = mocker.patch("ahriman.application.lock.Lock.watch")
clear_mock = mocker.patch("ahriman.application.lock.Lock.clear")
create_mock = mocker.patch("ahriman.application.lock.Lock.create")
update_status_mock = mocker.patch("ahriman.core.status.client.Client.status_update")
update_status_mock = mocker.patch("ahriman.core.status.Client.status_update")
with lock:
pass
@ -203,9 +203,9 @@ def test_exit_with_exception(lock: Lock, mocker: MockerFixture) -> None:
mocker.patch("ahriman.application.lock.Lock.check_user")
mocker.patch("ahriman.application.lock.Lock.clear")
mocker.patch("ahriman.application.lock.Lock.create")
update_status_mock = mocker.patch("ahriman.core.status.client.Client.status_update")
update_status_mock = mocker.patch("ahriman.core.status.Client.status_update")
with pytest.raises(Exception):
with pytest.raises(ValueError):
with lock:
raise Exception()
raise ValueError()
update_status_mock.assert_has_calls([MockCall(BuildStatusEnum.Building), MockCall(BuildStatusEnum.Failed)])