diff --git a/package/share/bash-completion/completions/_ahriman b/package/share/bash-completion/completions/_ahriman index 2c9225a5..e7de6870 100644 --- a/package/share/bash-completion/completions/_ahriman +++ b/package/share/bash-completion/completions/_ahriman @@ -31,8 +31,8 @@ _shtab_ahriman_repo_check_option_strings=('-h' '--help' '--changes' '--no-change _shtab_ahriman_check_option_strings=('-h' '--help' '--changes' '--no-changes' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_repo_create_keyring_option_strings=('-h' '--help') _shtab_ahriman_repo_create_mirrorlist_option_strings=('-h' '--help') -_shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '--vcs' '--no-vcs' '-y' '--refresh') -_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '--vcs' '--no-vcs' '-y' '--refresh') +_shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh') +_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_repo_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username') _shtab_ahriman_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username') _shtab_ahriman_repo_remove_unknown_option_strings=('-h' '--help' '--dry-run') @@ -273,6 +273,8 @@ _shtab_ahriman_repo_daemon___no_changes_nargs=0 _shtab_ahriman_repo_daemon___dependencies_nargs=0 _shtab_ahriman_repo_daemon___no_dependencies_nargs=0 _shtab_ahriman_repo_daemon___dry_run_nargs=0 +_shtab_ahriman_repo_daemon___increment_nargs=0 +_shtab_ahriman_repo_daemon___no_increment_nargs=0 _shtab_ahriman_repo_daemon___local_nargs=0 _shtab_ahriman_repo_daemon___no_local_nargs=0 _shtab_ahriman_repo_daemon___manual_nargs=0 @@ -292,6 +294,8 @@ _shtab_ahriman_daemon___no_changes_nargs=0 _shtab_ahriman_daemon___dependencies_nargs=0 _shtab_ahriman_daemon___no_dependencies_nargs=0 _shtab_ahriman_daemon___dry_run_nargs=0 +_shtab_ahriman_daemon___increment_nargs=0 +_shtab_ahriman_daemon___no_increment_nargs=0 _shtab_ahriman_daemon___local_nargs=0 _shtab_ahriman_daemon___no_local_nargs=0 _shtab_ahriman_daemon___manual_nargs=0 diff --git a/package/share/man/man1/ahriman.1 b/package/share/man/man1/ahriman.1 index 82bb4b7b..50bb83fb 100644 --- a/package/share/man/man1/ahriman.1 +++ b/package/share/man/man1/ahriman.1 @@ -1,4 +1,4 @@ -.TH AHRIMAN "1" "2023\-12\-26" "ahriman" "Generated Python Manual" +.TH AHRIMAN "1" "2023\-12\-27" "ahriman" "Generated Python Manual" .SH NAME ahriman .SH SYNOPSIS @@ -484,8 +484,9 @@ create package which contains list of available mirrors as set by configuration. .SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] - [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-\-local | \-\-no\-local] - [\-\-manual | \-\-no\-manual] [\-\-partitions | \-\-no\-partitions] [\-\-vcs | \-\-no\-vcs] [\-y] + [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-\-increment | \-\-no\-increment] + [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-\-partitions | \-\-no\-partitions] + [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y] start process which periodically will run update process @@ -510,6 +511,10 @@ process missing package dependencies \fB\-\-dry\-run\fR just perform check for updates, same as check command +.TP +\fB\-\-increment\fR, \fB\-\-no\-increment\fR +increment package release (pkgrel) on duplicate + .TP \fB\-\-local\fR, \fB\-\-no\-local\fR enable or disable checking of local packages for updates @@ -522,6 +527,10 @@ include or exclude manual updates \fB\-\-partitions\fR, \fB\-\-no\-partitions\fR instead of updating whole repository, split updates into chunks +.TP +\fB\-u\fR \fI\,USERNAME\/\fR, \fB\-\-username\fR \fI\,USERNAME\/\fR +build as user + .TP \fB\-\-vcs\fR, \fB\-\-no\-vcs\fR fetch actual version of VCS packages diff --git a/package/share/zsh/site-functions/_ahriman b/package/share/zsh/site-functions/_ahriman index 79e98171..5ebe47c9 100644 --- a/package/share/zsh/site-functions/_ahriman +++ b/package/share/zsh/site-functions/_ahriman @@ -155,9 +155,11 @@ _shtab_ahriman_daemon_options=( {--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:" {--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:" "--dry-run[just perform check for updates, same as check command (default\: False)]" + {--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:" {--local,--no-local}"[enable or disable checking of local packages for updates (default\: True)]:local:" {--manual,--no-manual}"[include or exclude manual updates (default\: True)]:manual:" {--partitions,--no-partitions}"[instead of updating whole repository, split updates into chunks (default\: True)]:partitions:" + {-u,--username}"[build as user (default\: None)]:username:" {--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:" "*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]" ) @@ -363,9 +365,11 @@ _shtab_ahriman_repo_daemon_options=( {--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:" {--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:" "--dry-run[just perform check for updates, same as check command (default\: False)]" + {--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:" {--local,--no-local}"[enable or disable checking of local packages for updates (default\: True)]:local:" {--manual,--no-manual}"[include or exclude manual updates (default\: True)]:manual:" {--partitions,--no-partitions}"[instead of updating whole repository, split updates into chunks (default\: True)]:partitions:" + {-u,--username}"[build as user (default\: None)]:username:" {--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:" "*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]" ) diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index 1865c5d7..24ace99d 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -317,7 +317,8 @@ def _set_package_changes_remove_parser(root: SubParserAction) -> argparse.Argume description="remove the package changes stored remotely", formatter_class=_formatter) parser.add_argument("package", help="package base") - parser.set_defaults(handler=handlers.Change, action=Action.Remove, lock=None, quiet=True, report=False, unsafe=True) + parser.set_defaults(handler=handlers.Change, action=Action.Remove, exit_code=False, lock=None, quiet=True, + report=False, unsafe=True) return parser @@ -428,8 +429,8 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser: "it must end with ()") parser.add_argument("patch", help="path to file which contains function or variable value. If not set, " "the value will be read from stdin", type=Path, nargs="?") - parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture="", lock=None, report=False, - repository="") + parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture="", exit_code=False, lock=None, + report=False, repository="") return parser @@ -471,8 +472,8 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: "to remove only specified PKGBUILD variables. In case if not set, " "it will remove all patches related to the package", action="append") - parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture="", lock=None, report=False, - repository="") + parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture="", exit_code=False, lock=None, + report=False, repository="") return parser @@ -496,8 +497,8 @@ def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser: parser.add_argument("package", help="path to directory with changed files for patch addition/update", type=Path) parser.add_argument("-t", "--track", help="files which has to be tracked", action="append", default=["*.diff", "*.patch"]) - parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture="", lock=None, report=False, - repository="", variable=None) + parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture="", exit_code=False, lock=None, + report=False, repository="", variable=None) return parser @@ -542,8 +543,8 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser: parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, " "-yy to force refresh even if up to date", action="count", default=False) - parser.set_defaults(handler=handlers.Update, dependencies=False, dry_run=True, aur=True, local=True, manual=False, - username=None) + parser.set_defaults(handler=handlers.Update, aur=True, dependencies=False, dry_run=True, increment=False, + local=True, manual=False, username=None) return parser @@ -1073,8 +1074,8 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser: "which is in particular must be used for OAuth2 authorization type.") parser.add_argument("-R", "--role", help="user access level", type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read) - parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture="", lock=None, quiet=True, - report=False, repository="") + parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture="", exit_code=False, lock=None, + quiet=True, report=False, repository="") return parser @@ -1113,8 +1114,8 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: description="remove user from the user mapping and update the configuration", formatter_class=_formatter) parser.add_argument("username", help="username for web service") - parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture="", lock=None, quiet=True, - report=False, repository="") + parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture="", exit_code=False, lock=None, + quiet=True, report=False, repository="") return parser diff --git a/src/ahriman/application/handlers/daemon.py b/src/ahriman/application/handlers/daemon.py index 0b350cd9..933f79c0 100644 --- a/src/ahriman/application/handlers/daemon.py +++ b/src/ahriman/application/handlers/daemon.py @@ -22,6 +22,7 @@ import argparse from ahriman.application.application import Application from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator from ahriman.application.handlers import Handler +from ahriman.application.handlers.update import Update from ahriman.core.configuration import Configuration from ahriman.models.repository_id import RepositoryId @@ -43,8 +44,6 @@ class Daemon(Handler): configuration(Configuration): configuration instance report(bool): force enable or disable reporting """ - from ahriman.application.handlers import Update - application = Application(repository_id, configuration, report=report, refresh_pacman_database=args.refresh) if args.partitions: iterator = UpdatesIterator(application, args.interval) diff --git a/tests/ahriman/application/test_ahriman.py b/tests/ahriman/application/test_ahriman.py index f129ba16..d4121150 100644 --- a/tests/ahriman/application/test_ahriman.py +++ b/tests/ahriman/application/test_ahriman.py @@ -272,11 +272,12 @@ def test_subparsers_package_add_option_variable_multiple(parser: argparse.Argume def test_subparsers_package_changes(parser: argparse.ArgumentParser) -> None: """ - package-changes command must imply action, lock, quiet, report and unsafe + package-changes command must imply action, exit code, lock, quiet, report and unsafe """ args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-changes", "ahriman"]) assert args.action == Action.List assert args.architecture == "x86_64" + assert not args.exit_code assert args.lock is None assert args.quiet assert not args.report @@ -298,6 +299,15 @@ def test_subparsers_package_changes_remove(parser: argparse.ArgumentParser) -> N assert args.unsafe +def test_subparsers_package_changes_remove_package_changes(parser: argparse.ArgumentParser) -> None: + """ + package-changes-remove must have same keys as package-changes + """ + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-changes-remove", "ahriman"]) + reference_args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-changes", "ahriman"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_package_remove_option_architecture(parser: argparse.ArgumentParser) -> None: """ package-remove command must correctly parse architecture list @@ -369,13 +379,24 @@ def test_subparsers_package_status_update_option_status(parser: argparse.Argumen assert isinstance(args.status, BuildStatusEnum) +def test_subparsers_package_status_update_package_status_remove(parser: argparse.ArgumentParser) -> None: + """ + package-status-update must have same keys as package-status-remove + """ + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-update"]) + reference_args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-remove", "ahriman"]) + del args.status + assert dir(args) == dir(reference_args) + + def test_subparsers_patch_add(parser: argparse.ArgumentParser) -> None: """ - patch-add command must imply action, architecture list, lock, report and repository + patch-add command must imply action, architecture list, exit code, lock, report and repository """ args = parser.parse_args(["patch-add", "ahriman", "version"]) assert args.action == Action.Update assert args.architecture == "" + assert not args.exit_code assert args.lock is None assert not args.report assert args.repository == "" @@ -442,13 +463,24 @@ def test_subparsers_patch_list_option_variable_multiple(parser: argparse.Argumen assert args.variable == ["var1", "var2"] +def test_subparsers_patch_list_patch_add(parser: argparse.ArgumentParser) -> None: + """ + patch-list must have same keys as patch-add + """ + args = parser.parse_args(["patch-list", "ahriman"]) + reference_args = parser.parse_args(["patch-add", "ahriman", "version"]) + del reference_args.patch + assert dir(args) == dir(reference_args) + + def test_subparsers_patch_remove(parser: argparse.ArgumentParser) -> None: """ - patch-remove command must imply action, architecture list, lock, report and repository + patch-remove command must imply action, architecture list, exit code, lock, report and repository """ args = parser.parse_args(["patch-remove", "ahriman"]) assert args.action == Action.Remove assert args.architecture == "" + assert not args.exit_code assert args.lock is None assert not args.report assert args.repository == "" @@ -486,13 +518,24 @@ def test_subparsers_patch_remove_option_variable_multiple(parser: argparse.Argum assert args.variable == ["var1", "var2"] +def test_subparsers_patch_remove_patch_add(parser: argparse.ArgumentParser) -> None: + """ + patch-remove must have same keys as patch-add + """ + args = parser.parse_args(["patch-remove", "ahriman"]) + reference_args = parser.parse_args(["patch-add", "ahriman", "version"]) + del reference_args.patch + assert dir(args) == dir(reference_args) + + def test_subparsers_patch_set_add(parser: argparse.ArgumentParser) -> None: """ - patch-set-add command must imply action, architecture list, lock, report, repository and variable + patch-set-add command must imply action, architecture list, exit code, lock, report, repository and variable """ args = parser.parse_args(["patch-set-add", "ahriman"]) assert args.action == Action.Update assert args.architecture == "" + assert not args.exit_code assert args.lock is None assert not args.report assert args.repository == "" @@ -531,6 +574,16 @@ def test_subparsers_patch_set_add_option_track(parser: argparse.ArgumentParser) assert args.track == ["*.diff", "*.patch", "*.py"] +def test_subparsers_patch_set_add_patch_add(parser: argparse.ArgumentParser) -> None: + """ + patch-set-add must have same keys as patch-add + """ + args = parser.parse_args(["patch-set-add", "ahriman"]) + reference_args = parser.parse_args(["patch-add", "ahriman", "version"]) + del reference_args.patch, args.track + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_backup(parser: argparse.ArgumentParser) -> None: """ repo-backup command must imply architecture list, lock, report, repository and unsafe @@ -561,12 +614,14 @@ def test_subparsers_repo_backup_option_repository(parser: argparse.ArgumentParse def test_subparsers_repo_check(parser: argparse.ArgumentParser) -> None: """ - repo-check command must imply dependencies, dry-run, aur, manual and username + repo-check command must imply aur, dependencies, dry-run, increment, local, manual and username """ args = parser.parse_args(["repo-check"]) + assert args.aur assert not args.dependencies assert args.dry_run - assert args.aur + assert not args.increment + assert args.local assert not args.manual assert args.username is None @@ -603,6 +658,15 @@ def test_subparsers_repo_check_option_refresh(parser: argparse.ArgumentParser) - assert args.refresh == 2 +def test_subparsers_repo_check_repo_update(parser: argparse.ArgumentParser) -> None: + """ + repo-check must have same keys as repo-update + """ + args = parser.parse_args(["repo-check"]) + reference_args = parser.parse_args(["repo-update"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_create_keyring(parser: argparse.ArgumentParser) -> None: """ repo-create-keyring command must imply trigger @@ -631,6 +695,15 @@ def test_subparsers_repo_create_keyring_option_repository(parser: argparse.Argum assert args.repository == "repo" +def test_subparsers_repo_create_keyring_repo_triggers(parser: argparse.ArgumentParser) -> None: + """ + repo-create-keyring must have same keys as repo-triggers + """ + args = parser.parse_args(["repo-create-keyring"]) + reference_args = parser.parse_args(["repo-triggers"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_create_mirrorlist(parser: argparse.ArgumentParser) -> None: """ repo-create-mirrorlist command must imply trigger @@ -659,6 +732,15 @@ def test_subparsers_repo_create_mirrorlist_option_repository(parser: argparse.Ar assert args.repository == "repo" +def test_subparsers_repo_create_mirrorlist_repo_triggers(parser: argparse.ArgumentParser) -> None: + """ + repo-create-mirrorlist must have same keys as repo-triggers + """ + args = parser.parse_args(["repo-create-mirrorlist"]) + reference_args = parser.parse_args(["repo-triggers"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_daemon(parser: argparse.ArgumentParser) -> None: """ repo-daemon command must imply exit code and package @@ -690,6 +772,16 @@ def test_subparsers_repo_daemon_option_interval(parser: argparse.ArgumentParser) assert isinstance(args.interval, int) +def test_subparsers_repo_daemon_repo_update(parser: argparse.ArgumentParser) -> None: + """ + repo-create-keyring must have same keys as repo-triggers + """ + args = parser.parse_args(["repo-daemon"]) + reference_args = parser.parse_args(["repo-update"]) + del args.interval, args.partitions + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_rebuild_option_architecture(parser: argparse.ArgumentParser) -> None: """ repo-rebuild command must correctly parse architecture list @@ -782,6 +874,15 @@ def test_subparsers_repo_report_option_repository(parser: argparse.ArgumentParse assert args.repository == "repo" +def test_subparsers_repo_report_repo_triggers(parser: argparse.ArgumentParser) -> None: + """ + repo-report must have same keys as repo-triggers + """ + args = parser.parse_args(["repo-report"]) + reference_args = parser.parse_args(["repo-triggers"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_restore(parser: argparse.ArgumentParser) -> None: """ repo-restore command must imply architecture list, lock, report, repository and unsafe @@ -855,6 +956,15 @@ def test_subparsers_repo_status_update_option_status(parser: argparse.ArgumentPa assert isinstance(args.status, BuildStatusEnum) +def test_subparsers_repo_status_update_package_status_update(parser: argparse.ArgumentParser) -> None: + """ + repo-status-update must have same keys as package-status-update + """ + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "repo-status-update"]) + reference_args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-update"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_sync(parser: argparse.ArgumentParser) -> None: """ repo-sync command must imply trigger @@ -883,6 +993,15 @@ def test_subparsers_repo_sync_option_repository(parser: argparse.ArgumentParser) assert args.repository == "repo" +def test_subparsers_repo_sync_repo_triggers(parser: argparse.ArgumentParser) -> None: + """ + repo-sync must have same keys as repo-triggers + """ + args = parser.parse_args(["repo-sync"]) + reference_args = parser.parse_args(["repo-triggers"]) + assert dir(args) == dir(reference_args) + + def test_subparsers_repo_tree(parser: argparse.ArgumentParser) -> None: """ repo-tree command must imply lock, quiet, report and unsafe @@ -1203,11 +1322,12 @@ def test_subparsers_service_tree_migrate(parser: argparse.ArgumentParser) -> Non def test_subparsers_user_add(parser: argparse.ArgumentParser) -> None: """ - user-add command must imply action, architecture, lock, quiet, report and repository + user-add command must imply action, architecture, exit code, lock, quiet, report and repository """ args = parser.parse_args(["user-add", "username"]) assert args.action == Action.Update assert args.architecture == "" + assert not args.exit_code assert args.lock is None assert args.quiet assert not args.report @@ -1278,13 +1398,24 @@ def test_subparsers_user_list_option_role(parser: argparse.ArgumentParser) -> No assert isinstance(args.role, UserAccess) +def test_subparsers_user_list_user_add(parser: argparse.ArgumentParser) -> None: + """ + user-list must have same keys as user-add + """ + args = parser.parse_args(["user-list"]) + reference_args = parser.parse_args(["user-add", "username"]) + del reference_args.key, reference_args.packager, reference_args.password + assert dir(args) == dir(reference_args) + + def test_subparsers_user_remove(parser: argparse.ArgumentParser) -> None: """ - user-remove command must imply action, architecture, lock, quiet, report and repository + user-remove command must imply action, architecture, exit code, lock, quiet, report and repository """ args = parser.parse_args(["user-remove", "username"]) assert args.action == Action.Remove assert args.architecture == "" + assert not args.exit_code assert args.lock is None assert args.quiet assert not args.report @@ -1307,6 +1438,16 @@ def test_subparsers_user_remove_option_repository(parser: argparse.ArgumentParse assert args.repository == "" +def test_subparsers_user_remove_user_add(parser: argparse.ArgumentParser) -> None: + """ + user-list must have same keys as user-add + """ + args = parser.parse_args(["user-remove", "username"]) + reference_args = parser.parse_args(["user-add", "username"]) + del reference_args.key, reference_args.packager, reference_args.password, reference_args.role + assert dir(args) == dir(reference_args) + + def test_subparsers_web(parser: argparse.ArgumentParser) -> None: """ web command must imply architecture, report, repository and parser