add gitremote pull trigger

This commit is contained in:
Evgenii Alekseev 2022-10-15 02:24:26 +03:00
parent fc0d8387df
commit 4ae76bc3dd
55 changed files with 399 additions and 122 deletions

View File

@ -82,7 +82,8 @@ disable=raw-checker-failed,
fixme,
too-many-arguments,
duplicate-code,
cyclic-import
cyclic-import,
confusing-with-statement,
# Enable the message, report, category or checker with the given id(s). You can

View File

@ -56,4 +56,4 @@ version:
ifndef VERSION
$(error VERSION is required, but not set)
endif
sed -i '/__version__ = .*/s/[^"][^)]*/__version__ = "$(VERSION)"/' src/ahriman/version.py
sed -i 's/^__version__ = .*/__version__ = "$(VERSION)"/' src/ahriman/version.py

View File

@ -391,7 +391,7 @@ just perform check for packages without rebuild process itself
.TP
\fB\-\-from\-database\fR
read packages from database instead of filesystem. This feature in particular is required in case if you would like to
restore repository from another repository instance. Note however that in order to restore packages you need to have
restore repository from another repository instance. Note, however, that in order to restore packages you need to have
original ahriman instance run with web service and have run repo\-update at least once.
.TP

View File

@ -0,0 +1,21 @@
ahriman.core.gitremote package
==============================
Submodules
----------
ahriman.core.gitremote.remote\_pkgbuild\_trigger module
-------------------------------------------------------
.. automodule:: ahriman.core.gitremote.remote_pkgbuild_trigger
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ahriman.core.gitremote
:members:
:no-undoc-members:
:show-inheritance:

View File

@ -12,6 +12,7 @@ Subpackages
ahriman.core.build_tools
ahriman.core.database
ahriman.core.formatters
ahriman.core.gitremote
ahriman.core.report
ahriman.core.repository
ahriman.core.sign

View File

@ -75,6 +75,14 @@ Settings for signing packages or repository. Group name can refer to architectur
* ``key`` - default PGP key, string, required. This key will also be used for database signing if enabled.
* ``key_*`` settings - PGP key which will be used for specific packages, string, optional. For example, if there is ``key_yay`` option the specified key will be used for yay package and default key for others.
``gitremote`` group
-------------------
Remote git source synchronization settings. Unlike ``Upload`` triggers those triggers are used for PKGBUILD synchronization - e.g. fetch from remote repository PKGBUILDs before updating process or pulling updated PKGBUILDs to the remote repository.
* ``pull_url`` - url of the remote repository from which PKGBUILDs can be pulled before build process, string, required.
* ``pull_branch`` - branch of the remote repository from which PKGBUILDs can be pulled before build process, string, optional, default is ``master``.
``report`` group
----------------

View File

@ -112,6 +112,30 @@ TL;DR
Before using this command you will need to create local directory, put ``PKGBUILD`` there and generate ``.SRCINFO`` by using ``makepkg --printsrcinfo > .SRCINFO`` command. These packages will be stored locally and *will be ignored* during automatic update; in order to update the package you will need to run ``package-add`` command again.
Err, I have remote repository with PKGBUILDs and would like to get versions from there automatically
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For that purpose you could use ``RemotePkgbuildTrigger`` trigger. To do so you will need:
#.
Append ``triggers`` option in ``build`` section with the following line:
.. code-block:: ini
[build]
triggers = ahriman.core.gitremote.RemotePkgbuildTrigger
#.
Configure trigger like following:
.. code-block:: ini
[gitremote]
pull_url = https://github.com/username/repository
During the next application run it will fetch repository from the specified url and will try to find packages there which can be used as local sources.
But I just wanted to change PKGBUILD from AUR a bit!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -49,7 +49,7 @@ Obviously you can implement the specified method in class, but for guide purpose
self.channel = configuration.get("slack", "channel")
self.username = configuration.get("slack", "username")
def run(self, result, packages):
def on_result(self, result, packages):
notify(result, self.slack_url, self.channel, self.username)
Setup the trigger

