Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions releasenotes/notes/wheel-path-enforce-baae211a3252a17a.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
``--wheel-path``/``RIOT_WHEEL_PATH`` now aborts the run if the wheel fails to
download or install, instead of silently falling back to an editable install.
This ensures that a specified wheel is always the one that gets used.
5 changes: 4 additions & 1 deletion riot/runner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
from pathlib import Path
import shlex
import subprocess
import sys
import tempfile
Expand Down Expand Up @@ -102,7 +103,7 @@ def install_dev_pkg(
logger.warning("No Python setup file found. Skipping dev package installation.")
return

find_links_flag = f"--find-links {wheel_path}" if wheel_path else ""
find_links_flag = f"--find-links {shlex.quote(wheel_path)}" if wheel_path else ""

# Determine installation method
if wheel_path:
Expand All @@ -129,6 +130,7 @@ def install_dev_pkg(
wheel_path,
e.proc.stdout,
)
sys.exit(1)

# Step 2: Install the downloaded wheel
install_cmd = f"pip --disable-pip-version-check install {find_links_flag} '{tmp_dir}'/*.whl"
Expand All @@ -137,6 +139,7 @@ def install_dev_pkg(
dev_pkg_lockfile.touch()
except CmdFailure as e:
logger.error("Wheel installation failed!\n%s", e.proc.stdout)
sys.exit(1)

if not dev_pkg_lockfile.exists():
# Install in editable mode (legacy behavior)
Expand Down
82 changes: 82 additions & 0 deletions tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,88 @@ def test_wheel_path_cli_option_passes_through(monkeypatch, tmp_path):
os.chdir(old_cwd)


def _make_cmd_failure():
from riot.exceptions import CmdFailure

proc = subprocess.CompletedProcess(args=["pip"], returncode=1, stdout="boom")
return CmdFailure("cmd failed", proc)


def test_install_dev_pkg_exits_when_wheel_download_fails(monkeypatch, tmp_path):
"""A failed wheel download must abort, never fall back to an editable install."""
from unittest.mock import patch

from riot.runner import install_dev_pkg

old_cwd = os.getcwd()
try:
os.chdir(tmp_path)
pathlib.Path("pyproject.toml").write_text('[project]\nname = "test-pkg"')

with patch("riot.runner.run_cmd_venv", side_effect=_make_cmd_failure()) as mock_run:
with pytest.raises(SystemExit) as exc_info:
install_dev_pkg(str(tmp_path / "venv"), force=True, wheel_path="/tmp/wheels")

assert exc_info.value.code == 1
# Only the download step should have been attempted -- no
# fallback `pip install -e .` call.
assert mock_run.call_count == 1
assert "download" in mock_run.call_args.args[1]
finally:
os.chdir(old_cwd)


def test_install_dev_pkg_exits_when_wheel_install_fails(monkeypatch, tmp_path):
"""A failed wheel install must abort, never fall back to an editable install."""
from unittest.mock import patch

from riot.runner import install_dev_pkg

old_cwd = os.getcwd()
try:
os.chdir(tmp_path)
pathlib.Path("pyproject.toml").write_text('[project]\nname = "test-pkg"')

# First call (download) succeeds, second call (install) fails.
with patch(
"riot.runner.run_cmd_venv", side_effect=[None, _make_cmd_failure()]
) as mock_run:
with pytest.raises(SystemExit) as exc_info:
install_dev_pkg(str(tmp_path / "venv"), force=True, wheel_path="/tmp/wheels")

assert exc_info.value.code == 1
assert mock_run.call_count == 2
assert "install" in mock_run.call_args.args[1]
finally:
os.chdir(old_cwd)


def test_install_dev_pkg_wheel_success_skips_editable_fallback(monkeypatch, tmp_path):
"""A successful wheel install must not also attempt an editable install."""
from unittest.mock import patch

from riot.runner import install_dev_pkg

old_cwd = os.getcwd()
try:
os.chdir(tmp_path)
pathlib.Path("pyproject.toml").write_text('[project]\nname = "test-pkg"')
venv_path = tmp_path / "venv"
venv_path.mkdir()

with patch("riot.runner.run_cmd_venv") as mock_run:
install_dev_pkg(str(venv_path), force=True, wheel_path="/tmp/wheels")

assert mock_run.call_count == 2
download_cmd, install_cmd = (c.args[1] for c in mock_run.call_args_list)
assert "download" in download_cmd
assert "install" in install_cmd
assert "-e ." not in install_cmd
assert (venv_path / ".riot-dev-pkg-installed").exists()
finally:
os.chdir(old_cwd)


def test_requirements_upgrades_compatible_pip_tools(
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
) -> None:
Expand Down
Loading