Skip to content

Commit

Permalink
Add support for a user config file
Browse files Browse the repository at this point in the history
This commit adds a new feature, the user config file. This enables users
to write a global config file for UI preferences on certain commands
that will be the new default for that option. For example, if you prefer
the default output on the 'stestr run' command to be with the
--no-subunit-trace flag set. You can just write a user config file to
set this output. Then for all stestr run invocations the default output
will be with --no-subunit-trace set.
  • Loading branch information
mtreinish committed Feb 19, 2018
1 parent 4f525ed commit a295e89
Show file tree
Hide file tree
Showing 9 changed files with 409 additions and 13 deletions.
36 changes: 36 additions & 0 deletions doc/source/MANUAL.rst
Expand Up @@ -354,6 +354,42 @@ There is also an option on ``stestr run``, ``--random``/``-r`` to randomize the
order of tests as they are passed to the workers. This is useful in certain
use cases, especially when you want to test isolation between test cases.


User Config Files
-----------------

If you prefer to have a different default output or setting for a particular
command stestr enables you to write a user config file to overide the defaults
for some options on some commands. By default stestr will look for this config
file in ``~/.stestr.yaml`` and ``~/.config/stestr.yaml`` in that order. You
can also specify the path to a config file with the ``--user-config``
parameter.

The config file is a yaml file that has a top level key for the command and
then a sub key for each option. For an example, a fully populated config file
that changes the default on all available options in the config file is::

run:
concurrency: 42 # This can be any integer value >= 0
random: True
no-subunit-trace: True
color: True
abbreviate: True
slowest: True
failing:
list: True
last:
no-subunit-trace: True
color: True
load:
force-init: True
subunit-trace: True
color: True
abbreviate: True

If you choose to use a user config file you can specify any subset of the
options and commands you choose.

Automated test isolation bisection
----------------------------------

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -9,3 +9,4 @@ fixtures>=3.0.0 # Apache-2.0/BSD
six>=1.10.0 # MIT
testtools>=2.2.0 # MIT
PyYAML>=3.10.0 # MIT
voluptuous>=0.8.9 # BSD License
5 changes: 5 additions & 0 deletions stestr/cli.py
Expand Up @@ -48,6 +48,11 @@ def build_option_parser(self, description, version, argparse_kwargs=None):
return parser

def _set_common_opts(self, parser):
parser.add_argument('--user-config', dest='user_config', default=None,
help='An optional path to a default user config '
'file if one is not specified ~/.stestr.yaml '
'and ~/.config/stestr.yaml will be tried in '
'that order')
parser.add_argument('-d', '--here', dest='here',
help="Set the directory or url that a command "
"should run from. This affects all default "
Expand Down
8 changes: 7 additions & 1 deletion stestr/commands/failing.py
Expand Up @@ -20,6 +20,7 @@
from stestr import output
from stestr.repository import util
from stestr import results
from stestr import user_config


class Failing(command.Command):
Expand All @@ -37,10 +38,15 @@ def get_parser(self, prog_name):
return parser

def take_action(self, parsed_args):
user_conf = user_config.get_user_config(self.app_args.user_config)
args = parsed_args
if getattr(user_conf, 'failing', False):
list_opt = args.list or user_conf.failing.get('list', False)
else:
list_opt = args.list
return failing(repo_type=self.app_args.repo_type,
repo_url=self.app_args.repo_url,
list_tests=args.list, subunit=args.subunit)
list_tests=list_opt, subunit=args.subunit)


def _show_subunit(run):
Expand Down
22 changes: 20 additions & 2 deletions stestr/commands/last.py
Expand Up @@ -21,6 +21,7 @@
from stestr.repository import util
from stestr import results
from stestr import subunit_trace
from stestr import user_config


class Last(command.Command):
Expand All @@ -45,6 +46,10 @@ def get_parser(self, prog_name):
default=False,
help="Disable output with the subunit-trace "
"output filter")
parser.add_argument('--force-subunit-trace', action='store_true',
default=False,
help='Force subunit-trace output regardless of any'
'other options or config settings')
parser.add_argument('--color', action='store_true', default=False,
help='Enable color output in the subunit-trace '
'output, if subunit-trace output is enabled. '
Expand All @@ -53,12 +58,25 @@ def get_parser(self, prog_name):
return parser

def take_action(self, parsed_args):
user_conf = user_config.get_user_config(self.app_args.user_config)
args = parsed_args
pretty_out = not args.no_subunit_trace
if getattr(user_conf, 'last', False):
if not user_conf.last.get('no-subunit-trace'):
if not args.no_subunit_trace:
pretty_out = True
else:
pretty_out = False
else:
pretty_out = False
pretty_out = args.force_subunit_trace or pretty_out
color = args.color or user_conf.last.get('color', False)
else:
pretty_out = args.force_subunit_trace or not args.no_subunit_trace
color = args.color
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)
color=color)


def last(repo_type='file', repo_url=None, subunit_out=False, pretty_out=True,
Expand Down
21 changes: 18 additions & 3 deletions stestr/commands/load.py
Expand Up @@ -28,6 +28,7 @@
from stestr.repository import util
from stestr import results
from stestr import subunit_trace
from stestr import user_config
from stestr import utils


Expand Down Expand Up @@ -73,15 +74,29 @@ def get_description(self):
return help_str

def take_action(self, parsed_args):
user_conf = user_config.get_user_config(self.app_args.user_config)
args = parsed_args
if getattr(user_conf, 'load', False):
force_init = args.force_init or user_conf.load.get('force-init',
False)
pretty_out = args.subunit_trace or user_conf.load.get(
'subunit-trace', False)
color = args.color or user_conf.load.get('color', False)
abbreviate = args.abbreviate or user_conf.load.get('abbreviate',
False)
else:
force_init = args.force_init
pretty_out = args.subunit_trace
color = args.color
abbreviate = args.abbreviate
verbose_level = self.app.options.verbose_level
stdout = open(os.devnull, 'w') if verbose_level == 0 else sys.stdout
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,
stdout=stdout, abbreviate=args.abbreviate)
force_init=force_init, streams=args.files,
pretty_out=pretty_out, color=color,
stdout=stdout, abbreviate=abbreviate)


def load(force_init=False, in_streams=None,
Expand Down
47 changes: 40 additions & 7 deletions stestr/commands/run.py
Expand Up @@ -30,6 +30,7 @@
from stestr.repository import abstract as repository
from stestr.repository import util
from stestr.testlist import parse_list
from stestr import user_config


class Run(command.Command):
Expand All @@ -46,7 +47,8 @@ def get_parser(self, prog_name):
parser.add_argument("--serial", action="store_true",
default=False,
help="Run tests in a serial process.")
parser.add_argument("--concurrency", action="store", default=0,
parser.add_argument("--concurrency", action="store", default=None,
type=int,
help="How many processes to use. The default (0) "
"autodetects your CPU count.")
parser.add_argument("--load-list", default=None,
Expand Down Expand Up @@ -108,6 +110,10 @@ def get_parser(self, prog_name):
default=False,
help='Disable the default subunit-trace output '
'filter')
parser.add_argument('--force-subunit-trace', action='store_true',
default=False,
help='Force subunit-trace output regardless of any'
'other options or config settings')
parser.add_argument('--color', action='store_true', default=False,
help='Enable color output in the subunit-trace '
'output, if subunit-trace output is enabled. '
Expand All @@ -127,30 +133,57 @@ def get_description(self):
return help_str

def take_action(self, parsed_args):
user_conf = user_config.get_user_config(self.app_args.user_config)
filters = parsed_args.filters
args = parsed_args
pretty_out = not args.no_subunit_trace
if getattr(user_conf, 'run', False):
if not user_conf.run.get('no-subunit-trace'):
if not args.no_subunit_trace:
pretty_out = True
else:
pretty_out = False
else:
pretty_out = False

pretty_out = args.force_subunit_trace or pretty_out
if args.concurrency is None:
concurrency = user_conf.run.get('concurrency', 0)
else:
concurrency = args.concurrency
random = args.random or user_conf.run.get('random', False)
color = args.color or user_conf.run.get('color', False)
abbreviate = args.abbreviate = user_conf.run.get(
'abbreviate', False)
else:
pretty_out = args.force_subunit_trace or not args.no_subunit_trace
concurrency = args.concurrency or 0
random = args.random
color = args.color
abbreviate = args.abbreviate
verbose_level = self.app.options.verbose_level
stdout = open(os.devnull, 'w') if verbose_level == 0 else sys.stdout
result = 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,
serial=args.serial, concurrency=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,
no_discover=args.no_discover, random=random,
combine=args.combine,
filters=filters, pretty_out=pretty_out, color=args.color,
stdout=stdout, abbreviate=args.abbreviate)
filters=filters, pretty_out=pretty_out, color=color,
stdout=stdout, abbreviate=abbreviate)

# Always output slowest test info if requested, regardless of other
# test run options
if args.slowest:
user_slowest = False
if getattr(user_conf, 'run', False):
user_slowest = user_conf.run.get('slowest', False)
if args.slowest or user_slowest:
slowest.slowest(repo_type=args.repo_type, repo_url=args.repo_url)

return result
Expand Down

0 comments on commit a295e89

Please sign in to comment.