diff --git a/package/etc/ahriman.ini.d/logging.ini b/package/etc/ahriman.ini.d/logging.ini index b4c9fa13..96c2f017 100644 --- a/package/etc/ahriman.ini.d/logging.ini +++ b/package/etc/ahriman.ini.d/logging.ini @@ -1,5 +1,5 @@ [loggers] -keys = root,builder,build_details,http +keys = root,builder,build_details,http,stderr [handlers] keys = console_handler,syslog_handler @@ -49,3 +49,8 @@ level = DEBUG handlers = syslog_handler qualname = http propagate = 0 + +[logger_stderr] +level = DEBUG +handlers = console_handler +qualname = stderr diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index d77e9846..8b3dfde0 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -67,105 +67,46 @@ def _parser() -> argparse.ArgumentParser: 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") + subparsers = parser.add_subparsers(title="command", help="command to run", dest="command", required=True) - _set_add_parser(subparsers) - _set_check_parser(subparsers) - _set_clean_parser(subparsers) - _set_config_parser(subparsers) - _set_init_parser(subparsers) + _set_aur_search_parser(subparsers) _set_key_import_parser(subparsers) + _set_package_add_parser(subparsers) + _set_package_remove_parser(subparsers) + _set_package_status_parser(subparsers) + _set_package_status_remove_parser(subparsers) + _set_package_status_update_parser(subparsers) _set_patch_add_parser(subparsers) _set_patch_list_parser(subparsers) _set_patch_remove_parser(subparsers) - _set_rebuild_parser(subparsers) - _set_remove_parser(subparsers) - _set_remove_unknown_parser(subparsers) - _set_report_parser(subparsers) - _set_search_parser(subparsers) - _set_setup_parser(subparsers) - _set_sign_parser(subparsers) - _set_status_parser(subparsers) - _set_status_update_parser(subparsers) - _set_sync_parser(subparsers) - _set_update_parser(subparsers) - _set_user_parser(subparsers) + _set_repo_check_parser(subparsers) + _set_repo_clean_parser(subparsers) + _set_repo_config_parser(subparsers) + _set_repo_init_parser(subparsers) + _set_repo_rebuild_parser(subparsers) + _set_repo_remove_unknown_parser(subparsers) + _set_repo_report_parser(subparsers) + _set_repo_setup_parser(subparsers) + _set_repo_sign_parser(subparsers) + _set_repo_sync_parser(subparsers) + _set_repo_update_parser(subparsers) + _set_user_add_parser(subparsers) + _set_user_remove_parser(subparsers) _set_web_parser(subparsers) return parser -def _set_add_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser: """ - add parser for add subcommand + add parser for AUR search subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("add", help="add package", description="add package", formatter_class=_formatter) - parser.add_argument("package", help="package base/name or archive path", nargs="+") - parser.add_argument("--now", help="run update function after", action="store_true") - parser.add_argument("--source", help="package source", choices=PackageSource, type=PackageSource, - default=PackageSource.Auto) - parser.add_argument("--without-dependencies", help="do not add dependencies", action="store_true") - parser.set_defaults(handler=handlers.Add) - return parser - - -def _set_check_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for check subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("check", help="check for updates", - description="check for updates. Same as update --dry-run --no-manual", - formatter_class=_formatter) - parser.add_argument("package", help="filter check by package base", nargs="*") - parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true") - parser.set_defaults(handler=handlers.Update, no_aur=False, no_manual=True, dry_run=True) - return parser - - -def _set_clean_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for clean subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("clean", help="clean local caches", description="clear local caches", - formatter_class=_formatter) - parser.add_argument("--no-build", help="do not clear directory with package sources", action="store_true") - parser.add_argument("--no-cache", help="do not clear directory with package caches", action="store_true") - parser.add_argument("--no-chroot", help="do not clear build chroot", action="store_true") - parser.add_argument("--no-manual", help="do not clear directory with manually added packages", action="store_true") - parser.add_argument("--no-packages", help="do not clear directory with built packages", action="store_true") - parser.set_defaults(handler=handlers.Clean, quiet=True, unsafe=True) - return parser - - -def _set_config_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for config subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("config", help="dump configuration", - description="dump configuration for specified architecture", - formatter_class=_formatter) - parser.set_defaults(handler=handlers.Dump, lock=None, quiet=True, no_report=True, unsafe=True) - return parser - - -def _set_init_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for init subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("init", help="create repository tree", - description="create empty repository tree. Optional command for auto architecture support", - formatter_class=_formatter) - parser.set_defaults(handler=handlers.Init, no_report=True) + parser = root.add_parser("aur-search", aliases=["search"], help="search for package", + description="search for package in AUR using API", formatter_class=_formatter) + parser.add_argument("search", help="search terms, can be specified multiple times", nargs="+") + parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, no_report=True, quiet=True, unsafe=True) return parser @@ -177,6 +118,10 @@ def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser: """ parser = root.add_parser("key-import", help="import PGP key", description="import PGP key from public sources to repository user", + epilog="By default ahriman runs build process with package sources validation " + "(in case if signature and keys are available in PKGBUILD). This process will " + "fail in case if key is not known for build user. This subcommand can be used " + "in order to import the PGP key to user keychain.", formatter_class=_formatter) parser.add_argument("--key-server", help="key server for key import", default="pgp.mit.edu") parser.add_argument("key", help="PGP key to import from public server") @@ -184,6 +129,91 @@ def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser: return parser +def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for package addition subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("package-add", aliases=["add"], help="add package", description="add package", + epilog="This subcommand should be used for new package addition. It also supports flag " + "--now in case if you would like to build the package immediately.", + formatter_class=_formatter) + parser.add_argument("package", help="package base/name or archive path", nargs="+") + parser.add_argument("-n", "--now", help="run update function after", action="store_true") + parser.add_argument("-s", "--source", help="package source", + type=PackageSource, choices=PackageSource, default=PackageSource.Auto) + parser.add_argument("--without-dependencies", help="do not add dependencies", action="store_true") + parser.set_defaults(handler=handlers.Add) + return parser + + +def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for package removal subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("package-remove", aliases=["remove"], help="remove package", description="remove package", + formatter_class=_formatter) + parser.add_argument("package", help="package name or base", nargs="+") + parser.set_defaults(handler=handlers.Remove) + return parser + + +def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for package status subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("package-status", aliases=["status"], help="get package status", + description="request status of the package", + epilog="This feature requests package status from the web interface if it is available.", + formatter_class=_formatter) + parser.add_argument("package", help="filter status by package base", nargs="*") + parser.add_argument("--ahriman", help="get service status itself", action="store_true") + parser.add_argument("-s", "--status", help="filter packages by status", + type=BuildStatusEnum, choices=BuildStatusEnum) + parser.set_defaults(handler=handlers.Status, lock=None, no_report=True, quiet=True, unsafe=True) + return parser + + +def _set_package_status_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for package status remove subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("package-status-remove", help="remove package status", + description="remove the package from the status page", + epilog="Please note that this subcommand does not remove the package itself, it just " + "clears the status page.", + formatter_class=_formatter) + parser.add_argument("package", help="remove specified packages", nargs="+") + parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Remove, lock=None, no_report=True, quiet=True, + unsafe=True) + return parser + + +def _set_package_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for package status update subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("package-status-update", aliases=["status-update"], help="update package status", + description="update package status on the status page", formatter_class=_formatter) + parser.add_argument("package", help="set status for specified packages. " + "If no packages supplied, service status will be updated", + nargs="*") + parser.add_argument("-s", "--status", help="new status", + type=BuildStatusEnum, choices=BuildStatusEnum, default=BuildStatusEnum.Success) + parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, no_report=True, quiet=True, + unsafe=True) + return parser + + def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for new patch subcommand @@ -230,38 +260,88 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: return parser -def _set_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser: """ - add parser for rebuild subcommand + add parser for repository check subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("rebuild", help="rebuild repository", description="rebuild whole repository", + parser = root.add_parser("repo-check", aliases=["check"], help="check for updates", + description="check for updates. Same as update --dry-run --no-manual", formatter_class=_formatter) + parser.add_argument("package", help="filter check by package base", nargs="*") + parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true") + parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_manual=True) + return parser + + +def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for repository clean subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("repo-clean", aliases=["clean"], help="clean local caches", + description="clear local caches", + epilog="The subcommand clears every temporary directories (builds, caches etc). Normally " + "you should not run this command manually. Also in case if you are going to clear " + "the chroot directories you will need root privileges.", + formatter_class=_formatter) + parser.add_argument("--no-build", help="do not clear directory with package sources", action="store_true") + parser.add_argument("--no-cache", help="do not clear directory with package caches", action="store_true") + parser.add_argument("--no-chroot", help="do not clear build chroot", action="store_true") + parser.add_argument("--no-manual", help="do not clear directory with manually added packages", action="store_true") + parser.add_argument("--no-packages", help="do not clear directory with built packages", action="store_true") + parser.set_defaults(handler=handlers.Clean, quiet=True, unsafe=True) + return parser + + +def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for config subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("repo-config", aliases=["config"], help="dump configuration", + description="dump configuration for specified architecture", + formatter_class=_formatter) + parser.set_defaults(handler=handlers.Dump, lock=None, no_report=True, quiet=True, unsafe=True) + return parser + + +def _set_repo_init_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for repository init subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("repo-init", aliases=["init"], help="create repository tree", + description="create empty repository tree. Optional command for auto architecture support", + formatter_class=_formatter) + parser.set_defaults(handler=handlers.Init, no_report=True) + return parser + + +def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for repository rebuild subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository", + description="rebuild whole repository", formatter_class=_formatter) parser.add_argument("--depends-on", help="only rebuild packages that depend on specified package", action="append") parser.set_defaults(handler=handlers.Rebuild) return parser -def _set_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for remove subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("remove", help="remove package", description="remove package", formatter_class=_formatter) - parser.add_argument("package", help="package name or base", nargs="+") - parser.set_defaults(handler=handlers.Remove) - return parser - - -def _set_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for remove unknown packages subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("remove-unknown", help="remove unknown packages", + parser = root.add_parser("repo-remove-unknown", aliases=["remove-unknown"], help="remove unknown packages", description="remove packages which are missing in AUR", formatter_class=_formatter) parser.add_argument("--dry-run", help="just perform check for packages without removal", action="store_true") @@ -269,39 +349,29 @@ def _set_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser return parser -def _set_report_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for report subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("report", help="generate report", description="generate report", + parser = root.add_parser("repo-report", aliases=["report"], help="generate report", description="generate report", + epilog="Create and/or update repository report as configured.", formatter_class=_formatter) parser.add_argument("target", help="target to generate report", nargs="*") parser.set_defaults(handler=handlers.Report) return parser -def _set_search_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for search subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("search", help="search for package", description="search for package in AUR using API") - parser.add_argument("search", help="search terms, can be specified multiple times", nargs="+") - parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, quiet=True, no_report=True, unsafe=True) - return parser - - -def _set_setup_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for setup subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("setup", help="initial service configuration", + parser = root.add_parser("repo-setup", aliases=["setup"], help="initial service configuration", description="create initial service configuration, requires root", + epilog="Create _minimal_ configuration for the service according to provided options.", formatter_class=_formatter) parser.add_argument("--build-command", help="build command prefix", default="ahriman") parser.add_argument("--from-configuration", help="path to default devtools pacman configuration", @@ -310,80 +380,51 @@ def _set_setup_parser(root: SubParserAction) -> argparse.ArgumentParser: parser.add_argument("--packager", help="packager name and email", required=True) parser.add_argument("--repository", help="repository name", required=True) parser.add_argument("--sign-key", help="sign key id") - parser.add_argument("--sign-target", help="sign options", type=SignSettings.from_option, - choices=SignSettings, action="append") + parser.add_argument("--sign-target", help="sign options", action="append", + type=SignSettings.from_option, choices=SignSettings) parser.add_argument("--web-port", help="port of the web service", type=int) - parser.set_defaults(handler=handlers.Setup, lock=None, quiet=True, no_report=True, unsafe=True) + parser.set_defaults(handler=handlers.Setup, lock=None, no_report=True, quiet=True, unsafe=True) return parser -def _set_sign_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for sign subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("sign", help="sign packages", description="(re-)sign packages and repository database", + parser = root.add_parser("repo-sign", aliases=["sign"], help="sign packages", + description="(re-)sign packages and repository database", + epilog="Sign repository and/or packages as configured.", formatter_class=_formatter) parser.add_argument("package", help="sign only specified packages", nargs="*") parser.set_defaults(handler=handlers.Sign) return parser -def _set_status_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser: """ - add parser for status subcommand + add parser for repository sync subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("status", help="get package status", description="request status of the package", - formatter_class=_formatter) - parser.add_argument("--ahriman", help="get service status itself", action="store_true") - parser.add_argument("--status", help="filter packages by status", choices=BuildStatusEnum, type=BuildStatusEnum) - parser.add_argument("package", help="filter status by package base", nargs="*") - parser.set_defaults(handler=handlers.Status, lock=None, quiet=True, no_report=True, unsafe=True) - return parser - - -def _set_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for status update subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("status-update", help="update package status", description="request status of the package", - formatter_class=_formatter) - parser.add_argument( - "package", - help="set status for specified packages. If no packages supplied, service status will be updated", - nargs="*") - parser.add_argument("--status", help="new status", choices=BuildStatusEnum, - type=BuildStatusEnum, default=BuildStatusEnum.Success) - parser.add_argument("--remove", help="remove package status page", action="store_true") - parser.set_defaults(handler=handlers.StatusUpdate, lock=None, quiet=True, no_report=True, unsafe=True) - return parser - - -def _set_sync_parser(root: SubParserAction) -> argparse.ArgumentParser: - """ - add parser for sync subcommand - :param root: subparsers for the commands - :return: created argument parser - """ - parser = root.add_parser("sync", help="sync repository", description="sync packages to remote server", + parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository", + description="sync packages to remote server", + epilog="Synchronize the repository to remote services as configured.", formatter_class=_formatter) parser.add_argument("target", help="target to sync", nargs="*") parser.set_defaults(handler=handlers.Sync) return parser -def _set_update_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser: """ - add parser for update subcommand + add parser for repository update subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("update", help="update packages", description="run updates", formatter_class=_formatter) + parser = root.add_parser("repo-update", aliases=["update"], help="update packages", description="run updates", + formatter_class=_formatter) parser.add_argument("package", help="filter check by package base", nargs="*") parser.add_argument("--dry-run", help="just perform check for updates, same as check command", action="store_true") parser.add_argument("--no-aur", help="do not check for AUR updates. Implies --no-vcs", action="store_true") @@ -393,31 +434,43 @@ def _set_update_parser(root: SubParserAction) -> argparse.ArgumentParser: return parser -def _set_user_parser(root: SubParserAction) -> argparse.ArgumentParser: +def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for create user subcommand :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser( - "user", - help="manage users for web services", - description="manage users for web services with password and role. In case if password was not entered it will be asked interactively", - formatter_class=_formatter) + parser = root.add_parser("user-add", help="create or update user for web services", + description="update user for web services with the given password and role. " + "In case if password was not entered it will be asked interactively", + formatter_class=_formatter) parser.add_argument("username", help="username for web service") parser.add_argument("--as-service", help="add user as service user", action="store_true") - parser.add_argument( - "-a", - "--access", - help="user access level", - type=UserAccess, - choices=UserAccess, - default=UserAccess.Read) parser.add_argument("--no-reload", help="do not reload authentication module", action="store_true") - parser.add_argument("-p", "--password", help="user password") - parser.add_argument("-r", "--remove", help="remove user from configuration", action="store_true") - parser.add_argument("--secure", help="set file permissions to user-only", action="store_true") - parser.set_defaults(handler=handlers.User, architecture=[""], lock=None, quiet=True, no_report=True, unsafe=True) + parser.add_argument("-p", "--password", help="user password. Blank password will be treated as empty password, " + "which is in particular must be used for OAuth2 authorization type.") + parser.add_argument("-r", "--role", help="user access level", + type=UserAccess, choices=UserAccess, default=UserAccess.Read) + parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true") + parser.set_defaults(handler=handlers.User, action=Action.Update, architecture=[""], lock=None, no_report=True, + quiet=True, unsafe=True) + return parser + + +def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for user removal subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("user-remove", help="remove user for web services", + description="remove user from the user mapping and write the configuration", + formatter_class=_formatter) + parser.add_argument("username", help="username for web service") + parser.add_argument("--no-reload", help="do not reload authentication module", action="store_true") + parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true") + parser.set_defaults(handler=handlers.User, action=Action.Remove, architecture=[""], lock=None, no_report=True, # nosec + password="", quiet=True, role=UserAccess.Read, unsafe=True) return parser @@ -427,7 +480,7 @@ def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser: :param root: subparsers for the commands :return: created argument parser """ - parser = root.add_parser("web", help="start web server", description="start web server", formatter_class=_formatter) + parser = root.add_parser("web", help="web server", description="start web server", formatter_class=_formatter) parser.set_defaults(handler=handlers.Web, lock=None, no_report=True, parser=_parser) return parser diff --git a/src/ahriman/application/handlers/handler.py b/src/ahriman/application/handlers/handler.py index d9f80cc6..6a38e87f 100644 --- a/src/ahriman/application/handlers/handler.py +++ b/src/ahriman/application/handlers/handler.py @@ -55,7 +55,8 @@ class Handler: cls.run(args, architecture, configuration, args.no_report) return True except Exception: - logging.getLogger("root").exception("process exception") + # we are basically always want to print error to stderr instead of default logger + logging.getLogger("stderr").exception("process exception") return False @classmethod diff --git a/src/ahriman/application/handlers/status_update.py b/src/ahriman/application/handlers/status_update.py index 499a544d..a9e9e4af 100644 --- a/src/ahriman/application/handlers/status_update.py +++ b/src/ahriman/application/handlers/status_update.py @@ -19,12 +19,12 @@ # import argparse -from typing import Callable, Type +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.core.exceptions import InvalidCommand +from ahriman.models.action import Action class StatusUpdate(Handler): @@ -46,13 +46,14 @@ class StatusUpdate(Handler): """ # we are using reporter here client = Application(architecture, configuration, no_report=False).repository.reporter - callback: Callable[[str], None] = lambda p: client.remove(p) if args.remove else client.update(p, args.status) - if args.package: + + if args.action == Action.Update and args.package: # update packages statuses for package in args.package: - callback(package) - elif args.remove: - raise InvalidCommand("Remove option is supplied, but no packages set") - else: + client.update(package, args.status) + elif args.action == Action.Update: # update service status client.update_self(args.status) + elif args.action == Action.Remove: + for package in args.package: + client.remove(package) diff --git a/src/ahriman/application/handlers/user.py b/src/ahriman/application/handlers/user.py index c5958637..97246de6 100644 --- a/src/ahriman/application/handlers/user.py +++ b/src/ahriman/application/handlers/user.py @@ -26,6 +26,7 @@ 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.action import Action from ahriman.models.user import User as MUser from ahriman.models.user_access import UserAccess @@ -52,7 +53,7 @@ class User(Handler): auth_configuration = User.get_auth_configuration(configuration.include) User.clear_user(auth_configuration, user) - if not args.remove: + if args.action == Action.Update: User.create_configuration(auth_configuration, user, salt, args.as_service) User.write_configuration(auth_configuration, args.secure) @@ -97,7 +98,7 @@ class User(Handler): :param args: command line args :return: built user descriptor """ - user = MUser(args.username, args.password, args.access) + user = MUser(args.username, args.password, args.role) if user.password is None: user.password = getpass.getpass() return user diff --git a/src/ahriman/core/configuration.py b/src/ahriman/core/configuration.py index 24e78b95..4f4d7074 100644 --- a/src/ahriman/core/configuration.py +++ b/src/ahriman/core/configuration.py @@ -150,10 +150,10 @@ class Configuration(configparser.RawConfigParser): try: path = self.logging_path fileConfig(path) - except (FileNotFoundError, PermissionError): + except Exception: logging.basicConfig(filename=None, format=self.DEFAULT_LOG_FORMAT, level=self.DEFAULT_LOG_LEVEL) - logging.exception("could not create logfile, fallback to stderr") + logging.exception("could not load logging from configuration, fallback to stderr") if quiet: logging.disable() diff --git a/src/ahriman/core/exceptions.py b/src/ahriman/core/exceptions.py index 762da9f6..8bd982a4 100644 --- a/src/ahriman/core/exceptions.py +++ b/src/ahriman/core/exceptions.py @@ -71,19 +71,6 @@ class InitializeException(RuntimeError): RuntimeError.__init__(self, f"Could not load service: {details}") -class InvalidCommand(ValueError): - """ - exception raised on invalid command line options - """ - - def __init__(self, details: Any) -> None: - """ - default constructor - :param details" error details - """ - ValueError.__init__(self, details) - - class InvalidOption(ValueError): """ exception which will be raised on configuration errors diff --git a/src/ahriman/models/auth_settings.py b/src/ahriman/models/auth_settings.py index 93b901af..e927fff8 100644 --- a/src/ahriman/models/auth_settings.py +++ b/src/ahriman/models/auth_settings.py @@ -19,7 +19,7 @@ # from __future__ import annotations -from enum import Enum, auto +from enum import Enum from typing import Type from ahriman.core.exceptions import InvalidOption @@ -33,9 +33,9 @@ class AuthSettings(Enum): :cvar OAuth: OAuth based provider """ - Disabled = auto() - Configuration = auto() - OAuth = auto() + Disabled = "disabled" + Configuration = "configuration" + OAuth = "oauth2" @classmethod def from_option(cls: Type[AuthSettings], value: str) -> AuthSettings: diff --git a/src/ahriman/models/report_settings.py b/src/ahriman/models/report_settings.py index 4c0cfa8e..c9217876 100644 --- a/src/ahriman/models/report_settings.py +++ b/src/ahriman/models/report_settings.py @@ -19,7 +19,7 @@ # from __future__ import annotations -from enum import Enum, auto +from enum import Enum from typing import Type from ahriman.core.exceptions import InvalidOption @@ -33,9 +33,9 @@ class ReportSettings(Enum): :cvar Email: email report generation """ - Disabled = auto() # for testing purpose - HTML = auto() - Email = auto() + Disabled = "disabled" # for testing purpose + HTML = "html" + Email = "email" @classmethod def from_option(cls: Type[ReportSettings], value: str) -> ReportSettings: diff --git a/src/ahriman/models/sign_settings.py b/src/ahriman/models/sign_settings.py index 0744ceea..c087e967 100644 --- a/src/ahriman/models/sign_settings.py +++ b/src/ahriman/models/sign_settings.py @@ -19,7 +19,7 @@ # from __future__ import annotations -from enum import Enum, auto +from enum import Enum from typing import Type from ahriman.core.exceptions import InvalidOption @@ -32,8 +32,8 @@ class SignSettings(Enum): :cvar Repository: sign repository database file """ - Packages = auto() - Repository = auto() + Packages = "pacakges" + Repository = "repository" @classmethod def from_option(cls: Type[SignSettings], value: str) -> SignSettings: diff --git a/src/ahriman/models/smtp_ssl_settings.py b/src/ahriman/models/smtp_ssl_settings.py index 473a9297..86ba08b8 100644 --- a/src/ahriman/models/smtp_ssl_settings.py +++ b/src/ahriman/models/smtp_ssl_settings.py @@ -19,7 +19,7 @@ # from __future__ import annotations -from enum import Enum, auto +from enum import Enum from typing import Type @@ -31,9 +31,9 @@ class SmtpSSLSettings(Enum): :cvar STARTTLS: use STARTTLS in normal SMTP client """ - Disabled = auto() - SSL = auto() - STARTTLS = auto() + Disabled = "disabled" + SSL = "ssl" + STARTTLS = "starttls" @classmethod def from_option(cls: Type[SmtpSSLSettings], value: str) -> SmtpSSLSettings: diff --git a/src/ahriman/models/upload_settings.py b/src/ahriman/models/upload_settings.py index dc1c6c1c..e866411d 100644 --- a/src/ahriman/models/upload_settings.py +++ b/src/ahriman/models/upload_settings.py @@ -19,7 +19,7 @@ # from __future__ import annotations -from enum import Enum, auto +from enum import Enum from typing import Type from ahriman.core.exceptions import InvalidOption @@ -33,9 +33,9 @@ class UploadSettings(Enum): :cvar S3: sync to Amazon S3 """ - Disabled = auto() # for testing purpose - Rsync = auto() - S3 = auto() + Disabled = "disabled" # for testing purpose + Rsync = "rsync" + S3 = "s3" @classmethod def from_option(cls: Type[UploadSettings], value: str) -> UploadSettings: diff --git a/tests/ahriman/application/handlers/test_handler_status_update.py b/tests/ahriman/application/handlers/test_handler_status_update.py index 1a5a30d8..04593abd 100644 --- a/tests/ahriman/application/handlers/test_handler_status_update.py +++ b/tests/ahriman/application/handlers/test_handler_status_update.py @@ -1,11 +1,10 @@ import argparse -import pytest from pytest_mock import MockerFixture from ahriman.application.handlers import StatusUpdate from ahriman.core.configuration import Configuration -from ahriman.core.exceptions import InvalidCommand +from ahriman.models.action import Action from ahriman.models.build_status import BuildStatusEnum from ahriman.models.package import Package @@ -16,9 +15,9 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace: :param args: command line arguments fixture :return: generated arguments for these test cases """ - args.status = BuildStatusEnum.Success args.package = None - args.remove = False + args.action = Action.Update + args.status = BuildStatusEnum.Success return args @@ -55,7 +54,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, pack """ args = _default_args(args) args.package = [package_ahriman.base] - args.remove = True + args.action = Action.Remove mocker.patch("pathlib.Path.mkdir") update_mock = mocker.patch("ahriman.core.status.client.Client.remove") @@ -63,19 +62,6 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, pack update_mock.assert_called_once() -def test_run_remove_without_packages(args: argparse.Namespace, configuration: Configuration, - mocker: MockerFixture) -> None: - """ - must raise exception when no packages set and remove called - """ - args = _default_args(args) - args.remove = True - mocker.patch("pathlib.Path.mkdir") - - with pytest.raises(InvalidCommand): - StatusUpdate.run(args, "x86_64", configuration, True) - - def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ must create application object with native reporting diff --git a/tests/ahriman/application/handlers/test_handler_user.py b/tests/ahriman/application/handlers/test_handler_user.py index 3d2e5b3f..1c67c2aa 100644 --- a/tests/ahriman/application/handlers/test_handler_user.py +++ b/tests/ahriman/application/handlers/test_handler_user.py @@ -7,6 +7,7 @@ from unittest import mock from ahriman.application.handlers import User from ahriman.core.configuration import Configuration +from ahriman.models.action import Action from ahriman.models.user import User as MUser from ahriman.models.user_access import UserAccess @@ -18,12 +19,12 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace: :return: generated arguments for these test cases """ args.username = "user" - args.password = "pa55w0rd" - args.access = UserAccess.Read + args.action = Action.Update args.as_service = False args.no_reload = False + args.password = "pa55w0rd" + args.role = UserAccess.Read args.secure = False - args.remove = False return args @@ -54,7 +55,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, mock must remove user if remove flag supplied """ args = _default_args(args) - args.remove = True + args.action = Action.Remove mocker.patch("pathlib.Path.mkdir") get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.User.get_auth_configuration") create_configuration_mock = mocker.patch("ahriman.application.handlers.User.create_configuration") diff --git a/tests/ahriman/application/test_ahriman.py b/tests/ahriman/application/test_ahriman.py index b8807551..8ffbd5a0 100644 --- a/tests/ahriman/application/test_ahriman.py +++ b/tests/ahriman/application/test_ahriman.py @@ -14,16 +14,16 @@ def test_parser(parser: argparse.ArgumentParser) -> None: """ must parse valid command line """ - parser.parse_args(["-a", "x86_64", "config"]) + parser.parse_args(["-a", "x86_64", "repo-config"]) def test_parser_option_configuration(parser: argparse.ArgumentParser) -> None: """ must convert configuration option to Path instance """ - args = parser.parse_args(["-a", "x86_64", "config"]) + args = parser.parse_args(["-a", "x86_64", "repo-config"]) assert isinstance(args.configuration, Path) - args = parser.parse_args(["-a", "x86_64", "-c", "ahriman.ini", "config"]) + args = parser.parse_args(["-a", "x86_64", "-c", "ahriman.ini", "repo-config"]) assert isinstance(args.configuration, Path) @@ -31,9 +31,9 @@ def test_parser_option_lock(parser: argparse.ArgumentParser) -> None: """ must convert lock option to Path instance """ - args = parser.parse_args(["update"]) + args = parser.parse_args(["repo-update"]) assert isinstance(args.lock, Path) - args = parser.parse_args(["-l", "ahriman.lock", "update"]) + args = parser.parse_args(["-l", "ahriman.lock", "repo-update"]) assert isinstance(args.lock, Path) @@ -41,78 +41,28 @@ def test_multiple_architectures(parser: argparse.ArgumentParser) -> None: """ must accept multiple architectures """ - args = parser.parse_args(["-a", "x86_64", "-a", "i686", "config"]) + args = parser.parse_args(["-a", "x86_64", "-a", "i686", "repo-config"]) assert args.architecture == ["x86_64", "i686"] -def test_subparsers_add_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_aur_search(parser: argparse.ArgumentParser) -> None: """ - add command must correctly parse architecture list + aur-search command must imply architecture list, lock, no-report, quiet and unsafe """ - args = parser.parse_args(["add", "ahriman"]) - assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "add", "ahriman"]) - assert args.architecture == ["x86_64"] - - -def test_subparsers_check(parser: argparse.ArgumentParser) -> None: - """ - check command must imply no-aur, no-manual and dry-run - """ - args = parser.parse_args(["check"]) - assert not args.no_aur - assert args.no_manual - assert args.dry_run - - -def test_subparsers_check_architecture(parser: argparse.ArgumentParser) -> None: - """ - check command must correctly parse architecture list - """ - args = parser.parse_args(["check"]) - assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "check"]) - assert args.architecture == ["x86_64"] - - -def test_subparsers_clean(parser: argparse.ArgumentParser) -> None: - """ - clean command must imply unsafe and no-log - """ - args = parser.parse_args(["clean"]) - assert args.quiet - assert args.unsafe - - -def test_subparsers_clean_architecture(parser: argparse.ArgumentParser) -> None: - """ - clean command must correctly parse architecture list - """ - args = parser.parse_args(["clean"]) - assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "clean"]) - assert args.architecture == ["x86_64"] - - -def test_subparsers_config(parser: argparse.ArgumentParser) -> None: - """ - config command must imply lock, no-log, no-report and unsafe - """ - args = parser.parse_args(["-a", "x86_64", "config"]) - assert args.architecture == ["x86_64"] + args = parser.parse_args(["aur-search", "ahriman"]) + assert args.architecture == [""] assert args.lock is None - assert args.quiet assert args.no_report + assert args.quiet assert args.unsafe -def test_subparsers_init(parser: argparse.ArgumentParser) -> None: +def test_subparsers_aur_search_architecture(parser: argparse.ArgumentParser) -> None: """ - init command must imply no_report + aur-search command must correctly parse architecture list """ - args = parser.parse_args(["-a", "x86_64", "init"]) - assert args.architecture == ["x86_64"] - assert args.no_report + args = parser.parse_args(["-a", "x86_64", "aur-search", "ahriman"]) + assert args.architecture == [""] def test_subparsers_key_import(parser: argparse.ArgumentParser) -> None: @@ -133,6 +83,74 @@ def test_subparsers_key_import_architecture(parser: argparse.ArgumentParser) -> assert args.architecture == [""] +def test_subparsers_package_add_architecture(parser: argparse.ArgumentParser) -> None: + """ + package-add command must correctly parse architecture list + """ + args = parser.parse_args(["package-add", "ahriman"]) + assert args.architecture is None + args = parser.parse_args(["-a", "x86_64", "package-add", "ahriman"]) + assert args.architecture == ["x86_64"] + + +def test_subparsers_package_remove_architecture(parser: argparse.ArgumentParser) -> None: + """ + package-remove command must correctly parse architecture list + """ + args = parser.parse_args(["package-remove", "ahriman"]) + assert args.architecture is None + args = parser.parse_args(["-a", "x86_64", "package-remove", "ahriman"]) + assert args.architecture == ["x86_64"] + + +def test_subparsers_package_status(parser: argparse.ArgumentParser) -> None: + """ + package-status command must imply lock, no-report, quiet and unsafe + """ + args = parser.parse_args(["-a", "x86_64", "package-status"]) + assert args.architecture == ["x86_64"] + assert args.lock is None + assert args.no_report + assert args.quiet + assert args.unsafe + + +def test_subparsers_package_status_remove(parser: argparse.ArgumentParser) -> None: + """ + package-status-remove command must imply action, lock, no-report, quiet and unsafe + """ + args = parser.parse_args(["-a", "x86_64", "package-status-remove", "ahriman"]) + assert args.architecture == ["x86_64"] + assert args.action == Action.Remove + assert args.lock is None + assert args.no_report + assert args.quiet + assert args.unsafe + + +def test_subparsers_package_status_update(parser: argparse.ArgumentParser) -> None: + """ + package-status-update command must imply action, lock, no-report, quiet and unsafe + """ + args = parser.parse_args(["-a", "x86_64", "package-status-update"]) + assert args.architecture == ["x86_64"] + assert args.action == Action.Update + assert args.lock is None + assert args.no_report + assert args.quiet + assert args.unsafe + + +def test_subparsers_package_status_update_option_status(parser: argparse.ArgumentParser) -> None: + """ + package-status-update command must convert status option to buildstatusenum instance + """ + args = parser.parse_args(["-a", "x86_64", "package-status-update"]) + assert isinstance(args.status, BuildStatusEnum) + args = parser.parse_args(["-a", "x86_64", "package-status-update", "--status", "failed"]) + assert isinstance(args.status, BuildStatusEnum) + + def test_subparsers_patch_add(parser: argparse.ArgumentParser) -> None: """ patch-add command must imply action, architecture list, lock and no-report @@ -198,183 +216,213 @@ def test_subparsers_patch_remove_architecture(parser: argparse.ArgumentParser) - assert args.architecture == [""] -def test_subparsers_rebuild_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_check(parser: argparse.ArgumentParser) -> None: """ - rebuild command must correctly parse architecture list + repo-check command must imply dry-run, no-aur and no-manual """ - args = parser.parse_args(["rebuild"]) + args = parser.parse_args(["repo-check"]) + assert args.dry_run + assert not args.no_aur + assert args.no_manual + + +def test_subparsers_repo_check_architecture(parser: argparse.ArgumentParser) -> None: + """ + repo-check command must correctly parse architecture list + """ + args = parser.parse_args(["repo-check"]) assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "rebuild"]) + args = parser.parse_args(["-a", "x86_64", "repo-check"]) assert args.architecture == ["x86_64"] -def test_subparsers_remove_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_clean(parser: argparse.ArgumentParser) -> None: """ - remove command must correctly parse architecture list + repo-clean command must imply quiet and unsafe """ - args = parser.parse_args(["remove", "ahriman"]) - assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "remove", "ahriman"]) - assert args.architecture == ["x86_64"] - - -def test_subparsers_report_architecture(parser: argparse.ArgumentParser) -> None: - """ - report command must correctly parse architecture list - """ - args = parser.parse_args(["report"]) - assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "report"]) - assert args.architecture == ["x86_64"] - - -def test_subparsers_search(parser: argparse.ArgumentParser) -> None: - """ - search command must imply architecture list, lock, no-log, no-report and unsafe - """ - args = parser.parse_args(["search", "ahriman"]) - assert args.architecture == [""] - assert args.lock is None + args = parser.parse_args(["repo-clean"]) assert args.quiet - assert args.no_report assert args.unsafe -def test_subparsers_search_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_clean_architecture(parser: argparse.ArgumentParser) -> None: """ - search command must correctly parse architecture list + repo-clean command must correctly parse architecture list """ - args = parser.parse_args(["-a", "x86_64", "search", "ahriman"]) - assert args.architecture == [""] + args = parser.parse_args(["repo-clean"]) + assert args.architecture is None + args = parser.parse_args(["-a", "x86_64", "repo-clean"]) + assert args.architecture == ["x86_64"] -def test_subparsers_setup(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_config(parser: argparse.ArgumentParser) -> None: """ - setup command must imply lock, no-log, no-report and unsafe + repo-config command must imply lock, no-report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "repo-config"]) + assert args.architecture == ["x86_64"] + assert args.lock is None + assert args.no_report + assert args.quiet + assert args.unsafe + + +def test_subparsers_repo_init(parser: argparse.ArgumentParser) -> None: + """ + repo-init command must imply no_report + """ + args = parser.parse_args(["-a", "x86_64", "repo-init"]) + assert args.architecture == ["x86_64"] + assert args.no_report + + +def test_subparsers_repo_rebuild_architecture(parser: argparse.ArgumentParser) -> None: + """ + repo-rebuild command must correctly parse architecture list + """ + args = parser.parse_args(["repo-rebuild"]) + assert args.architecture is None + args = parser.parse_args(["-a", "x86_64", "repo-rebuild"]) + assert args.architecture == ["x86_64"] + + +def test_subparsers_repo_remove_unknown_architecture(parser: argparse.ArgumentParser) -> None: + """ + repo-remove-unknown command must correctly parse architecture list + """ + args = parser.parse_args(["repo-remove-unknown"]) + assert args.architecture is None + args = parser.parse_args(["-a", "x86_64", "repo-remove-unknown"]) + assert args.architecture == ["x86_64"] + + +def test_subparsers_repo_report_architecture(parser: argparse.ArgumentParser) -> None: + """ + repo-report command must correctly parse architecture list + """ + args = parser.parse_args(["repo-report"]) + assert args.architecture is None + args = parser.parse_args(["-a", "x86_64", "repo-report"]) + assert args.architecture == ["x86_64"] + + +def test_subparsers_repo_setup(parser: argparse.ArgumentParser) -> None: + """ + repo-setup command must imply lock, no-report, quiet and unsafe + """ + args = parser.parse_args(["-a", "x86_64", "repo-setup", "--packager", "John Doe ", "--repository", "aur-clone"]) assert args.architecture == ["x86_64"] assert args.lock is None - assert args.quiet assert args.no_report + assert args.quiet assert args.unsafe -def test_subparsers_setup_option_from_configuration(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_setup_option_from_configuration(parser: argparse.ArgumentParser) -> None: """ - setup command must convert from-configuration option to path instance + repo-setup command must convert from-configuration option to path instance """ - args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "repo-setup", "--packager", "John Doe ", "--repository", "aur-clone"]) assert isinstance(args.from_configuration, Path) - args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "repo-setup", "--packager", "John Doe ", "--repository", "aur-clone", "--from-configuration", "path"]) assert isinstance(args.from_configuration, Path) -def test_subparsers_setup_option_sign_target(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_setup_option_sign_target(parser: argparse.ArgumentParser) -> None: """ - setup command must convert sign-target option to signsettings instance + repo-setup command must convert sign-target option to signsettings instance """ - args = parser.parse_args(["-a", "x86_64", "setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "repo-setup", "--packager", "John Doe ", "--repository", "aur-clone", "--sign-target", "packages"]) assert args.sign_target assert all(isinstance(target, SignSettings) for target in args.sign_target) -def test_subparsers_sign_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_sign_architecture(parser: argparse.ArgumentParser) -> None: """ - sign command must correctly parse architecture list + repo-sign command must correctly parse architecture list """ - args = parser.parse_args(["sign"]) + args = parser.parse_args(["repo-sign"]) assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "sign"]) + args = parser.parse_args(["-a", "x86_64", "repo-sign"]) assert args.architecture == ["x86_64"] -def test_subparsers_status(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_sync_architecture(parser: argparse.ArgumentParser) -> None: """ - status command must imply lock, no-log, no-report and unsafe + repo-sync command must correctly parse architecture list """ - args = parser.parse_args(["-a", "x86_64", "status"]) - assert args.architecture == ["x86_64"] - assert args.lock is None - assert args.quiet - assert args.no_report - assert args.unsafe - - -def test_subparsers_status_update(parser: argparse.ArgumentParser) -> None: - """ - status-update command must imply lock, no-log, no-report and unsafe - """ - args = parser.parse_args(["-a", "x86_64", "status-update"]) - assert args.architecture == ["x86_64"] - assert args.lock is None - assert args.quiet - assert args.no_report - assert args.unsafe - - -def test_subparsers_status_update_option_status(parser: argparse.ArgumentParser) -> None: - """ - status-update command must convert status option to buildstatusenum instance - """ - args = parser.parse_args(["-a", "x86_64", "status-update"]) - assert isinstance(args.status, BuildStatusEnum) - args = parser.parse_args(["-a", "x86_64", "status-update", "--status", "failed"]) - assert isinstance(args.status, BuildStatusEnum) - - -def test_subparsers_sync_architecture(parser: argparse.ArgumentParser) -> None: - """ - sync command must correctly parse architecture list - """ - args = parser.parse_args(["sync"]) + args = parser.parse_args(["repo-sync"]) assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "sync"]) + args = parser.parse_args(["-a", "x86_64", "repo-sync"]) assert args.architecture == ["x86_64"] -def test_subparsers_update_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_repo_update_architecture(parser: argparse.ArgumentParser) -> None: """ - update command must correctly parse architecture list + repo-update command must correctly parse architecture list """ - args = parser.parse_args(["update"]) + args = parser.parse_args(["repo-update"]) assert args.architecture is None - args = parser.parse_args(["-a", "x86_64", "update"]) + args = parser.parse_args(["-a", "x86_64", "repo-update"]) assert args.architecture == ["x86_64"] -def test_subparsers_user(parser: argparse.ArgumentParser) -> None: +def test_subparsers_user_add(parser: argparse.ArgumentParser) -> None: """ - user command must imply architecture, lock, no-log, no-report and unsafe + user-add command must imply action, architecture, lock, no-report, quiet and unsafe """ - args = parser.parse_args(["user", "username"]) + args = parser.parse_args(["user-add", "username"]) + assert args.action == Action.Update assert args.architecture == [""] assert args.lock is None - assert args.quiet assert args.no_report + assert args.quiet assert args.unsafe -def test_subparsers_user_architecture(parser: argparse.ArgumentParser) -> None: +def test_subparsers_user_add_architecture(parser: argparse.ArgumentParser) -> None: """ - user command must correctly parse architecture list + user-add command must correctly parse architecture list """ - args = parser.parse_args(["-a", "x86_64", "user", "username"]) + args = parser.parse_args(["-a", "x86_64", "user-add", "username"]) assert args.architecture == [""] -def test_subparsers_user_option_role(parser: argparse.ArgumentParser) -> None: +def test_subparsers_user_add_option_role(parser: argparse.ArgumentParser) -> None: """ - user command must convert role option to useraccess instance + user-add command must convert role option to useraccess instance """ - args = parser.parse_args(["user", "username"]) - assert isinstance(args.access, UserAccess) - args = parser.parse_args(["user", "username", "--access", "write"]) - assert isinstance(args.access, UserAccess) + args = parser.parse_args(["user-add", "username"]) + assert isinstance(args.role, UserAccess) + args = parser.parse_args(["user-add", "username", "--role", "write"]) + assert isinstance(args.role, UserAccess) + + +def test_subparsers_user_remove(parser: argparse.ArgumentParser) -> None: + """ + user-remove command must imply action, architecture, lock, no-report, password, quiet, role and unsafe + """ + args = parser.parse_args(["user-remove", "username"]) + assert args.action == Action.Remove + assert args.architecture == [""] + assert args.lock is None + assert args.no_report + assert args.password is not None + assert args.quiet + assert args.role is not None + assert args.unsafe + + +def test_subparsers_user_remove_architecture(parser: argparse.ArgumentParser) -> None: + """ + user-remove command must correctly parse architecture list + """ + args = parser.parse_args(["-a", "x86_64", "user-remove", "username"]) + assert args.architecture == [""] def test_subparsers_web(parser: argparse.ArgumentParser) -> None: