diff --git a/nox/__main__.py b/nox/__main__.py index 24fd8999..093d0f7b 100644 --- a/nox/__main__.py +++ b/nox/__main__.py @@ -57,6 +57,7 @@ def __init__(self, args): self.install_only = args.install_only self.posargs = args.posargs self.report = args.report + self.color = not args.nocolor or args.forcecolor if self.posargs and self.posargs[0] == "--": self.posargs.pop(0) @@ -242,7 +243,7 @@ def main(): return global_config = GlobalConfig(args) - setup_logging(color=not args.nocolor or args.forcecolor) + setup_logging(color=global_config.color) # Execute the appropriate tasks. exit_code = workflow.execute( diff --git a/nox/manifest.py b/nox/manifest.py index 534367c9..ec29ea89 100644 --- a/nox/manifest.py +++ b/nox/manifest.py @@ -94,6 +94,11 @@ def __next__(self): def __len__(self): return len(self._queue) + len(self._consumed) + def list_all_sessions(self): + """Yields all sessions and whether or not they're selected.""" + for session in self._all_sessions: + yield session, session in self._queue + def add_session(self, session): """Add the given session to the manifest. diff --git a/nox/tasks.py b/nox/tasks.py index f392f65c..5256b429 100644 --- a/nox/tasks.py +++ b/nox/tasks.py @@ -17,6 +17,8 @@ import json import os +from colorlog.escape_codes import parse_colors + from nox import _options from nox import registry from nox.logger import logger @@ -132,21 +134,47 @@ def honor_list_request(manifest, global_config): Union[~.Manifest,int]: ``0`` if a listing is all that is requested, the manifest otherwise (to be sent to the next task). """ + if not global_config.list_sessions: + return manifest + # If the user just asked for a list of sessions, print that # and be done. - if global_config.list_sessions: - print("Available sessions:") - for session in manifest: - output = "* {session}" - if session.description is not None: - output += " -> {description}" - print( - output.format( - session=session.friendly_name, description=session.description - ) + + print("Sessions defined in {noxfile}:\n".format(noxfile=global_config.noxfile)) + + reset = parse_colors("reset") if global_config.color else "" + selected_color = parse_colors("cyan") if global_config.color else "" + skipped_color = parse_colors("white") if global_config.color else "" + + for session, selected in manifest.list_all_sessions(): + output = "{marker} {color}{session}{reset}" + + if selected: + marker = "*" + color = selected_color + else: + marker = "-" + color = skipped_color + + if session.description is not None: + output += " -> {description}" + + print( + output.format( + color=color, + reset=reset, + session=session.friendly_name, + description=session.description, + marker=marker, ) - return 0 - return manifest + ) + + print( + "\nsessions marked with {selected_color}*{reset} are selected, sessions marked with {skipped_color}-{reset} are skipped.".format( + selected_color=selected_color, skipped_color=skipped_color, reset=reset + ) + ) + return 0 def verify_manifest_nonempty(manifest, global_config): diff --git a/tests/test_main.py b/tests/test_main.py index 5c436522..861d6a8d 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -51,6 +51,8 @@ def make_args(self): install_only=False, posargs=["a", "b", "c"], report=None, + nocolor=False, + forcecolor=False, ) def test_constructor(self): diff --git a/tests/test_manifest.py b/tests/test_manifest.py index d679e8f7..a5a95136 100644 --- a/tests/test_manifest.py +++ b/tests/test_manifest.py @@ -148,6 +148,19 @@ def test_filter_by_keyword(): assert len(manifest) == 1 +def test_list_all_sessions_with_filter(): + sessions = create_mock_sessions() + manifest = Manifest(sessions, mock.sentinel.CONFIG) + assert len(manifest) == 2 + manifest.filter_by_keywords("foo") + assert len(manifest) == 1 + all_sessions = list(manifest.list_all_sessions()) + assert len(all_sessions) == 2 + # Only one should be marked as selected. + assert all_sessions[0][1] is True + assert all_sessions[1][1] is False + + def test_add_session_plain(): manifest = Manifest({}, mock.sentinel.CONFIG) session_func = mock.Mock(spec=(), python=None) diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 12522661..c4d32d41 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -127,11 +127,30 @@ def test_honor_list_request_noop(): @pytest.mark.parametrize("description", [None, "bar"]) def test_honor_list_request(description): - config = argparse.Namespace(list_sessions=True) - manifest = [argparse.Namespace(friendly_name="foo", description=description)] + config = argparse.Namespace(list_sessions=True, noxfile="noxfile.py", color=False) + manifest = mock.create_autospec(Manifest) + manifest.list_all_sessions.return_value = [ + (argparse.Namespace(friendly_name="foo", description=description), True) + ] + return_value = tasks.honor_list_request(manifest, global_config=config) + assert return_value == 0 + + +def test_honor_list_request_skip_and_selected(capsys): + config = argparse.Namespace(list_sessions=True, noxfile="noxfile.py", color=False) + manifest = mock.create_autospec(Manifest) + manifest.list_all_sessions.return_value = [ + (argparse.Namespace(friendly_name="foo", description=None), True), + (argparse.Namespace(friendly_name="bar", description=None), False), + ] return_value = tasks.honor_list_request(manifest, global_config=config) assert return_value == 0 + out = capsys.readouterr().out + + assert "* foo" in out + assert "- bar" in out + def test_verify_manifest_empty(): config = argparse.Namespace(sessions=(), keywords=())