View File

@ -49,15 +49,6 @@ class Application(ApplicationPackages, ApplicationRepository):
be used instead.
"""
def _finalize(self, result: Result) -> None:
"""
generate report and sync to remote server
Args:
result(Result): build result
"""
self.repository.process_triggers(result)
def _known_packages(self) -> Set[str]:
"""
load packages from repository and pacman repositories
@ -73,3 +64,26 @@ class Application(ApplicationPackages, ApplicationRepository):
known_packages.update(properties.provides)
known_packages.update(self.repository.pacman.all_packages())
return known_packages
def on_result(self, result: Result) -> None:
"""
generate report and sync to remote server
Args:
result(Result): build result
"""
packages = self.repository.packages()
self.repository.triggers.on_result(result, packages)
def on_start(self) -> None:
"""
run triggers on start of the application
"""
self.repository.triggers.on_start()
def on_stop(self) -> None:
"""
run triggers on stop of the application. Note, however, that in most cases this method should not be called
directly as it will be called after on_start action
"""
self.repository.triggers.on_stop()

View File

@ -37,18 +37,6 @@ class ApplicationPackages(ApplicationProperties):
package control class
"""
def _finalize(self, result: Result) -> None:
"""
generate report and sync to remote server
Args:
result(Result): build result
Raises:
NotImplementedError: not implemented method
"""
raise NotImplementedError
def _known_packages(self) -> Set[str]:
"""
load packages from repository and pacman repositories
@ -61,6 +49,18 @@ class ApplicationPackages(ApplicationProperties):
"""
raise NotImplementedError
def on_result(self, result: Result) -> None:
"""
generate report and sync to remote server
Args:
result(Result): build result
Raises:
NotImplementedError: not implemented method
"""
raise NotImplementedError
def _add_archive(self, source: str, *_: Any) -> None:
"""
add package from archive
@ -86,8 +86,7 @@ class ApplicationPackages(ApplicationProperties):
self.database.build_queue_insert(package)
self.database.remote_update(package)
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, \
(local_dir := Path(dir_name)): # pylint: disable=confusing-with-statement
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (local_dir := Path(dir_name)):
Sources.load(local_dir, package, self.database.patches_get(package.base), self.repository.paths)
self._process_dependencies(local_dir, known_packages, without_dependencies)
@ -187,4 +186,4 @@ class ApplicationPackages(ApplicationProperties):
names(Iterable[str]): list of packages (either base or name) to remove
"""
self.repository.process_remove(names)
self._finalize(Result())
self.on_result(Result())

View File

@ -35,7 +35,7 @@ class ApplicationRepository(ApplicationProperties):
repository control class
"""
def _finalize(self, result: Result) -> None:
def on_result(self, result: Result) -> None:
"""
generate report and sync to remote server
@ -89,7 +89,7 @@ class ApplicationRepository(ApplicationProperties):
self.update([])
# sign repository database if set
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
self._finalize(Result())
self.on_result(Result())
def unknown(self) -> List[str]:
"""
@ -139,7 +139,7 @@ class ApplicationRepository(ApplicationProperties):
if not paths:
return # don't need to process if no update supplied
update_result = self.repository.process_update(paths)
self._finalize(result.merge(update_result))
self.on_result(result.merge(update_result))
# process built packages
build_result = Result()

View File

@ -45,6 +45,7 @@ class Add(Handler):
unsafe(bool): if set no user check will be performed before path creation
"""
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
application.add(args.package, args.source, args.without_dependencies)
if not args.now:
return

View File

@ -44,5 +44,6 @@ class Clean(Handler):
no_report(bool): force disable reporting
unsafe(bool): if set no user check will be performed before path creation
"""
Application(architecture, configuration, no_report, unsafe).clean(
args.cache, args.chroot, args.manual, args.packages)
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
application.clean(args.cache, args.chroot, args.manual, args.packages)

