From 10e4f3b629cdd2f3d4e4efeaccd050c1b3a516bb Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Mon, 29 Mar 2021 03:24:58 +0300 Subject: [PATCH] Setup command (#9) * block issues without templates * add setup subcommand * handle devtools config correctly --- .github/ISSUE_TEMPLATE/config.yml | 1 + README.md | 6 +- src/ahriman/application/ahriman.py | 34 ++-- src/ahriman/application/handlers/__init__.py | 1 + src/ahriman/application/handlers/setup.py | 160 ++++++++++++++++++ .../application/handlers/test_handler_add.py | 9 +- .../handlers/test_handler_clean.py | 13 +- .../handlers/test_handler_remove.py | 7 +- .../handlers/test_handler_report.py | 7 +- .../handlers/test_handler_setup.py | 145 ++++++++++++++++ .../application/handlers/test_handler_sign.py | 7 +- .../handlers/test_handler_status.py | 10 +- .../application/handlers/test_handler_sync.py | 7 +- .../handlers/test_handler_update.py | 18 +- tests/ahriman/application/test_ahriman.py | 18 ++ tests/testresources/core/ahriman.ini | 1 + 16 files changed, 406 insertions(+), 38 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 src/ahriman/application/handlers/setup.py create mode 100644 tests/ahriman/application/handlers/test_handler_setup.py diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3ba13e0c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/README.md b/README.md index e5c6e5c9..a4443df3 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,14 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github * Create `/var/lib/ahriman/.makepkg.conf` with `makepkg.conf` overrides if required (at least you might want to set `PACKAGER`): ```shell - echo 'PACKAGES="John Doe "' | sudo -u ahriman tee -a /var/lib/ahriman/.makepkg.conf + echo 'PACKAGER="John Doe "' | sudo -u ahriman tee -a /var/lib/ahriman/.makepkg.conf ``` * Configure build tools (it is required for correct dependency management system): * create build command, e.g. `ln -s /usr/bin/archbuild /usr/local/bin/ahriman-x86_64-build` (you can choose any name for command, basically it should be `{name}-{arch}-build`); * create configuration file, e.g. `cp /usr/share/devtools/pacman-{extra,ahriman}.conf` (same as previous `pacman-{name}.conf`); - * change configuration file, add your own repository, add multilib repository etc. Hint: you can use `Include` option as well; + * change configuration file, add your own repository, add multilib repository etc; * set `build_command` option to point to your command; * configure `/etc/sudoers.d/ahriman` to allow running command without a password. @@ -66,3 +66,5 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github ```shell sudo -u ahriman ahriman -a x86_64 add yay ``` + +Note that initial service configuration can be done by running `ahriman setup` with specific arguments. diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index 218b04f9..4b8f07e0 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -31,12 +31,8 @@ def _parser() -> argparse.ArgumentParser: :return: command line parser for the application """ parser = argparse.ArgumentParser(prog="ahriman", description="ArcHlinux ReposItory MANager") - parser.add_argument( - "-a", - "--architecture", - help="target architectures (can be used multiple times)", - action="append", - required=True) + parser.add_argument("-a", "--architecture", help="target architectures (can be used multiple times)", + action="append", required=True) parser.add_argument("-c", "--config", help="configuration path", default="/etc/ahriman.ini") parser.add_argument("--force", help="force run, remove file lock", action="store_true") parser.add_argument("--lock", help="lock file", default="/tmp/ahriman.lock") @@ -44,6 +40,7 @@ def _parser() -> argparse.ArgumentParser: parser.add_argument("--no-report", help="force disable reporting to web service", action="store_true") parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user", action="store_true") parser.add_argument("-v", "--version", action="version", version=version.__version__) + subparsers = parser.add_subparsers(title="command", help="command to run", dest="command", required=True) add_parser = subparsers.add_parser("add", description="add package") @@ -60,12 +57,10 @@ def _parser() -> argparse.ArgumentParser: clean_parser.add_argument("--no-build", help="do not clear directory with package sources", action="store_true") clean_parser.add_argument("--no-cache", help="do not clear directory with package caches", action="store_true") clean_parser.add_argument("--no-chroot", help="do not clear build chroot", action="store_true") - clean_parser.add_argument( - "--no-manual", - help="do not clear directory with manually added packages", - action="store_true") + clean_parser.add_argument("--no-manual", help="do not clear directory with manually added packages", + action="store_true") clean_parser.add_argument("--no-packages", help="do not clear directory with built packages", action="store_true") - clean_parser.set_defaults(handler=handlers.Clean) + clean_parser.set_defaults(handler=handlers.Clean, unsafe=True) config_parser = subparsers.add_parser("config", description="dump configuration for specified architecture") config_parser.set_defaults(handler=handlers.Dump, lock=None, no_report=True, unsafe=True) @@ -81,6 +76,15 @@ def _parser() -> argparse.ArgumentParser: report_parser.add_argument("target", help="target to generate report", nargs="*") report_parser.set_defaults(handler=handlers.Report) + setup_parser = subparsers.add_parser("setup", description="create initial service configuration, requires root") + setup_parser.add_argument("--build-command", help="build command prefix", default="ahriman") + setup_parser.add_argument("--from-config", help="path to default devtools pacman configuration", + default="/usr/share/devtools/pacman-extra.conf") + setup_parser.add_argument("--no-multilib", help="do not add multilib repository", action="store_true") + setup_parser.add_argument("--packager", help="packager name and email", required=True) + setup_parser.add_argument("--repository", help="repository name", default="aur-clone") + setup_parser.set_defaults(handler=handlers.Setup, lock=None, no_report=True, unsafe=True) + sign_parser = subparsers.add_parser("sign", description="(re-)sign packages and repository database") sign_parser.add_argument("package", help="sign only specified packages", nargs="*") sign_parser.set_defaults(handler=handlers.Sign) @@ -96,8 +100,8 @@ def _parser() -> argparse.ArgumentParser: update_parser = subparsers.add_parser("update", description="run updates") update_parser.add_argument("package", help="filter check by package base", nargs="*") - update_parser.add_argument( - "--dry-run", help="just perform check for updates, same as check command", action="store_true") + update_parser.add_argument("--dry-run", help="just perform check for updates, same as check command", + action="store_true") update_parser.add_argument("--no-aur", help="do not check for AUR updates. Implies --no-vcs", action="store_true") update_parser.add_argument("--no-manual", help="do not include manual updates", action="store_true") update_parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true") @@ -110,8 +114,8 @@ def _parser() -> argparse.ArgumentParser: if __name__ == "__main__": - arg_parser = _parser() - args = arg_parser.parse_args() + args_parser = _parser() + args = args_parser.parse_args() handler: handlers.Handler = args.handler status = handler.execute(args) diff --git a/src/ahriman/application/handlers/__init__.py b/src/ahriman/application/handlers/__init__.py index 7691c927..d64f241b 100644 --- a/src/ahriman/application/handlers/__init__.py +++ b/src/ahriman/application/handlers/__init__.py @@ -25,6 +25,7 @@ from ahriman.application.handlers.dump import Dump from ahriman.application.handlers.rebuild import Rebuild from ahriman.application.handlers.remove import Remove from ahriman.application.handlers.report import Report +from ahriman.application.handlers.setup import Setup from ahriman.application.handlers.sign import Sign from ahriman.application.handlers.status import Status from ahriman.application.handlers.sync import Sync diff --git a/src/ahriman/application/handlers/setup.py b/src/ahriman/application/handlers/setup.py new file mode 100644 index 00000000..a168310c --- /dev/null +++ b/src/ahriman/application/handlers/setup.py @@ -0,0 +1,160 @@ +# +# Copyright (c) 2021 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 . +# +import argparse +import configparser + +from pathlib import Path +from typing import Type + +from ahriman.application.application import Application +from ahriman.application.handlers.handler import Handler +from ahriman.core.configuration import Configuration +from ahriman.models.repository_paths import RepositoryPaths + + +class Setup(Handler): + """ + setup handler + :cvar ARCHBUILD_COMMAND_PATH: default devtools command + :cvar BIN_DIR_PATH: directory for custom binaries + :cvar MIRRORLIST_PATH: path to pacman default mirrorlist (used by multilib repository) + :cvar SUDOERS_PATH: path to sudoers.d include configuration + """ + + ARCHBUILD_COMMAND_PATH = Path("/usr/bin/archbuild") + BIN_DIR_PATH = Path("/usr/local/bin") + MIRRORLIST_PATH = Path("/etc/pacman.d/mirrorlist") + SUDOERS_PATH = Path("/etc/sudoers.d/ahriman") + + @classmethod + def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None: + """ + callback for command line + :param args: command line args + :param architecture: repository architecture + :param config: configuration instance + """ + application = Application(architecture, config) + Setup.create_makepkg_configuration(args.packager, application.repository.paths) + Setup.create_executable(args.build_command, architecture) + Setup.create_devtools_configuration(args.build_command, architecture, Path(args.from_config), args.no_multilib, + args.repository, application.repository.paths) + Setup.create_ahriman_configuration(args.build_command, architecture, args.repository, config.include) + Setup.create_sudo_configuration(args.build_command, architecture) + + @staticmethod + def build_command(prefix: str, architecture: str) -> Path: + """ + generate build command name + :param prefix: command prefix in {prefix}-{architecture}-build + :param architecture: repository architecture + :return: valid devtools command name + """ + return Setup.BIN_DIR_PATH / f"{prefix}-{architecture}-build" + + @staticmethod + def create_ahriman_configuration(prefix: str, architecture: str, repository: str, include_path: Path) -> None: + """ + create service specific configuration + :param prefix: command prefix in {prefix}-{architecture}-build + :param architecture: repository architecture + :param repository: repository name + :param include_path: path to directory with configuration includes + """ + config = configparser.ConfigParser() + + config.add_section("build") + config.set("build", "build_command", str(Setup.build_command(prefix, architecture))) + + config.add_section("repository") + config.set("repository", "name", repository) + + target = include_path / "build-overrides.ini" + with target.open("w") as ahriman_config: + config.write(ahriman_config) + + @staticmethod + def create_devtools_configuration(prefix: str, architecture: str, source: Path, + no_multilib: bool, repository: str, paths: RepositoryPaths) -> None: + """ + create configuration for devtools based on `source` configuration + :param prefix: command prefix in {prefix}-{architecture}-build + :param architecture: repository architecture + :param source: path to source configuration file + :param no_multilib: do not add multilib repository + :param repository: repository name + :param paths: repository paths instance + """ + config = configparser.ConfigParser() + # preserve case + # stupid mypy thinks that it is impossible + config.optionxform = lambda key: key # type: ignore + + # load default configuration first + # we cannot use Include here because it will be copied to new chroot, thus no includes there + config.read(source) + + # set our architecture now + config.set("options", "Architecture", architecture) + + # add multilib + if not no_multilib: + config.add_section("multilib") + config.set("multilib", "Include", str(Setup.MIRRORLIST_PATH)) + + # add repository itself + config.add_section(repository) + config.set(repository, "SigLevel", "Optional TrustAll") # we don't care + config.set(repository, "Server", f"file://{paths.repository}") + + target = source.parent / f"pacman-{prefix}.conf" + with target.open("w") as devtools_config: + config.write(devtools_config) + + @staticmethod + def create_makepkg_configuration(packager: str, paths: RepositoryPaths) -> None: + """ + create configuration for makepkg + :param packager: packager identifier (e.g. name, email) + :param paths: repository paths instance + """ + (paths.root / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n") + + @staticmethod + def create_sudo_configuration(prefix: str, architecture: str) -> None: + """ + create configuration to run build command with sudo without password + :param prefix: command prefix in {prefix}-{architecture}-build + :param architecture: repository architecture + """ + command = Setup.build_command(prefix, architecture) + Setup.SUDOERS_PATH.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n") + Setup.SUDOERS_PATH.chmod(0o400) # security! + + @staticmethod + def create_executable(prefix: str, architecture: str) -> None: + """ + create executable for the service + :param prefix: command prefix in {prefix}-{architecture}-build + :param architecture: repository architecture + """ + command = Setup.build_command(prefix, architecture) + command.unlink(missing_ok=True) + command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH) diff --git a/tests/ahriman/application/handlers/test_handler_add.py b/tests/ahriman/application/handlers/test_handler_add.py index 671ff6ee..4a6f0a4e 100644 --- a/tests/ahriman/application/handlers/test_handler_add.py +++ b/tests/ahriman/application/handlers/test_handler_add.py @@ -6,12 +6,17 @@ from ahriman.application.handlers import Add from ahriman.core.configuration import Configuration +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.package = [] + args.without_dependencies = False + return args + + def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ - args.package = [] - args.without_dependencies = False + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.add") diff --git a/tests/ahriman/application/handlers/test_handler_clean.py b/tests/ahriman/application/handlers/test_handler_clean.py index 50555798..db2c0e06 100644 --- a/tests/ahriman/application/handlers/test_handler_clean.py +++ b/tests/ahriman/application/handlers/test_handler_clean.py @@ -6,15 +6,20 @@ from ahriman.application.handlers import Clean from ahriman.core.configuration import Configuration -def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: - """ - must run command - """ +def _default_args(args: argparse.Namespace) -> argparse.Namespace: args.no_build = False args.no_cache = False args.no_chroot = False args.no_manual = False args.no_packages = False + return args + + +def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: + """ + must run command + """ + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.clean") diff --git a/tests/ahriman/application/handlers/test_handler_remove.py b/tests/ahriman/application/handlers/test_handler_remove.py index 5f9a22b2..df990cbc 100644 --- a/tests/ahriman/application/handlers/test_handler_remove.py +++ b/tests/ahriman/application/handlers/test_handler_remove.py @@ -6,11 +6,16 @@ from ahriman.application.handlers import Remove from ahriman.core.configuration import Configuration +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.package = [] + return args + + def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ - args.package = [] + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.remove") diff --git a/tests/ahriman/application/handlers/test_handler_report.py b/tests/ahriman/application/handlers/test_handler_report.py index 9dbba316..7deaa60d 100644 --- a/tests/ahriman/application/handlers/test_handler_report.py +++ b/tests/ahriman/application/handlers/test_handler_report.py @@ -6,11 +6,16 @@ from ahriman.application.handlers import Report from ahriman.core.configuration import Configuration +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.target = [] + return args + + def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ - args.target = [] + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.report") diff --git a/tests/ahriman/application/handlers/test_handler_setup.py b/tests/ahriman/application/handlers/test_handler_setup.py new file mode 100644 index 00000000..686b85ee --- /dev/null +++ b/tests/ahriman/application/handlers/test_handler_setup.py @@ -0,0 +1,145 @@ +import argparse + +from pathlib import Path +from pytest_mock import MockerFixture +from unittest import mock + +from ahriman.application.handlers import Setup +from ahriman.core.configuration import Configuration +from ahriman.models.repository_paths import RepositoryPaths + + +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.build_command = "ahriman" + args.from_config = "/usr/share/devtools/pacman-extra.conf" + args.no_multilib = False + args.packager = "John Doe " + args.repository = "aur-clone" + return args + + +def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: + """ + must run command + """ + args = _default_args(args) + mocker.patch("pathlib.Path.mkdir") + ahriman_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_ahriman_configuration") + devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_devtools_configuration") + makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_makepkg_configuration") + sudo_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_sudo_configuration") + executable_mock = mocker.patch("ahriman.application.handlers.setup.Setup.create_executable") + + Setup.run(args, "x86_64", configuration) + ahriman_configuration_mock.assert_called_once() + devtools_configuration_mock.assert_called_once() + makepkg_configuration_mock.assert_called_once() + sudo_configuration_mock.assert_called_once() + executable_mock.assert_called_once() + + +def test_build_command(args: argparse.Namespace) -> None: + """ + must generate correct build command name + """ + args = _default_args(args) + assert Setup.build_command(args.build_command, "x86_64").name == f"{args.build_command}-x86_64-build" + + +def test_create_ahriman_configuration(args: argparse.Namespace, configuration: Configuration, + mocker: MockerFixture) -> None: + """ + must create configuration for the service + """ + args = _default_args(args) + mocker.patch("pathlib.Path.open") + add_section_mock = mocker.patch("configparser.RawConfigParser.add_section") + set_mock = mocker.patch("configparser.RawConfigParser.set") + write_mock = mocker.patch("configparser.RawConfigParser.write") + + command = Setup.build_command(args.build_command, "x86_64") + Setup.create_ahriman_configuration(args.build_command, "x86_64", args.repository, configuration.include) + add_section_mock.assert_has_calls([ + mock.call("build"), + mock.call("repository"), + ]) + set_mock.assert_has_calls([ + mock.call("build", "build_command", str(command)), + mock.call("repository", "name", args.repository), + ]) + write_mock.assert_called_once() + + +def test_create_devtools_configuration(args: argparse.Namespace, repository_paths: RepositoryPaths, + mocker: MockerFixture) -> None: + """ + must create configuration for the devtools + """ + args = _default_args(args) + mocker.patch("pathlib.Path.open") + mocker.patch("configparser.RawConfigParser.set") + add_section_mock = mocker.patch("configparser.RawConfigParser.add_section") + write_mock = mocker.patch("configparser.RawConfigParser.write") + + Setup.create_devtools_configuration(args.build_command, "x86_64", Path(args.from_config), args.no_multilib, + args.repository, repository_paths) + add_section_mock.assert_has_calls([ + mock.call("multilib"), + mock.call(args.repository) + ]) + write_mock.assert_called_once() + + +def test_create_devtools_configuration_no_multilib(args: argparse.Namespace, repository_paths: RepositoryPaths, + mocker: MockerFixture) -> None: + """ + must create configuration for the devtools without multilib + """ + args = _default_args(args) + mocker.patch("pathlib.Path.open") + mocker.patch("configparser.RawConfigParser.set") + add_section_mock = mocker.patch("configparser.RawConfigParser.add_section") + write_mock = mocker.patch("configparser.RawConfigParser.write") + + Setup.create_devtools_configuration(args.build_command, "x86_64", Path(args.from_config), True, + args.repository, repository_paths) + add_section_mock.assert_called_once() + write_mock.assert_called_once() + + +def test_create_makepkg_configuration(args: argparse.Namespace, repository_paths: RepositoryPaths, + mocker: MockerFixture) -> None: + """ + must create makepkg configuration + """ + args = _default_args(args) + write_text_mock = mocker.patch("pathlib.Path.write_text") + + Setup.create_makepkg_configuration(args.packager, repository_paths) + write_text_mock.assert_called_once() + + +def test_create_sudo_configuration(args: argparse.Namespace, mocker: MockerFixture) -> None: + """ + must create sudo configuration + """ + args = _default_args(args) + chmod_text_mock = mocker.patch("pathlib.Path.chmod") + write_text_mock = mocker.patch("pathlib.Path.write_text") + + Setup.create_sudo_configuration(args.build_command, "x86_64") + chmod_text_mock.assert_called_with(0o400) + write_text_mock.assert_called_once() + + +def test_create_executable(args: argparse.Namespace, mocker: MockerFixture) -> None: + """ + must create executable + """ + args = _default_args(args) + symlink_text_mock = mocker.patch("pathlib.Path.symlink_to") + unlink_text_mock = mocker.patch("pathlib.Path.unlink") + + Setup.create_executable(args.build_command, "x86_64") + symlink_text_mock.assert_called_once() + unlink_text_mock.assert_called_once() diff --git a/tests/ahriman/application/handlers/test_handler_sign.py b/tests/ahriman/application/handlers/test_handler_sign.py index 38f906f4..0b16f01a 100644 --- a/tests/ahriman/application/handlers/test_handler_sign.py +++ b/tests/ahriman/application/handlers/test_handler_sign.py @@ -6,11 +6,16 @@ from ahriman.application.handlers import Sign from ahriman.core.configuration import Configuration +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.package = [] + return args + + def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ - args.package = [] + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.sign") diff --git a/tests/ahriman/application/handlers/test_handler_status.py b/tests/ahriman/application/handlers/test_handler_status.py index 8ded654e..a1cac924 100644 --- a/tests/ahriman/application/handlers/test_handler_status.py +++ b/tests/ahriman/application/handlers/test_handler_status.py @@ -6,13 +6,17 @@ from ahriman.application.handlers import Status from ahriman.core.configuration import Configuration +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.ahriman = True + args.package = [] + return args + + def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ - args.ahriman = True - args.package = [] - args.without_dependencies = False + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.core.status.client.Client.get_self") packages_mock = mocker.patch("ahriman.core.status.client.Client.get") diff --git a/tests/ahriman/application/handlers/test_handler_sync.py b/tests/ahriman/application/handlers/test_handler_sync.py index 4926976e..28dac940 100644 --- a/tests/ahriman/application/handlers/test_handler_sync.py +++ b/tests/ahriman/application/handlers/test_handler_sync.py @@ -6,11 +6,16 @@ from ahriman.application.handlers import Sync from ahriman.core.configuration import Configuration +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + args.target = [] + return args + + def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must run command """ - args.target = [] + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.sync") diff --git a/tests/ahriman/application/handlers/test_handler_update.py b/tests/ahriman/application/handlers/test_handler_update.py index 3de20521..a4bbafd2 100644 --- a/tests/ahriman/application/handlers/test_handler_update.py +++ b/tests/ahriman/application/handlers/test_handler_update.py @@ -6,15 +6,20 @@ from ahriman.application.handlers import Update from ahriman.core.configuration import Configuration -def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: - """ - must run command - """ +def _default_args(args: argparse.Namespace) -> argparse.Namespace: args.package = [] args.dry_run = False args.no_aur = False args.no_manual = False args.no_vcs = False + return args + + +def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: + """ + must run command + """ + args = _default_args(args) mocker.patch("pathlib.Path.mkdir") application_mock = mocker.patch("ahriman.application.application.Application.update") updates_mock = mocker.patch("ahriman.application.application.Application.get_updates") @@ -28,11 +33,8 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, moc """ must run simplified command """ - args.package = [] + args = _default_args(args) args.dry_run = True - args.no_aur = False - args.no_manual = False - args.no_vcs = False mocker.patch("pathlib.Path.mkdir") updates_mock = mocker.patch("ahriman.application.application.Application.get_updates") diff --git a/tests/ahriman/application/test_ahriman.py b/tests/ahriman/application/test_ahriman.py index ea87dd59..0b4153fd 100644 --- a/tests/ahriman/application/test_ahriman.py +++ b/tests/ahriman/application/test_ahriman.py @@ -26,6 +26,14 @@ def test_subparsers_check(parser: argparse.ArgumentParser) -> None: assert args.dry_run +def test_subparsers_clean(parser: argparse.ArgumentParser) -> None: + """ + clean command must imply unsafe + """ + args = parser.parse_args(["-a", "x86_64", "clean"]) + assert args.unsafe + + def test_subparsers_config(parser: argparse.ArgumentParser) -> None: """ config command must imply lock, no_report and unsafe @@ -36,6 +44,16 @@ def test_subparsers_config(parser: argparse.ArgumentParser) -> None: assert args.unsafe +def test_subparsers_setup(parser: argparse.ArgumentParser) -> None: + """ + setup command must imply lock, no_report and unsafe + """ + args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe "]) + assert args.lock is None + assert args.no_report + assert args.unsafe + + def test_subparsers_status(parser: argparse.ArgumentParser) -> None: """ status command must imply lock, no_report and unsafe diff --git a/tests/testresources/core/ahriman.ini b/tests/testresources/core/ahriman.ini index b918f520..e7faa097 100644 --- a/tests/testresources/core/ahriman.ini +++ b/tests/testresources/core/ahriman.ini @@ -1,4 +1,5 @@ [settings] +include = . logging = logging.ini [alpm]