55import os
66import subprocess
77import sys
8+ from pathlib import Path
89
910from lib .commands import ssh
11+ from lib .config_loader import load_config
1012
1113from typing import NotRequired , TypedDict , cast
1214
@@ -811,14 +813,26 @@ def extract_tests(cmd: list[str]) -> set[str]:
811813 if error :
812814 sys .exit (1 )
813815
816+ def _config_hosts (args : argparse .Namespace ) -> str | None :
817+ """Return the pool masters listed in the config's [hosts], as a comma-separated string, or None."""
818+ cfg = load_config (override = args .config , config_values = args .config_value )
819+ hosts = list (cfg .hosts .keys ())
820+ return "," .join (hosts ) if hosts else None
821+
822+
814823def action_run (args : argparse .Namespace ) -> None :
815- cmd = build_pytest_cmd (JOBS [args .job ], args .hosts , None , args .pytest_args )
824+ hosts = args .hosts or _config_hosts (args )
825+ if hosts is None :
826+ print ("Error: no hosts provided. Pass a comma-separated list of pool masters as the positional "
827+ "hosts argument, or define them in the [hosts] section of the config." , file = sys .stderr )
828+ sys .exit (1 )
829+ cmd = build_pytest_cmd (JOBS [args .job ], hosts , None , args .pytest_args )
816830 print (subprocess .list2cmdline (cmd ))
817831 if args .print_only :
818832 return
819833
820834 # check that enough pool masters have been provided
821- nb_pools = len (args . hosts .split ("," ))
835+ nb_pools = len (hosts .split ("," ))
822836 job_nb_pools = JOBS [args .job ]["nb_pools" ]
823837 assert isinstance (job_nb_pools , int )
824838 if nb_pools < job_nb_pools :
@@ -837,35 +851,69 @@ def action_run(args: argparse.Namespace) -> None:
837851
838852def main () -> None :
839853 parser = argparse .ArgumentParser (description = "Manage test jobs" )
854+ parser .add_argument (
855+ "-c" , "--config" ,
856+ type = Path ,
857+ default = None ,
858+ metavar = "PATH" ,
859+ help = "Config overlay: a .toml file path or profile name (default: config.default.toml or XCPNG_CONFIG)" ,
860+ )
861+ common_parser = argparse .ArgumentParser (add_help = False )
862+ common_parser .add_argument (
863+ "-c" , "--config" ,
864+ type = Path ,
865+ default = None ,
866+ metavar = "PATH" ,
867+ help = "Config overlay: a .toml file path or profile name (default: config.default.toml or XCPNG_CONFIG)" ,
868+ )
869+
870+ def _add_config_value_option (target : argparse .ArgumentParser ) -> None :
871+ target .add_argument (
872+ "--config-value" ,
873+ action = "append" ,
874+ default = [],
875+ metavar = "KEY=VALUE" ,
876+ help = "Override a config value, e.g. host.default_password=foo (repeatable; highest priority)" ,
877+ )
878+
879+ _add_config_value_option (parser )
880+ _add_config_value_option (common_parser )
881+
840882 subparsers = parser .add_subparsers (dest = "action" , metavar = "action" )
841883 subparsers .required = True
842884
843885 list_parser = subparsers .add_parser ("list" , help = "list available jobs." )
844886 list_parser .set_defaults (func = action_list )
845887
846- run_parser = subparsers .add_parser ("show" , help = "show details about a job definition." )
847- run_parser .add_argument ("job" , help = "name of the job." , choices = JOBS .keys (), metavar = "job" )
848- run_parser .set_defaults (func = action_show )
888+ show_parser = subparsers .add_parser ("show" , help = "show details about a job definition." , parents = [ common_parser ] )
889+ show_parser .add_argument ("job" , help = "name of the job." , choices = JOBS .keys (), metavar = "job" )
890+ show_parser .set_defaults (func = action_show )
849891
850- run_parser = subparsers .add_parser ("collect" , help = "show test collection based on the job definition." )
851- run_parser .add_argument ("job" , help = "name of the job." , choices = JOBS .keys (), metavar = "job" )
852- run_parser .add_argument ("-v" , "--host-version" , help = "host version to match VM filters." )
853- run_parser .add_argument ("pytest_args" , nargs = argparse .REMAINDER ,
854- help = "all additional arguments after the last positional argument will "
855- "be passed to pytest and replace default job params if needed." )
856- run_parser .set_defaults (func = action_collect )
892+ collect_parser = subparsers .add_parser ("collect" , help = "show test collection based on the job definition." ,
893+ parents = [common_parser ])
894+ collect_parser .add_argument ("job" , help = "name of the job." , choices = JOBS .keys (), metavar = "job" )
895+ collect_parser .add_argument ("-v" , "--host-version" , help = "host version to match VM filters." )
896+ collect_parser .add_argument ("pytest_args" , nargs = argparse .REMAINDER ,
897+ help = "all additional arguments after the last positional argument will "
898+ "be passed to pytest and replace default job params if needed." )
899+ collect_parser .set_defaults (func = action_collect )
857900
858- run_parser = subparsers .add_parser ("check" , help = "run sanity checks on the tests and jobs." )
859- run_parser .set_defaults (func = action_check )
901+ check_parser = subparsers .add_parser (
902+ "check" , help = "run sanity checks on the tests and jobs." , parents = [common_parser ])
903+ check_parser .set_defaults (func = action_check )
860904
861- run_parser = subparsers .add_parser ("run" , help = "run a job." )
905+ run_parser = subparsers .add_parser ("run" , help = "run a job." , parents = [ common_parser ] )
862906 run_parser .add_argument ("--print-only" , "-p" , action = "store_true" ,
863907 help = "print the command, but don't run it. Must be specified before positional arguments." )
864908 run_parser .add_argument ("job" , help = "name of the job to run." , choices = JOBS .keys (), metavar = "job" )
865- run_parser .add_argument ("hosts" , help = "master host(s) of pools to run the tests on, comma-separated." )
909+ run_parser .add_argument ("hosts" , nargs = "?" , default = None ,
910+ help = "master host(s) of pools to run the tests on, comma-separated. When omitted, the "
911+ "hosts from the config's [hosts] section are used." )
866912 run_parser .add_argument ("pytest_args" , nargs = argparse .REMAINDER ,
867913 help = "all additional arguments after the last positional argument will "
868- "be passed to pytest and replace default job params if needed." )
914+ "be passed to pytest and replace default job params if needed. "
915+ "Note: -c/--config and --config-value must be specified before the "
916+ "positional arguments." )
869917 run_parser .set_defaults (func = action_run )
870918
871919 args = parser .parse_args ()
0 commit comments