View File

@ -46,5 +46,5 @@ class KeyImport(Handler):
no_report(bool): force disable reporting
unsafe(bool): if set no user check will be performed before path creation
"""
Application(architecture, configuration, no_report, unsafe).repository.sign.key_import(
args.key_server, args.key)
application = Application(architecture, configuration, no_report, unsafe)
application.repository.sign.key_import(args.key_server, args.key)

View File

@ -50,6 +50,7 @@ class Patch(Handler):
unsafe(bool): if set no user check will be performed before path creation
"""
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
if args.action == Action.List:
Patch.patch_set_list(application, args.package, args.exit_code)

View File

@ -49,6 +49,8 @@ class Rebuild(Handler):
depends_on = set(args.depends_on) if args.depends_on else None
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
if args.from_database:
updates = Rebuild.extract_packages(application)
else:

View File

@ -44,4 +44,6 @@ class Remove(Handler):
no_report(bool): force disable reporting
unsafe(bool): if set no user check will be performed before path creation
"""
Application(architecture, configuration, no_report, unsafe).remove(args.package)
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
application.remove(args.package)

View File

@ -46,6 +46,7 @@ class RemoveUnknown(Handler):
unsafe(bool): if set no user check will be performed before path creation
"""
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
unknown_packages = application.unknown()
if args.dry_run:

View File

@ -49,4 +49,5 @@ class Triggers(Handler):
if args.trigger:
loader = application.repository.triggers
loader.triggers = [loader.load_trigger(trigger) for trigger in args.trigger]
application.repository.process_triggers(Result())
application.on_start()
application.on_result(Result())

View File

