diff --git a/nox/_options.py b/nox/_options.py index b7548499..a0cf8ce2 100644 --- a/nox/_options.py +++ b/nox/_options.py @@ -414,6 +414,16 @@ def _tag_completer( help="Adds a timestamp to logged output.", noxfile=True, ), + _option_set.Option( + "max_log_args", + "-ma", + "--max-log-args", + group=options.groups["reporting"], + default=None, + type=int, + help="Set a limit on the maximum number of arguments that are logged.", + noxfile=True, + ), _option_set.Option( "default_venv_backend", "-db", diff --git a/nox/command.py b/nox/command.py index 4f948e6e..b79d24b8 100644 --- a/nox/command.py +++ b/nox/command.py @@ -73,8 +73,21 @@ def _clean_env(env: Mapping[str, str | None] | None = None) -> dict[str, str] | return clean_env -def _shlex_join(args: Sequence[str | os.PathLike[str]]) -> str: - return " ".join(shlex.quote(os.fspath(arg)) for arg in args) +def _get_cmd_for_log( + max_log_args: int | None, + cmd: str | os.PathLike[str], + args: Sequence[str | os.PathLike[str]], +) -> str: + num_more_args = len(args) - (max_log_args or 0) + args = args[:max_log_args] + output_list = [str(cmd)] + if args: + output_list.extend(shlex.quote(os.fspath(arg)) for arg in args) + if (max_log_args is not None) and num_more_args > 0: + more_note = "more " if max_log_args > 0 else "" + args_note = "arguments" if num_more_args > 1 else "argument" + output_list.append(f"... ({num_more_args} {more_note}{args_note})") + return " ".join(output_list) def run( @@ -85,6 +98,7 @@ def run( paths: Sequence[str] | None = None, success_codes: Iterable[int] | None = None, log: bool = True, + max_log_args: int | None = None, external: ExternalType = False, stdout: int | IO[str] | None = None, stderr: int | IO[str] = subprocess.STDOUT, @@ -97,7 +111,7 @@ def run( success_codes = [0] cmd, args = args[0], args[1:] - full_cmd = f"{cmd} {_shlex_join(args)}" + full_cmd = _get_cmd_for_log(max_log_args, cmd, args) cmd_path = which(os.fspath(cmd), paths) str_args = [os.fspath(arg) for arg in args] diff --git a/nox/sessions.py b/nox/sessions.py index 4f5d2805..a6a66de8 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -593,6 +593,7 @@ def _run( silent=silent, success_codes=success_codes, log=log, + max_log_args=self._runner.global_config.max_log_args, external=external, stdout=stdout, stderr=stderr, diff --git a/tests/test_command.py b/tests/test_command.py index ae398e96..0782a721 100644 --- a/tests/test_command.py +++ b/tests/test_command.py @@ -121,6 +121,19 @@ def test_run_verbosity_failed_command(capsys, caplog): assert not logs +def test__get_cmd_for_log(): + get_cmd_for_log = nox.command._get_cmd_for_log + assert get_cmd_for_log(None, "test", []) == "test" + assert get_cmd_for_log(1, "test", []) == "test" + arg_list = ["a", "b", "c"] + assert get_cmd_for_log(None, "test", arg_list) == "test a b c" + assert get_cmd_for_log(4, "test", arg_list) == "test a b c" + assert get_cmd_for_log(3, "test", arg_list) == "test a b c" + assert get_cmd_for_log(2, "test", arg_list) == "test a b ... (1 more argument)" + assert get_cmd_for_log(1, "test", arg_list) == "test a ... (2 more arguments)" + assert get_cmd_for_log(0, "test", arg_list) == "test ... (3 arguments)" + + @pytest.mark.skipif( platform.system() == "Windows", reason="See https://github.com/python/cpython/issues/85815", diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 90b0caf6..1868f66c 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -47,6 +47,7 @@ def run_with_defaults(**kwargs): "paths": None, "success_codes": None, "log": True, + "max_log_args": None, "external": False, "stdout": None, "stderr": subprocess.STDOUT,