summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMasen Furer <m_github@0x26.net>2023-01-16 14:08:26 -0800
committerGitHub <noreply@github.com>2023-01-16 14:08:26 -0800
commite4c65bb1fef704aadc6192679f21a55dfeee9c62 (patch)
tree82b4a7637212019e4a9b8071d91af8cb23cb57dc
parenta2222e98b320467e821cf9444113e9b40ab3ad1b (diff)
downloadtox-git-e4c65bb1fef704aadc6192679f21a55dfeee9c62.tar.gz
Provision: ignore other test environments (#2865)
Fix https://github.com/tox-dev/tox/issues/2862
-rw-r--r--docs/changelog/2862.bugfix.rst4
-rw-r--r--docs/upgrading.rst7
-rw-r--r--src/tox/provision.py3
-rw-r--r--src/tox/session/env_select.py13
-rw-r--r--tests/demo_pkg_inline/build.py27
-rw-r--r--tests/test_provision.py25
6 files changed, 72 insertions, 7 deletions
diff --git a/docs/changelog/2862.bugfix.rst b/docs/changelog/2862.bugfix.rst
new file mode 100644
index 00000000..c52228ff
--- /dev/null
+++ b/docs/changelog/2862.bugfix.rst
@@ -0,0 +1,4 @@
+The provision environment (``.tox``) will never inherit from ``testenv``.
+During provisioning, other test environments are not processed, allowing the
+use of keys and values that may be registered by later tox version or
+provisioned plugins - by :user:`masenf`.
diff --git a/docs/upgrading.rst b/docs/upgrading.rst
index 90b2c550..b44fae87 100644
--- a/docs/upgrading.rst
+++ b/docs/upgrading.rst
@@ -317,3 +317,10 @@ version is above the version this feature was added to it, for example for setup
[testenv:dev]
deps = setuptools>=64
package = editable
+
+Provisioning environment
+------------------------
+
+The provisioning environment is triggered when ``minversion`` or ``requires`` are specified and the current environment
+does not satisfy the requirement. In tox 4, the provisioning environment (``.tox`` by default) must be explicitly
+configured and will not inherit values from ``[testenv]`` section.
diff --git a/src/tox/provision.py b/src/tox/provision.py
index 34b56d07..9b1aeba5 100644
--- a/src/tox/provision.py
+++ b/src/tox/provision.py
@@ -97,7 +97,8 @@ def provision(state: State) -> int | bool:
recreate=state.conf.options.recreate and not state.conf.options.no_recreate_provision,
)
provision_tox_env: str = state.conf.core["provision_tox_env"]
- state.envs._mark_provision(bool(missing), provision_tox_env, loader)
+ state.conf.memory_seed_loaders[provision_tox_env].append(loader)
+ state.envs._mark_provision(bool(missing), provision_tox_env)
from tox.plugin.manager import MANAGER
diff --git a/src/tox/session/env_select.py b/src/tox/session/env_select.py
index f926beda..52f11953 100644
--- a/src/tox/session/env_select.py
+++ b/src/tox/session/env_select.py
@@ -13,7 +13,6 @@ from tox.tox_env.api import ToxEnvCreateArgs
from tox.tox_env.register import REGISTER
from tox.tox_env.runner import RunToxEnv
-from ..config.loader.memory import MemoryLoader
from ..config.types import EnvList
from ..report import HandledError
from ..tox_env.errors import Skip
@@ -134,7 +133,7 @@ class EnvSelector:
self._manager = MANAGER
self._log_handler = self._state._options.log_handler
self._journal = self._state._journal
- self._provision: None | tuple[bool, str, MemoryLoader] = None
+ self._provision: None | tuple[bool, str] = None
self._state.conf.core.add_config("labels", Dict[str, EnvList], {}, "core labels")
tox_env_filter_regex = getattr(state.conf.options, "skip_env", "").strip()
@@ -242,10 +241,12 @@ class EnvSelector:
def _build_run_env(self, name: str) -> RunToxEnv | None:
if self._provision is not None and self._provision[0] is False and name == self._provision[1]:
+ # ignore provision env unless this is a provision run
+ return None
+ if self._provision is not None and self._provision[0] and name != self._provision[1]:
+ # ignore other envs when this is a provision run
return None
env_conf = self._state.conf.get_env(name, package=False)
- if self._provision is not None and self._provision[1] == name:
- env_conf.loaders.insert(0, self._provision[2])
desc = "the tox execute used to evaluate this environment"
env_conf.add_config(keys="runner", desc=desc, of_type=str, default=self._state.conf.options.default_runner)
runner = REGISTER.runner(cast(str, env_conf["runner"]))
@@ -367,8 +368,8 @@ class EnvSelector:
if invalid:
raise HandledError(f"cannot run packaging environment(s) {','.join(invalid)}")
- def _mark_provision(self, on: bool, provision_tox_env: str, loader: MemoryLoader) -> None:
- self._provision = on, provision_tox_env, loader
+ def _mark_provision(self, on: bool, provision_tox_env: str) -> None:
+ self._provision = on, provision_tox_env
__all__ = [
diff --git a/tests/demo_pkg_inline/build.py b/tests/demo_pkg_inline/build.py
index 35e22f03..47df3a3d 100644
--- a/tests/demo_pkg_inline/build.py
+++ b/tests/demo_pkg_inline/build.py
@@ -14,11 +14,38 @@ pkg_name = name.replace("_", "-")
version = "1.0.0"
dist_info = "{}-{}.dist-info".format(name, version)
logic = "{}/__init__.py".format(name)
+plugin = "{}/example_plugin.py".format(name)
+entry_points = "{}/entry_points.txt".format(dist_info)
metadata = "{}/METADATA".format(dist_info)
wheel = "{}/WHEEL".format(dist_info)
record = "{}/RECORD".format(dist_info)
content = {
logic: "def do():\n print('greetings from {}')".format(name),
+ plugin: dedent(
+ """
+ try:
+ from tox.plugin import impl
+ from tox.tox_env.python.virtual_env.runner import VirtualEnvRunner
+ from tox.tox_env.register import ToxEnvRegister
+ except ImportError:
+ pass
+ else:
+ class ExampleVirtualEnvRunner(VirtualEnvRunner):
+ @staticmethod
+ def id() -> str:
+ return "example"
+ @impl
+ def tox_register_tox_env(register: ToxEnvRegister) -> None:
+ register.add_run_env(ExampleVirtualEnvRunner)
+ """,
+ ),
+ entry_points: dedent(
+ """
+ [tox]
+ example = {}.example_plugin""".format(
+ name,
+ ),
+ ),
metadata: """
Metadata-Version: 2.1
Name: {}
diff --git a/tests/test_provision.py b/tests/test_provision.py
index c7a7fac2..91d7689d 100644
--- a/tests/test_provision.py
+++ b/tests/test_provision.py
@@ -187,3 +187,28 @@ def test_provision_no_recreate_json(tox_project: ToxProjectCreator) -> None:
with (project.path / "out.json").open() as file_handler:
requires = json.load(file_handler)
assert requires == {"minversion": None, "requires": ["p", "tox"]}
+
+
+@pytest.mark.integration()
+@pytest.mark.usefixtures("_pypi_index_self")
+@pytest.mark.parametrize("plugin_testenv", ["testenv", "testenv:a"])
+def test_provision_plugin_runner(tox_project: ToxProjectCreator, tmp_path: Path, plugin_testenv: str) -> None:
+ """Ensure that testenv runner doesn't affect the provision env."""
+ log = tmp_path / "out.log"
+ proj = tox_project({"tox.ini": f"[tox]\nrequires=demo-pkg-inline\n[{plugin_testenv}]\nrunner=example"})
+ result_first = proj.run("r", "-e", "py", "--result-json", str(log))
+ result_first.assert_success()
+ prov_msg = (
+ f"ROOT: will run in automatically provisioned tox, host {sys.executable} is missing"
+ f" [requires (has)]: demo-pkg-inline"
+ )
+ assert prov_msg in result_first.out
+
+
+@pytest.mark.integration()
+def test_provision_plugin_runner_in_provision(tox_project: ToxProjectCreator, tmp_path: Path) -> None:
+ """Ensure that provision environment can be explicitly configured."""
+ log = tmp_path / "out.log"
+ proj = tox_project({"tox.ini": "[tox]\nrequires=somepkg123xyz\n[testenv:.tox]\nrunner=example"})
+ with pytest.raises(KeyError, match="example"):
+ proj.run("r", "-e", "py", "--result-json", str(log))