@ -45,6 +45,7 @@ class Update(Handler):
unsafe(bool): if set no user check will be performed before path creation
"""
application = Application(architecture, configuration, no_report, unsafe)
application.on_start()
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
Update.log_fn(application, args.dry_run))
Update.check_if_empty(args.exit_code, not packages)

View File

@ -0,0 +1,20 @@
#
# copyright (c) 2021-2022 ahriman team.
#
# this file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# this program is free software: you can redistribute it and/or modify
# it under the terms of the gnu general public license as published by
# the free software foundation, either version 3 of the license, or
# (at your option) any later version.
#
# this program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose. see the
# gnu general public license for more details.
#
# you should have received a copy of the gnu general public license
# along with this program. if not, see <http://www.gnu.org/licenses/>.
#
from ahriman.core.gitremote.remote_pull_trigger import RemotePullTrigger

View File

@ -0,0 +1,86 @@
#
# copyright (c) 2021-2022 ahriman team.
#
# this file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# this program is free software: you can redistribute it and/or modify
# it under the terms of the gnu general public license as published by
# the free software foundation, either version 3 of the license, or
# (at your option) any later version.
#
# this program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose. see the
# gnu general public license for more details.
#
# you should have received a copy of the gnu general public license
# along with this program. if not, see <http://www.gnu.org/licenses/>.
#
import shutil
from pathlib import Path
from tempfile import TemporaryDirectory
from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration
from ahriman.core.triggers import Trigger
from ahriman.core.util import walk
from ahriman.models.package_source import PackageSource
from ahriman.models.remote_source import RemoteSource
class RemotePullTrigger(Trigger):
"""
trigger for fetching PKGBUILDs from remote repository
Attributes:
remote_source(RemoteSource): repository remote source (remote pull url and branch)
repository_paths(RepositoryPaths): repository paths instance
"""
def __init__(self, architecture: str, configuration: Configuration) -> None:
"""
default constructor
Args:
architecture(str): repository architecture
configuration(Configuration): configuration instance
"""
Trigger.__init__(self, architecture, configuration)
self.remote_source = RemoteSource(
git_url=configuration.get("gitremote", "pull_url"),
web_url="",
path=".",
branch=configuration.get("gitremote", "pull_branch", fallback="master"),
source=PackageSource.Local,
)
self.repository_paths = configuration.repository_paths
def on_start(self) -> None:
"""
trigger action which will be called at the start of the application
"""
self.repo_clone()
def repo_clone(self) -> None:
"""
clone repository from remote source
"""
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (clone_dir := Path(dir_name)):
Sources.fetch(clone_dir, self.remote_source)
self.repo_copy(clone_dir)
def repo_copy(self, clone_dir: Path) -> None:
"""
copy directories from cloned remote source to local cache
Args:
clone_dir(Path): path to temporary cloned directory
"""
for pkgbuild_path in filter(lambda path: path.name == "PKGBUILD", walk(clone_dir)):
cloned_pkgbuild_dir = pkgbuild_path.parent
package_base = cloned_pkgbuild_dir.name
local_pkgbuild_dir = self.repository_paths.cache_for(package_base)
shutil.copytree(cloned_pkgbuild_dir, local_pkgbuild_dir, dirs_exist_ok=True)
Sources.init(local_pkgbuild_dir) # initialized git repository is required for local sources

View File

@ -17,5 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from ahriman.core.report.report import Report
from ahriman.core.report.report_trigger import ReportTrigger

View File

@ -21,7 +21,7 @@ from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import BuildPrinter
from ahriman.core.report import Report
from ahriman.core.report.report import Report
from ahriman.models.package import Package
from ahriman.models.result import Result

View File

@ -25,8 +25,8 @@ from email.mime.text import MIMEText
from typing import Dict, Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.report import Report
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
from ahriman.core.util import pretty_datetime
from ahriman.models.package import Package
from ahriman.models.result import Result

View File

@ -20,8 +20,8 @@
from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.report import Report
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
from ahriman.models.package import Package
from ahriman.models.result import Result

View File

@ -21,7 +21,7 @@ from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.triggers import Trigger
from ahriman.core.report import Report
from ahriman.core.report.report import Report
from ahriman.models.package import Package
from ahriman.models.result import Result

View File

@ -23,8 +23,8 @@ import requests
from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.report import Report
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
from ahriman.core.util import exception_response_text
from ahriman.models.package import Package
from ahriman.models.result import Result

View File

@ -84,8 +84,7 @@ class Executor(Cleaner):
result = Result()
for single in updates:
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, \
(build_dir := Path(dir_name)): # pylint: disable=confusing-with-statement
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (build_dir := Path(dir_name)):
try:
build_single(single, build_dir)
result.add_success(single)
@ -144,15 +143,6 @@ class Executor(Cleaner):
return self.repo.repo_path
def process_triggers(self, result: Result) -> None:
"""
process triggers setup by settings
Args:
result(Result): build result
"""
self.triggers.on_result(result, self.packages())
def process_update(self, packages: Iterable[Path]) -> Result:
"""
sign packages, add them to repository and update repository database

View File

@ -72,8 +72,7 @@ class Leaf:
Returns:
Leaf: loaded class
"""
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, \
(clone_dir := Path(dir_name)): # pylint: disable=confusing-with-statement
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (clone_dir := Path(dir_name)):
Sources.load(clone_dir, package, database.patches_get(package.base), paths)
dependencies = Package.dependencies(clone_dir)
return cls(package, dependencies)

View File

@ -20,7 +20,6 @@
import contextlib
import importlib
import os
import weakref
from pathlib import Path
from types import ModuleType
@ -74,9 +73,15 @@ class TriggerLoader(LazyLogging):
self.load_trigger(trigger)
for trigger in configuration.getlist("build", "triggers")
]
self._on_stop_requested = False
self.on_start()
self._finalizer = weakref.finalize(self, self.on_stop)
def __del__(self) -> None:
"""
custom destructor object which calls on_stop in case if it was requested
"""
if not self._on_stop_requested:
return
self.on_stop()
@contextlib.contextmanager
def __execute_trigger(self, trigger: Trigger) -> Generator[None, None, None]:
@ -178,6 +183,7 @@ class TriggerLoader(LazyLogging):
result(Result): build result
packages(Iterable[Package]): list of all available packages
"""
self.logger.debug("executing triggers on result")
for trigger in self.triggers:
with self.__execute_trigger(trigger):
trigger.on_result(result, packages)
@ -186,6 +192,8 @@ class TriggerLoader(LazyLogging):
"""
run triggers on load
"""
self.logger.debug("executing triggers on start")
self._on_stop_requested = True
for trigger in self.triggers:
with self.__execute_trigger(trigger):
trigger.on_start()
@ -194,6 +202,7 @@ class TriggerLoader(LazyLogging):
"""
run triggers before the application exit
"""
self.logger.debug("executing triggers on stop")
for trigger in self.triggers:
with self.__execute_trigger(trigger):
trigger.on_stop()

