From 893f53fc236f5d07a96a34f9f0e31bac8b8ae8f8 Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Thu, 21 Sep 2017 16:29:08 +0900 Subject: [PATCH] Use cliff for CLI layer This commit makes stestr use cliff[1] for CLI layer. The cliff project provides a lot of advantages for stestr cli which has subcommands. Instead of just using argparse, we should leverage cliff to provide a more plished CLI experience. [1] https://pypi.python.org/pypi/cliff Closes Issue #62 --- requirements.txt | 1 + setup.cfg | 9 ++ stestr/cli.py | 75 +++++------ stestr/commands/failing.py | 33 ++--- stestr/commands/init.py | 21 ++- stestr/commands/last.py | 72 ++++++----- stestr/commands/list.py | 82 +++++++----- stestr/commands/load.py | 97 +++++++------- stestr/commands/run.py | 207 ++++++++++++++++-------------- stestr/commands/slowest.py | 36 +++--- stestr/tests/test_return_codes.py | 3 - 11 files changed, 338 insertions(+), 298 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7226bf45..0a1c575a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ # process, which may cause wedges in the gate later. future pbr!=2.1.0,>=2.0.0 # Apache-2.0 +cliff>=2.8.0 # Apache-2.0 python-subunit>=0.18.0 # Apache-2.0/BSD fixtures>=3.0.0 # Apache-2.0/BSD six>=1.10.0 # MIT diff --git a/setup.cfg b/setup.cfg index 81863051..7a54b0e1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,6 +29,15 @@ packages = console_scripts = stestr = stestr.cli:main +stestr.cm = + run = stestr.commands.run:Run + failing = stestr.commands.failing:Failing + init = stestr.commands.init:Init + last = stestr.commands.last:Last + list = stestr.commands.list:List + load = stestr.commands.load:Load + slowest = stestr.commands.slowest:Slowest + [extras] sql = subunit2sql>=1.8.0 diff --git a/stestr/cli.py b/stestr/cli.py index 312ecdba..e2f951d1 100644 --- a/stestr/cli.py +++ b/stestr/cli.py @@ -10,36 +10,41 @@ # License for the specific language governing permissions and limitations # under the License. -import argparse -import importlib -import os import sys +from cliff import app +from cliff import commandmanager from stestr import version __version__ = version.version_info.version_string_with_vcs() -class StestrCLI(object): - - commands = ['run', 'list', 'slowest', 'failing', 'last', 'init', 'load'] - command_module = 'stestr.commands.' +class StestrCLI(app.App): def __init__(self): - self.parser = self._get_parser() - - def _get_parser(self): - self.command_dict = {} - parser = argparse.ArgumentParser() - self._set_common_opts(parser) - subparsers = parser.add_subparsers(help='command help') - for cmd in self.commands: - self.command_dict[cmd] = importlib.import_module( - self.command_module + cmd) - help_str = self.command_dict[cmd].get_cli_help() - command_parser = subparsers.add_parser(cmd, help=help_str) - self.command_dict[cmd].set_cli_opts(command_parser) - command_parser.set_defaults(func=self.command_dict[cmd].run) + super(StestrCLI, self).__init__( + description='stestr application', + version=__version__, + command_manager=commandmanager.CommandManager('stestr.cm'), + deferred_help=True, + ) + + def initialize_app(self, argv): + self.LOG.debug('initialize_app') + + def prepare_to_run_command(self, cmd): + self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__) + + def clean_up(self, cmd, result, err): + self.LOG.debug('clean_up %s', cmd.__class__.__name__) + if err: + self.LOG.debug('got an error: %s', err) + + def build_option_parser(self, description, version, argparse_kwargs=None): + parser = super(StestrCLI, + self).build_option_parser(description, version, + argparse_kwargs) + parser = self._set_common_opts(parser) return parser def _set_common_opts(self, parser): @@ -49,12 +54,6 @@ def _set_common_opts(self, parser): "path lookups but does not affect paths " "supplied to the command.", default=None, type=str) - parser.add_argument("-q", "--quiet", action="store_true", - default=False, - help="Turn off output other than the primary " - "output for a command and any errors.") - parser.add_argument('--version', action='version', - version=__version__) parser.add_argument('--config', '-c', dest='config', default='.stestr.conf', help="Set a stestr config file to use with this " @@ -88,25 +87,13 @@ def _set_common_opts(self, parser): "both this and the corresponding config file " "option are set this value will be used.") + return parser + -def main(): +def main(argv=sys.argv[1:]): cli = StestrCLI() - args = cli.parser.parse_known_args() - if args[0].here: - os.chdir(args[0].here) - # NOTE(mtreinish): Make sure any subprocesses launch the same version of - # python being run here - if 'PYTHON' not in os.environ: - os.environ['PYTHON'] = sys.executable - if hasattr(args[0], 'func'): - sys.exit(args[0].func(args)) - else: - cli.parser.print_help() - # NOTE(andreaf) This point is reached only when using Python 3.x. - # Python 2.x fails with return code 2 in case of no - # command, so using 2 for consistency - sys.exit(2) + return cli.run(argv) if __name__ == '__main__': - main() + sys.exit(main(sys.argv[1:])) diff --git a/stestr/commands/failing.py b/stestr/commands/failing.py index 1ea43d4f..74cbfce1 100644 --- a/stestr/commands/failing.py +++ b/stestr/commands/failing.py @@ -14,6 +14,7 @@ import sys +from cliff import command import testtools from stestr import output @@ -21,17 +22,25 @@ from stestr import results -def get_cli_help(): - return "Show the current failures known by the repository" +class Failing(command.Command): + def get_description(self): + return "Show the current failures known by the repository" + def get_parser(self, prog_name): + parser = super(Failing, self).get_parser(prog_name) + parser.add_argument( + "--subunit", action="store_true", + default=False, help="Show output as a subunit stream.") + parser.add_argument( + "--list", action="store_true", + default=False, help="Show only a list of failing tests.") + return parser -def set_cli_opts(parser): - parser.add_argument( - "--subunit", action="store_true", - default=False, help="Show output as a subunit stream."), - parser.add_argument( - "--list", action="store_true", - default=False, help="Show only a list of failing tests."), + def take_action(self, parsed_args): + args = parsed_args + return failing(repo_type=self.app_args.repo_type, + repo_url=self.app_args.repo_url, + list_tests=args.list, subunit=args.subunit) def _show_subunit(run): @@ -57,12 +66,6 @@ def _get_id(): return output_result, summary_result -def run(arguments): - args = arguments[0] - return failing(repo_type=args.repo_type, repo_url=args.repo_url, - list_tests=args.list, subunit=args.subunit) - - def failing(repo_type='file', repo_url=None, list_tests=False, subunit=False, stdout=sys.stdout): """Print the failing tests from the most recent run in the repository diff --git a/stestr/commands/init.py b/stestr/commands/init.py index eb3da1e1..c773c519 100644 --- a/stestr/commands/init.py +++ b/stestr/commands/init.py @@ -14,12 +14,18 @@ import sys +from cliff import command + from stestr.repository import util -def run(arguments): - args = arguments[0] - init(args.repo_type, args.repo_url) +class Init(command.Command): + def take_action(self, parsed_args): + init(self.app_args.repo_type, self.app_args.repo_url) + + def get_description(self): + help_str = "Create a new repository." + return help_str def init(repo_type='file', repo_url=None, stdout=sys.stdout): @@ -50,12 +56,3 @@ def init(repo_type='file', repo_url=None, stdout=sys.stdout): 'Please check if the repository already exists or ' 'select a different path\n' % repo_path) return 1 - - -def set_cli_opts(parser): - pass - - -def get_cli_help(): - help_str = "Create a new repository." - return help_str diff --git a/stestr/commands/last.py b/stestr/commands/last.py index e97c367e..0d3e0273 100644 --- a/stestr/commands/last.py +++ b/stestr/commands/last.py @@ -14,6 +14,8 @@ import sys +from cliff import command + from stestr import output from stestr.repository import abstract from stestr.repository import util @@ -21,40 +23,42 @@ from stestr import subunit_trace -def get_cli_help(): - help_str = """Show the last run loaded into a repository. - - Failing tests are shown on the console and a summary of the run is printed - at the end. - - Without --subunit, the process exit code will be non-zero if the test run - was not successful. With --subunit, the process exit code is non-zero if - the subunit stream could not be generated successfully. - """ - return help_str - - -def set_cli_opts(parser): - parser.add_argument( - "--subunit", action="store_true", - default=False, help="Show output as a subunit stream.") - parser.add_argument("--no-subunit-trace", action='store_true', - default=False, - help="Disable output with the subunit-trace output " - "filter") - parser.add_argument('--color', action='store_true', default=False, - help='Enable color output in the subunit-trace output,' - ' if subunit-trace output is enabled. (this is ' - 'the default). If subunit-trace is disable this ' - ' does nothing.') - - -def run(arguments): - args = arguments[0] - pretty_out = not args.no_subunit_trace - return last(repo_type=args.repo_type, repo_url=args.repo_url, - subunit_out=args.subunit, pretty_out=pretty_out, - color=args.color) +class Last(command.Command): + def get_description(self): + help_str = """Show the last run loaded into a repository. + + Failing tests are shown on the console and a summary of the run is + printed at the end. + + Without --subunit, the process exit code will be non-zero if the test + run was not successful. With --subunit, the process exit code is + non-zero if the subunit stream could not be generated successfully. + """ + return help_str + + def get_parser(self, prog_name): + parser = super(Last, self).get_parser(prog_name) + parser.add_argument( + "--subunit", action="store_true", + default=False, help="Show output as a subunit stream.") + parser.add_argument("--no-subunit-trace", action='store_true', + default=False, + help="Disable output with the subunit-trace " + "output filter") + parser.add_argument('--color', action='store_true', default=False, + help='Enable color output in the subunit-trace ' + 'output, if subunit-trace output is enabled. ' + '(this is the default). If subunit-trace is ' + 'disable this does nothing.') + return parser + + def take_action(self, parsed_args): + args = parsed_args + pretty_out = not args.no_subunit_trace + return last(repo_type=self.app_args.repo_type, + repo_url=self.app_args.repo_url, + subunit_out=args.subunit, pretty_out=pretty_out, + color=args.color) def last(repo_type='file', repo_url=None, subunit_out=False, pretty_out=True, diff --git a/stestr/commands/list.py b/stestr/commands/list.py index aaf4db50..f00c74b1 100644 --- a/stestr/commands/list.py +++ b/stestr/commands/list.py @@ -15,47 +15,61 @@ from io import BytesIO import sys +from cliff import command + from stestr import config_file from stestr import output -def get_cli_help(): - help_str = ("List the tests for a project. You can use a filter just like" - "with the run command to see exactly what tests match") - return help_str - +class List(command.Command): -def set_cli_opts(parser): - parser.add_argument('--blacklist-file', '-b', - default=None, dest='blacklist_file', - help='Path to a blacklist file, this file ' - 'contains a separate regex exclude on each ' - 'newline') - parser.add_argument('--whitelist-file', '-w', - default=None, dest='whitelist_file', - help='Path to a whitelist file, this file ' - 'contains a separate regex on each newline.') - parser.add_argument('--black-regex', '-B', - default=None, dest='black_regex', - help='Test rejection regex. If a test cases name ' - 'matches on re.search() operation , ' - 'it will be removed from the final test list. ' - 'Effectively the black-regexp is added to ' - ' black regexp list, but you do need to edit a file. ' - 'The black filtering happens after the initial ' - ' white selection, which by default is everything.') + def get_description(self): + help_str = ("List the tests for a project. You can use a filter just " + "like with the run command to see exactly what tests " + "match") + return help_str + def get_parser(self, prog_name): + parser = super(List, self).get_parser(prog_name) + parser.add_argument("filters", nargs="*", default=None, + help="A list of string regex filters to initially " + "apply on the test list. Tests that match any of " + "the regexes will be used. (assuming any other " + "filtering specified also uses it)") + parser.add_argument('--blacklist-file', '-b', + default=None, dest='blacklist_file', + help='Path to a blacklist file, this file ' + 'contains a separate regex exclude on each ' + 'newline') + parser.add_argument('--whitelist-file', '-w', + default=None, dest='whitelist_file', + help='Path to a whitelist file, this file ' + 'contains a separate regex on each newline.') + parser.add_argument('--black-regex', '-B', + default=None, dest='black_regex', + help='Test rejection regex. If a test cases name ' + 'matches on re.search() operation , ' + 'it will be removed from the final test list. ' + 'Effectively the black-regexp is added to ' + ' black regexp list, but you do need to edit a ' + 'file. The black filtering happens after the ' + 'initial white selection, which by default is ' + 'everything.') + return parser -def run(arguments): - args = arguments[0] - filters = arguments[1] - return list_command(config=args.config, repo_type=args.repo_type, - repo_url=args.repo_url, group_regex=args.group_regex, - test_path=args.test_path, top_dir=args.top_dir, - blacklist_file=args.blacklist_file, - whitelist_file=args.whitelist_file, - black_regex=args.black_regex, - filters=filters) + def take_action(self, parsed_args): + args = parsed_args + filters = parsed_args.filters + return list_command(config=self.app_args.config, + repo_type=self.app_args.repo_type, + repo_url=self.app_args.repo_url, + group_regex=self.app_args.group_regex, + test_path=self.app_args.test_path, + top_dir=self.app_args.top_dir, + blacklist_file=args.blacklist_file, + whitelist_file=args.whitelist_file, + black_regex=args.black_regex, + filters=filters) def list_command(config='.stestr.conf', repo_type='file', repo_url=None, diff --git a/stestr/commands/load.py b/stestr/commands/load.py index 2648c284..6e6f19fe 100644 --- a/stestr/commands/load.py +++ b/stestr/commands/load.py @@ -17,6 +17,7 @@ import functools import sys +from cliff import command import subunit import testtools @@ -28,51 +29,57 @@ from stestr import utils -def set_cli_opts(parser): - parser.add_argument("--partial", action="store_true", - default=False, - help="The stream being loaded was a partial run.") - parser.add_argument("--force-init", action="store_true", - default=False, - help="Initialise the repository if it does not exist " - "already") - parser.add_argument("--subunit", action="store_true", - default=False, - help="Display results in subunit format.") - parser.add_argument("--id", "-i", default=None, - help="Append the stream into an existing entry in the " - "repository") - parser.add_argument("--subunit-trace", action='store_true', default=False, - help="Display the loaded stream through the " - "subunit-trace output filter") - parser.add_argument('--color', action='store_true', default=False, - help='Enable color output in the subunit-trace output,' - ' if subunit-trace output is enabled. If ' - 'subunit-trace is disable this does nothing.') - parser.add_argument('--abbreviate', action='store_true', - dest='abbreviate', - help='Print one character status for each test') - - -def get_cli_help(): - help_str = """Load a subunit stream into a repository. - - Failing tests are shown on the console and a summary of the stream is - printed at the end. - - Unless the stream is a partial stream, any existing failures are - discarded. - """ - return help_str - - -def run(arguments): - args = arguments[0] - load(repo_type=args.repo_type, repo_url=args.repo_url, - partial=args.partial, subunit_out=args.subunit, - force_init=args.force_init, streams=arguments[1], - pretty_out=args.subunit_trace, color=args.color, - abbreviate=args.abbreviate) +class Load(command.Command): + def get_parser(self, prog_name): + parser = super(Load, self).get_parser(prog_name) + parser.add_argument("files", nargs="*", default=False, + help="A list of file paths to read for the input " + "streams.") + parser.add_argument("--partial", action="store_true", + default=False, + help="The stream being loaded was a partial run.") + parser.add_argument("--force-init", action="store_true", + default=False, + help="Initialise the repository if it does not " + "exist already") + parser.add_argument("--subunit", action="store_true", + default=False, + help="Display results in subunit format.") + parser.add_argument("--id", "-i", default=None, + help="Append the stream into an existing entry in " + "the repository") + parser.add_argument("--subunit-trace", action='store_true', + default=False, + help="Display the loaded stream through the " + "subunit-trace output filter") + parser.add_argument('--color', action='store_true', default=False, + help='Enable color output in the subunit-trace ' + 'output, if subunit-trace output is enabled. If ' + 'subunit-trace is disable this does nothing.') + parser.add_argument('--abbreviate', action='store_true', + dest='abbreviate', + help='Print one character status for each test') + return parser + + def get_description(self): + help_str = """Load a subunit stream into a repository. + + Failing tests are shown on the console and a summary of the stream + is printed at the end. + + Unless the stream is a partial stream, any existing failures are + discarded. + """ + return help_str + + def take_action(self, parsed_args): + args = parsed_args + load(repo_type=self.app_args.repo_type, + repo_url=self.app_args.repo_url, + partial=args.partial, subunit_out=args.subunit, + force_init=args.force_init, streams=args.files, + pretty_out=args.subunit_trace, color=args.color, + abbreviate=args.abbreviate) def load(force_init=False, in_streams=None, diff --git a/stestr/commands/run.py b/stestr/commands/run.py index 9f7dab58..56545b5a 100644 --- a/stestr/commands/run.py +++ b/stestr/commands/run.py @@ -12,11 +12,13 @@ """Run a projects tests and load them into stestr.""" +import logging from math import ceil import os import subprocess import sys +from cliff import command import six import subunit import testtools @@ -29,81 +31,116 @@ from stestr.testlist import parse_list -def set_cli_opts(parser): - parser.add_argument("--failing", action="store_true", - default=False, - help="Run only tests known to be failing.") - parser.add_argument("--serial", action="store_true", - default=False, - help="Run tests in a serial process.") - parser.add_argument("--concurrency", action="store", default=0, - help="How many processes to use. The default (0) " - "autodetects your CPU count.") - parser.add_argument("--load-list", default=None, - help="Only run tests listed in the named file."), - parser.add_argument("--partial", action="store_true", default=False, - help="Only some tests will be run. Implied by " - "--failing.") - parser.add_argument("--subunit", action="store_true", default=False, - help="Display results in subunit format.") - parser.add_argument("--until-failure", action="store_true", default=False, - help="Repeat the run again and again until failure " - "occurs.") - parser.add_argument("--analyze-isolation", action="store_true", - default=False, - help="Search the last test run for 2-test test " - "isolation interactions.") - parser.add_argument("--isolated", action="store_true", - default=False, - help="Run each test id in a separate test runner.") - parser.add_argument("--worker-file", action="store", default=None, - dest='worker_path', - help="Optional path of a manual worker grouping file " - "to use for the run") - parser.add_argument('--blacklist-file', '-b', - default=None, dest='blacklist_file', - help='Path to a blacklist file, this file ' - 'contains a separate regex exclude on each ' - 'newline') - parser.add_argument('--whitelist-file', '-w', - default=None, dest='whitelist_file', - help='Path to a whitelist file, this file ' - 'contains a separate regex on each newline.') - parser.add_argument('--black-regex', '-B', default=None, - dest='black_regex', - help='Test rejection regex. If a test cases name ' - 'matches on re.search() operation , ' - 'it will be removed from the final test list. ' - 'Effectively the black-regexp is added to ' - ' black regexp list, but you do need to edit a file. ' - 'The black filtering happens after the initial ' - ' white selection, which by default is everything.') - parser.add_argument('--no-discover', '-n', default=None, metavar='TEST_ID', - help="Takes in a single test to bypasses test discover" - " and just execute the test specified. A file " - "name may be used in place of a test name.") - parser.add_argument('--random', '-r', action="store_true", default=False, - help="Randomize the test order after they are " - "partitioned into separate workers") - parser.add_argument('--combine', action='store_true', default=False, - help="Combine the results from the test run with the " - "last run in the repository") - parser.add_argument('--no-subunit-trace', action='store_true', - default=False, - help='Disable the default subunit-trace output filter') - parser.add_argument('--color', action='store_true', default=False, - help='Enable color output in the subunit-trace output,' - ' if subunit-trace output is enabled. (this is ' - 'the default). If subunit-trace is disable this ' - ' does nothing.') - parser.add_argument('--abbreviate', action='store_true', - dest='abbreviate', - help='Print one character status for each test') - - -def get_cli_help(): - help_str = "Run the tests for a project and load them into a repository." - return help_str +class Run(command.Command): + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(Run, self).get_parser(prog_name) + parser.add_argument("filters", nargs="*", default=None, + help="A list of string regex filters to initially " + "apply on the test list. Tests that match any of " + "the regexes will be used. (assuming any other " + "filtering specified also uses it)") + parser.add_argument("--failing", action="store_true", + default=False, + help="Run only tests known to be failing.") + parser.add_argument("--serial", action="store_true", + default=False, + help="Run tests in a serial process.") + parser.add_argument("--concurrency", action="store", default=0, + help="How many processes to use. The default (0) " + "autodetects your CPU count.") + parser.add_argument("--load-list", default=None, + help="Only run tests listed in the named file."), + parser.add_argument("--partial", action="store_true", default=False, + help="Only some tests will be run. Implied by " + "--failing.") + parser.add_argument("--subunit", action="store_true", default=False, + help="Display results in subunit format.") + parser.add_argument("--until-failure", action="store_true", + default=False, + help="Repeat the run again and again until " + "failure occurs.") + parser.add_argument("--analyze-isolation", action="store_true", + default=False, + help="Search the last test run for 2-test test " + "isolation interactions.") + parser.add_argument("--isolated", action="store_true", + default=False, + help="Run each test id in a separate test runner.") + parser.add_argument("--worker-file", action="store", default=None, + dest='worker_path', + help="Optional path of a manual worker grouping " + "file to use for the run") + parser.add_argument('--blacklist-file', '-b', + default=None, dest='blacklist_file', + help='Path to a blacklist file, this file ' + 'contains a separate regex exclude on each ' + 'newline') + parser.add_argument('--whitelist-file', '-w', + default=None, dest='whitelist_file', + help='Path to a whitelist file, this file ' + 'contains a separate regex on each newline.') + parser.add_argument('--black-regex', '-B', default=None, + dest='black_regex', + help='Test rejection regex. If a test cases name ' + 'matches on re.search() operation , ' + 'it will be removed from the final test list. ' + 'Effectively the black-regexp is added to ' + ' black regexp list, but you do need to edit a ' + 'file. The black filtering happens after the ' + 'initial white selection, which by default is ' + 'everything.') + parser.add_argument('--no-discover', '-n', default=None, + metavar='TEST_ID', + help="Takes in a single test to bypasses test " + "discover and just execute the test specified. A " + "file may be used in place of a test name.") + parser.add_argument('--random', '-r', action="store_true", + default=False, + help="Randomize the test order after they are " + "partitioned into separate workers") + parser.add_argument('--combine', action='store_true', default=False, + help="Combine the results from the test run with " + "the last run in the repository") + parser.add_argument('--no-subunit-trace', action='store_true', + default=False, + help='Disable the default subunit-trace output ' + 'filter') + parser.add_argument('--color', action='store_true', default=False, + help='Enable color output in the subunit-trace ' + 'output, if subunit-trace output is enabled. ' + '(this is the default). If subunit-trace is ' + 'disable this does nothing.') + parser.add_argument('--abbreviate', action='store_true', + dest='abbreviate', + help='Print one character status for each test') + return parser + + def get_description(self): + help_str = "Run the tests for a project and load them into a " + "repository." + return help_str + + def take_action(self, parsed_args): + filters = parsed_args.filters + args = parsed_args + pretty_out = not args.no_subunit_trace + return run_command( + config=self.app_args.config, repo_type=self.app_args.repo_type, + repo_url=self.app_args.repo_url, + test_path=self.app_args.test_path, top_dir=self.app_args.top_dir, + group_regex=self.app_args.group_regex, failing=args.failing, + serial=args.serial, concurrency=args.concurrency, + load_list=args.load_list, partial=args.partial, + subunit_out=args.subunit, until_failure=args.until_failure, + analyze_isolation=args.analyze_isolation, isolated=args.isolated, + worker_path=args.worker_path, blacklist_file=args.blacklist_file, + whitelist_file=args.whitelist_file, black_regex=args.black_regex, + no_discover=args.no_discover, random=args.random, + combine=args.combine, + filters=filters, pretty_out=pretty_out, color=args.color, + abbreviate=args.abbreviate) def _find_failing(repo): @@ -508,23 +545,3 @@ def run_tests(): return result finally: cmd.cleanUp() - - -def run(arguments): - filters = arguments[1] or None - args = arguments[0] - pretty_out = not args.no_subunit_trace - - return run_command( - config=args.config, repo_type=args.repo_type, repo_url=args.repo_url, - test_path=args.test_path, top_dir=args.top_dir, - group_regex=args.group_regex, failing=args.failing, serial=args.serial, - concurrency=args.concurrency, load_list=args.load_list, - partial=args.partial, subunit_out=args.subunit, - until_failure=args.until_failure, - analyze_isolation=args.analyze_isolation, isolated=args.isolated, - worker_path=args.worker_path, blacklist_file=args.blacklist_file, - whitelist_file=args.whitelist_file, black_regex=args.black_regex, - no_discover=args.no_discover, random=args.random, combine=args.combine, - filters=filters, pretty_out=pretty_out, color=args.color, - abbreviate=args.abbreviate) diff --git a/stestr/commands/slowest.py b/stestr/commands/slowest.py index 7a822026..67910f8b 100644 --- a/stestr/commands/slowest.py +++ b/stestr/commands/slowest.py @@ -16,23 +16,33 @@ from operator import itemgetter import sys +from cliff import command + from stestr import output from stestr.repository import util -def get_cli_help(): - help_str = """Show the slowest tests from the last test run. +class Slowest(command.Command): + def get_description(self): + help_str = """Show the slowest tests from the last test run. - This command shows a table, with the longest running - tests at the top. - """ - return help_str + This command shows a table, with the longest running + tests at the top. + """ + return help_str + def get_parser(self, prog_name): + parser = super(Slowest, self).get_parser(prog_name) + parser.add_argument( + "--all", action="store_true", + default=False, help="Show timing for all tests.") + return parser -def set_cli_opts(parser): - parser.add_argument( - "--all", action="store_true", - default=False, help="Show timing for all tests."), + def take_action(self, parsed_args): + args = parsed_args + return slowest(repo_type=self.app_args.repo_type, + repo_url=self.app_args.repo_url, + show_all=args.all) def format_times(times): @@ -51,12 +61,6 @@ def format_time(time): return times -def run(arguments): - args = arguments[0] - return slowest(repo_type=args.repo_type, repo_url=args.repo_url, - show_all=args.all) - - def slowest(repo_type='file', repo_url=None, show_all=False, stdout=sys.stdout): """Print the slowest times from the last run in the repository diff --git a/stestr/tests/test_return_codes.py b/stestr/tests/test_return_codes.py index ee4f2de1..d3ebe99c 100644 --- a/stestr/tests/test_return_codes.py +++ b/stestr/tests/test_return_codes.py @@ -101,9 +101,6 @@ def test_until_failure_with_subunit_fails(self): def test_list(self): self.assertRunExit('stestr list', 0) - def test_no_command(self): - self.assertRunExit('stestr', 2) - def _get_cmd_stdout(self, cmd): p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)