From 5b0f8946c89474eed803fbf40f27c846f1b35f1e Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 8 Feb 2022 07:45:33 +0000 Subject: [PATCH 1/6] Missing interpreters on CI now fail the session by default --- nox/sessions.py | 6 +++++- tests/test_sessions.py | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/nox/sessions.py b/nox/sessions.py index 0ca37eb4..86a75055 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -688,9 +688,13 @@ def execute(self) -> Result: return Result(self, Status.SUCCESS) except nox.virtualenv.InterpreterNotFound as exc: - if self.global_config.error_on_missing_interpreters: + if self.global_config.error_on_missing_interpreters or "CI" in os.environ: return Result(self, Status.FAILED, reason=str(exc)) else: + logger.warning( + "Missing interpreters will error by default on CI systems." + " Use `--error-on-missing-interpreters` to emulate this behaviour." + ) return Result(self, Status.SKIPPED, reason=str(exc)) except _SessionQuit as exc: diff --git a/tests/test_sessions.py b/tests/test_sessions.py index dad453b0..5d0f2678 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -901,7 +901,7 @@ def test_execute_with_manifest_null_session_func(self): assert result.status == nox.sessions.Status.SKIPPED assert "no parameters" in result.reason - def test_execute_skip_missing_interpreter(self): + def test_execute_skip_missing_interpreter(self, caplog): runner = self.make_runner_with_mock_venv() runner._create_venv.side_effect = nox.virtualenv.InterpreterNotFound("meep") @@ -909,6 +909,19 @@ def test_execute_skip_missing_interpreter(self): assert result.status == nox.sessions.Status.SKIPPED assert "meep" in result.reason + assert ( + "Missing interpreters will error by default on CI systems." in caplog.text + ) + + def test_execute_missing_interpreter_on_CI(self): + runner = self.make_runner_with_mock_venv() + runner._create_venv.side_effect = nox.virtualenv.InterpreterNotFound("meep") + + with mock.patch.dict(os.environ, {"CI": True}): + result = runner.execute() + + assert result.status == nox.sessions.Status.FAILED + assert "meep" in result.reason def test_execute_error_missing_interpreter(self): runner = self.make_runner_with_mock_venv() From d86ed1614e5149ef8becf6f841f190363eb01720 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 8 Feb 2022 08:00:58 +0000 Subject: [PATCH 2/6] Patch CI env var on actual CI --- tests/test_sessions.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 5d0f2678..5c61407a 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -901,9 +901,10 @@ def test_execute_with_manifest_null_session_func(self): assert result.status == nox.sessions.Status.SKIPPED assert "no parameters" in result.reason - def test_execute_skip_missing_interpreter(self, caplog): + def test_execute_skip_missing_interpreter(self, caplog, monkeypatch): runner = self.make_runner_with_mock_venv() runner._create_venv.side_effect = nox.virtualenv.InterpreterNotFound("meep") + monkeypatch.delenv("CI", raising=False) result = runner.execute() @@ -913,12 +914,12 @@ def test_execute_skip_missing_interpreter(self, caplog): "Missing interpreters will error by default on CI systems." in caplog.text ) - def test_execute_missing_interpreter_on_CI(self): + def test_execute_missing_interpreter_on_CI(self, monkeypatch): runner = self.make_runner_with_mock_venv() runner._create_venv.side_effect = nox.virtualenv.InterpreterNotFound("meep") + monkeypatch.setenv("CI", "True") - with mock.patch.dict(os.environ, {"CI": True}): - result = runner.execute() + result = runner.execute() assert result.status == nox.sessions.Status.FAILED assert "meep" in result.reason From 978c22f414409ebb06a85b29d485f9412b6a3b1d Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 8 Feb 2022 16:41:38 +0000 Subject: [PATCH 3/6] Shorten warning message and add mention in docs --- docs/usage.rst | 4 +++- nox/sessions.py | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index 1309a841..e9b0c3aa 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -218,7 +218,7 @@ If the Noxfile sets ``nox.options.stop_on_first_error``, you can override the No Failing sessions when the interpreter is missing ------------------------------------------------ -By default, Nox will skip sessions where the Python interpreter can't be found. If you want Nox to mark these sessions as failed, you can use ``--error-on-missing-interpreters``: +By default, when not on CI, Nox will skip sessions where the Python interpreter can't be found. If you want Nox to mark these sessions as failed, you can use ``--error-on-missing-interpreters``: .. code-block:: console @@ -226,6 +226,8 @@ By default, Nox will skip sessions where the Python interpreter can't be found. If the Noxfile sets ``nox.options.error_on_missing_interpreters``, you can override the Noxfile setting from the command line by using ``--no-error-on-missing-interpreters``. +If being run on Continuous Integration (CI) systems, Nox will treat missing interpreters as errors by default to avoid sessions silently passing when the requested python interpreter is not installed. Nox does this by looking for an environment variable called ``CI`` which is a convention used by most CI providers. + .. _opt-error-on-external-run: Disallowing external programs diff --git a/nox/sessions.py b/nox/sessions.py index cc347ac0..7f234453 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -696,7 +696,6 @@ def execute(self) -> Result: else: logger.warning( "Missing interpreters will error by default on CI systems." - " Use `--error-on-missing-interpreters` to emulate this behaviour." ) return Result(self, Status.SKIPPED, reason=str(exc)) From 1bbdc11ce8d9f6a183522548ef15983eec0283e7 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 12 Feb 2022 20:15:12 +0000 Subject: [PATCH 4/6] Make CI only set the default for error-on-missing-interpreters --- nox/_option_set.py | 2 ++ nox/_options.py | 1 + nox/sessions.py | 2 +- tests/test_sessions.py | 4 ++-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/nox/_option_set.py b/nox/_option_set.py index 6c2ba62a..1656860b 100644 --- a/nox/_option_set.py +++ b/nox/_option_set.py @@ -157,6 +157,7 @@ def make_flag_pair( name: str, enable_flags: tuple[str, str] | tuple[str], disable_flags: tuple[str], + default: bool = False, **kwargs: Any, ) -> tuple[Option, Option]: """Returns two options - one to enable a behavior and another to disable it. @@ -172,6 +173,7 @@ def make_flag_pair( *enable_flags, noxfile=True, merge_func=functools.partial(flag_pair_merge_func, name, disable_name), + default=default, **kwargs, ) diff --git a/nox/_options.py b/nox/_options.py index bdb032b5..39ca1ccb 100644 --- a/nox/_options.py +++ b/nox/_options.py @@ -419,6 +419,7 @@ def _session_completer( ("--no-error-on-missing-interpreters",), group=options.groups["execution"], help="Error instead of skipping sessions if an interpreter can not be located.", + default=True if "CI" in os.environ else False, ), *_option_set.make_flag_pair( "error_on_external_run", diff --git a/nox/sessions.py b/nox/sessions.py index 7f234453..75fb6716 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -691,7 +691,7 @@ def execute(self) -> Result: return Result(self, Status.SUCCESS) except nox.virtualenv.InterpreterNotFound as exc: - if self.global_config.error_on_missing_interpreters or "CI" in os.environ: + if self.global_config.error_on_missing_interpreters: return Result(self, Status.FAILED, reason=str(exc)) else: logger.warning( diff --git a/tests/test_sessions.py b/tests/test_sessions.py index d12698eb..ad648a4e 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -749,7 +749,7 @@ def make_runner(self): envdir="envdir", posargs=[], reuse_existing_virtualenvs=False, - error_on_missing_interpreters=False, + error_on_missing_interpreters=True if "CI" in os.environ else False, ), manifest=mock.create_autospec(nox.manifest.Manifest), ) @@ -918,9 +918,9 @@ def test_execute_skip_missing_interpreter(self, caplog, monkeypatch): ) def test_execute_missing_interpreter_on_CI(self, monkeypatch): + monkeypatch.setenv("CI", "True") runner = self.make_runner_with_mock_venv() runner._create_venv.side_effect = nox.virtualenv.InterpreterNotFound("meep") - monkeypatch.setenv("CI", "True") result = runner.execute() From 64ebe2ff72f668a8ee62c02e87ed3cfad1db9e57 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 12 Feb 2022 20:23:17 +0000 Subject: [PATCH 5/6] Fix failing test --- tests/test_sessions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index ad648a4e..bcce12aa 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -905,9 +905,12 @@ def test_execute_with_manifest_null_session_func(self): assert "no parameters" in result.reason def test_execute_skip_missing_interpreter(self, caplog, monkeypatch): + # Important to have this first here as the runner will pick it up + # to set default for --error-on-missing-interpreters + monkeypatch.delenv("CI", raising=False) + runner = self.make_runner_with_mock_venv() runner._create_venv.side_effect = nox.virtualenv.InterpreterNotFound("meep") - monkeypatch.delenv("CI", raising=False) result = runner.execute() From a761df4c01e3d68c2faee756b8ffc3a4bfe92a9d Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 13 Feb 2022 12:01:03 +0000 Subject: [PATCH 6/6] Apply suggestions from code review --- nox/_options.py | 2 +- tests/test_sessions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nox/_options.py b/nox/_options.py index 39ca1ccb..b61c41cd 100644 --- a/nox/_options.py +++ b/nox/_options.py @@ -419,7 +419,7 @@ def _session_completer( ("--no-error-on-missing-interpreters",), group=options.groups["execution"], help="Error instead of skipping sessions if an interpreter can not be located.", - default=True if "CI" in os.environ else False, + default="CI" in os.environ, ), *_option_set.make_flag_pair( "error_on_external_run", diff --git a/tests/test_sessions.py b/tests/test_sessions.py index bcce12aa..a71d1f94 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -749,7 +749,7 @@ def make_runner(self): envdir="envdir", posargs=[], reuse_existing_virtualenvs=False, - error_on_missing_interpreters=True if "CI" in os.environ else False, + error_on_missing_interpreters="CI" in os.environ, ), manifest=mock.create_autospec(nox.manifest.Manifest), )