View File

@ -17,5 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from ahriman.core.upload.upload import Upload
from ahriman.core.upload.upload_trigger import UploadTrigger

View File

@ -24,7 +24,7 @@ from pathlib import Path
from typing import Any, Dict
from ahriman.core.configuration import Configuration
from ahriman.core.upload import Upload
from ahriman.core.upload.upload import Upload
from ahriman.core.util import exception_response_text

View File

@ -21,7 +21,7 @@ from pathlib import Path
from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.upload import Upload
from ahriman.core.upload.upload import Upload
from ahriman.core.util import check_output
from ahriman.models.package import Package

View File

@ -25,7 +25,7 @@ from pathlib import Path
from typing import Any, Dict, Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.upload import Upload
from ahriman.core.upload.upload import Upload
from ahriman.core.util import walk
from ahriman.models.package import Package

View File

@ -21,7 +21,7 @@ from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.triggers import Trigger
from ahriman.core.upload import Upload
from ahriman.core.upload.upload import Upload
from ahriman.models.package import Package
from ahriman.models.result import Result

View File

@ -5,16 +5,6 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_finalize(application: Application, mocker: MockerFixture) -> None:
"""
must report and sync at the last
"""
triggers_mock = mocker.patch("ahriman.core.repository.Repository.process_triggers")
application._finalize(Result())
triggers_mock.assert_called_once_with(Result())
def test_known_packages(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must return not empty list of known packages
@ -23,3 +13,34 @@ def test_known_packages(application: Application, package_ahriman: Package, mock
packages = application._known_packages()
assert len(packages) > 1
assert package_ahriman.base in packages
def test_on_result(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must call on_result trigger function
"""
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_result")
application.on_result(Result())
triggers_mock.assert_called_once_with(Result(), [package_ahriman])
def test_on_start(application: Application, mocker: MockerFixture) -> None:
"""
must call on_start trigger function
"""
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_start")
application.on_start()
triggers_mock.assert_called_once_with()
def test_on_stop(application: Application, mocker: MockerFixture) -> None:
"""
must call on_stop trigger function
"""
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_stop")
application.on_stop()
triggers_mock.assert_called_once_with()

View File

@ -11,12 +11,12 @@ from ahriman.models.package_source import PackageSource
from ahriman.models.result import Result
def test_finalize(application_packages: ApplicationPackages) -> None:
def test_on_result(application_packages: ApplicationPackages) -> None:
"""
must raise NotImplemented for missing finalize method
"""
with pytest.raises(NotImplementedError):
application_packages._finalize([])
application_packages.on_result(Result())
def test_known_packages(application_packages: ApplicationPackages) -> None:
@ -242,8 +242,8 @@ def test_remove(application_packages: ApplicationPackages, mocker: MockerFixture
must remove package
"""
executor_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove")
finalize_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._finalize")
on_result_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages.on_result")
application_packages.remove([])
executor_mock.assert_called_once_with([])
finalize_mock.assert_called_once_with(Result())
on_result_mock.assert_called_once_with(Result())

View File

@ -9,12 +9,12 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_finalize(application_repository: ApplicationRepository) -> None:
def test_on_result(application_repository: ApplicationRepository) -> None:
"""
must raise NotImplemented for missing finalize method
"""
with pytest.raises(NotImplementedError):
application_repository._finalize(Result())
application_repository.on_result(Result())
def test_clean_cache(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
@ -63,8 +63,8 @@ def test_sign(application_repository: ApplicationRepository, package_ahriman: Pa
copy_mock = mocker.patch("shutil.copy")
update_mock = mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.update")
sign_repository_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_repository")
finalize_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository._finalize")
on_result_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
application_repository.sign([])
copy_mock.assert_has_calls([
@ -73,7 +73,7 @@ def test_sign(application_repository: ApplicationRepository, package_ahriman: Pa
])
update_mock.assert_called_once_with([])
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
finalize_mock.assert_called_once_with(Result())
on_result_mock.assert_called_once_with(Result())
def test_sign_skip(application_repository: ApplicationRepository, package_ahriman: Package,
@ -84,7 +84,7 @@ def test_sign_skip(application_repository: ApplicationRepository, package_ahrima
package_ahriman.packages[package_ahriman.base].filename = None
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.update")
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository._finalize")
mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.on_result")
application_repository.sign([])
@ -99,8 +99,8 @@ def test_sign_specific(application_repository: ApplicationRepository, package_ah
copy_mock = mocker.patch("shutil.copy")
update_mock = mocker.patch("ahriman.application.application.application_repository.ApplicationRepository.update")
sign_repository_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_repository")
finalize_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository._finalize")
on_result_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
filename = package_ahriman.packages[package_ahriman.base].filepath
application_repository.sign([package_ahriman.base])
@ -109,7 +109,7 @@ def test_sign_specific(application_repository: ApplicationRepository, package_ah
application_repository.repository.paths.packages / filename.name)
update_mock.assert_called_once_with([])
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
finalize_mock.assert_called_once_with(Result())
on_result_mock.assert_called_once_with(Result())
def test_unknown_no_aur(application_repository: ApplicationRepository, package_ahriman: Package,
@ -163,13 +163,13 @@ def test_update(application_repository: ApplicationRepository, package_ahriman:
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=paths)
build_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_build", return_value=result)
update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update", return_value=result)
finalize_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository._finalize")
on_result_mock = mocker.patch(
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
application_repository.update([package_ahriman])
build_mock.assert_called_once_with([package_ahriman])
update_mock.assert_has_calls([mock.call(paths), mock.call(paths)])
finalize_mock.assert_has_calls([mock.call(result), mock.call(result)])
on_result_mock.assert_has_calls([mock.call(result), mock.call(result)])
def test_update_empty(application_repository: ApplicationRepository, package_ahriman: Package,

View File

@ -35,9 +35,11 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args = _default_args(args)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.add")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Add.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with(args.package, args.source, args.without_dependencies)
on_start_mock.assert_called_once_with()
def test_run_with_updates(args: argparse.Namespace, configuration: Configuration,

View File

@ -30,6 +30,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args = _default_args(args)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.clean")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Clean.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with(False, False, False, False)
on_start_mock.assert_called_once_with()

View File

@ -36,9 +36,11 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args.action = Action.Update
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Patch.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), Path(args.package), args.track)
on_start_mock.assert_called_once_with()
def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:

View File

@ -41,11 +41,13 @@ def test_run(args: argparse.Namespace, package_ahriman: Package,
return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Rebuild.run(args, "x86_64", configuration, True, False)
application_packages_mock.assert_called_once_with(None)
application_mock.assert_called_once_with([package_ahriman])
check_mock.assert_has_calls([mock.call(False, False), mock.call(False, False)])
on_start_mock.assert_called_once_with()
def test_run_extract_packages(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:

View File

@ -27,6 +27,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args = _default_args(args)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Remove.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with([])
on_start_mock.assert_called_once_with()

View File

@ -32,10 +32,12 @@ def test_run(args: argparse.Namespace, package_ahriman: Package,
application_mock = mocker.patch("ahriman.application.application.Application.unknown",
return_value=[package_ahriman])
remove_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
RemoveUnknown.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with()
remove_mock.assert_called_once_with([package_ahriman])
on_start_mock.assert_called_once_with()
def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package,

View File

@ -28,10 +28,12 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
"""
args = _default_args(args)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.core.repository.Repository.process_triggers")
application_mock = mocker.patch("ahriman.application.application.Application.on_result")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Triggers.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with(Result())
on_start_mock.assert_called_once_with()
def test_run_trigger(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package,

View File

@ -43,12 +43,14 @@ def test_run(args: argparse.Namespace, package_ahriman: Package,
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Update.run(args, "x86_64", configuration, True, False)
application_mock.assert_called_once_with([package_ahriman])
updates_mock.assert_called_once_with(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
pytest.helpers.anyvar(int))
check_mock.assert_has_calls([mock.call(False, False), mock.call(False, False)])
on_start_mock.assert_called_once_with()
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:

View File

@ -0,0 +1,58 @@
import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from unittest import mock
from ahriman.core.configuration import Configuration
from ahriman.core.gitremote import RemotePullTrigger
def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must clone repo on start
"""
clone_mock = mocker.patch("ahriman.core.gitremote.RemotePullTrigger.repo_clone")
trigger = RemotePullTrigger("x86_64", configuration)
trigger.on_start()
clone_mock.assert_called_once_with()
def test_repo_clone(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must clone repository locally and copy its content
"""
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
copy_mock = mocker.patch("ahriman.core.gitremote.RemotePullTrigger.repo_copy")
trigger = RemotePullTrigger("x86_64", configuration)
trigger.repo_clone()
fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), trigger.remote_source)
copy_mock.assert_called_once_with(pytest.helpers.anyvar(int))
def test_repo_copy(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must copy repository tree from temporary directory to the local cache
"""
mocker.patch("ahriman.core.gitremote.remote_pull_trigger.walk", return_value=[
Path("local") / "package1" / "PKGBUILD",
Path("local") / "package1" / ".SRCINFO",
Path("local") / "package2" / ".SRCINFO",
Path("local") / "package3" / "PKGBUILD",
Path("local") / "package3" / ".SRCINFO",
])
copytree_mock = mocker.patch("shutil.copytree")
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
trigger = RemotePullTrigger("x86_64", configuration)
trigger.repo_copy(Path("local"))
copytree_mock.assert_has_calls([
mock.call(Path("local") / "package1", configuration.repository_paths.cache_for("package1"), dirs_exist_ok=True),
mock.call(Path("local") / "package3", configuration.repository_paths.cache_for("package3"), dirs_exist_ok=True),
])
init_mock.assert_has_calls([
mock.call(configuration.repository_paths.cache_for("package1")),
mock.call(configuration.repository_paths.cache_for("package3")),
])

View File

@ -4,7 +4,7 @@ from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ReportFailed
from ahriman.core.report import Report
from ahriman.core.report.report import Report
from ahriman.models.report_settings import ReportSettings
from ahriman.models.result import Result
@ -23,7 +23,7 @@ def test_report_dummy(configuration: Configuration, result: Result, mocker: Mock
must construct dummy report class
"""
mocker.patch("ahriman.models.report_settings.ReportSettings.from_option", return_value=ReportSettings.Disabled)
report_mock = mocker.patch("ahriman.core.report.Report.generate")
report_mock = mocker.patch("ahriman.core.report.report.Report.generate")
Report.load("x86_64", configuration, "disabled").run(result, [])
report_mock.assert_called_once_with([], result)

View File

@ -10,7 +10,7 @@ def test_on_result(configuration: Configuration, mocker: MockerFixture) -> None:
must run report for specified targets
"""
configuration.set_option("report", "target", "email")
run_mock = mocker.patch("ahriman.core.report.Report.run")
run_mock = mocker.patch("ahriman.core.report.report.Report.run")
trigger = ReportTrigger("x86_64", configuration)
trigger.on_result(Result(), [])

View File

@ -4,7 +4,6 @@ from pathlib import Path
from pytest_mock import MockerFixture
from unittest import mock
from ahriman.core.report import Report
from ahriman.core.repository.executor import Executor
from ahriman.models.package import Package
from ahriman.models.result import Result
@ -144,17 +143,6 @@ def test_process_remove_nothing(executor: Executor, package_ahriman: Package, pa
repo_remove_mock.assert_not_called()
def test_process_triggers(executor: Executor, package_ahriman: Package, result: Result, mocker: MockerFixture) -> None:
"""
must process report
"""
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
triggers_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.on_result")
executor.process_triggers(result)
triggers_mock.assert_called_once_with(result, [package_ahriman])
def test_process_update(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run update process

View File

@ -10,19 +10,6 @@ from ahriman.models.package import Package
from ahriman.models.result import Result
def test_init_at_exit(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must call on_start on init and on_stop on exit
"""
on_start_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_start")
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
trigger_loader = TriggerLoader("x86_64", configuration)
on_start_mock.assert_called_once_with()
del trigger_loader
on_stop_mock.assert_called_once_with()
def test_load_trigger_package(trigger_loader: TriggerLoader) -> None:
"""
must load trigger from package
@ -123,10 +110,34 @@ def test_on_start(trigger_loader: TriggerLoader, package_ahriman: Package, mocke
report_mock = mocker.patch("ahriman.core.report.ReportTrigger.on_start")
trigger_loader.on_start()
assert trigger_loader._on_stop_requested
report_mock.assert_called_once_with()
upload_mock.assert_called_once_with()
def test_on_stop_with_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must call on_stop on exit if on_start was called
"""
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
trigger_loader = TriggerLoader("x86_64", configuration)
trigger_loader.on_start()
del trigger_loader
on_stop_mock.assert_called_once_with()
def test_on_stop_without_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must call not on_stop on exit if on_start wasn't called
"""
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
trigger_loader = TriggerLoader("x86_64", configuration)
del trigger_loader
on_stop_mock.assert_not_called()
def test_on_stop(trigger_loader: TriggerLoader, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run triggers on stop

View File

@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import SyncFailed
from ahriman.core.upload import Upload
from ahriman.core.upload.upload import Upload
from ahriman.models.upload_settings import UploadSettings
@ -23,7 +23,7 @@ def test_report_dummy(configuration: Configuration, mocker: MockerFixture) -> No
must construct dummy upload class
"""
mocker.patch("ahriman.models.upload_settings.UploadSettings.from_option", return_value=UploadSettings.Disabled)
upload_mock = mocker.patch("ahriman.core.upload.Upload.sync")
upload_mock = mocker.patch("ahriman.core.upload.upload.Upload.sync")
Upload.load("x86_64", configuration, "disabled").run(Path("path"), [])
upload_mock.assert_called_once_with(Path("path"), [])

View File

@ -10,7 +10,7 @@ def test_on_result(configuration: Configuration, mocker: MockerFixture) -> None:
must run report for specified targets
"""
configuration.set_option("upload", "target", "rsync")
run_mock = mocker.patch("ahriman.core.upload.Upload.run")
run_mock = mocker.patch("ahriman.core.upload.upload.Upload.run")
trigger = UploadTrigger("x86_64", configuration)
trigger.on_result(Result(), [])

View File

@ -31,6 +31,9 @@ root = ../../../
[sign]
target =
[gitremote]
pull_url = https://github.com/arcan1s/repository.git
[report]
target =