Public Access
The v0.49.x tag line diverged from origin/master, leaving many features only accessible via tags but not on the master branch. New modules: - ci/cancel_superseded_runs.py — cancel superseded CI runs - ci/check_workflow_artifact_deps.py — validate artifact deps - ci/check_workflow_tofu_init.py — validate tofu init steps - tools/check_alert_rules.py — validate Prometheus alert rules - tools/check_ansible_set_fact_to_json.py — lint set_fact usage - tools/check_docker_init.py — validate Docker init scripts - utils/jinja.py — Jinja2 template utilities - utils/ui.py — UI/console utilities Modified modules: - distribute_molecule.py: add --include-roles/--exclude-roles - utils/api.py: add container.credentials for private registry auth - install_tools.py: retry ansible-galaxy on transient timeouts - setup_image.py: skip dep resolution with --no-deps - cli.py: register new commands - i18n.py: add new translation keys Also removes accidentally committed .vale/styles/Google/ files. Test results: 2195 passed, 100% coverage. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
274 lines
9.8 KiB
Python
274 lines
9.8 KiB
Python
"""Unit tests for devx.tools.setup_image."""
|
|
|
|
import os
|
|
import subprocess
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from click.testing import CliRunner
|
|
|
|
from devx.tools.setup_image import (
|
|
_build_pip_extra_index_url,
|
|
_fallback_to_setup_ci,
|
|
_install_in_image,
|
|
cli,
|
|
)
|
|
|
|
|
|
class TestBuildPipExtraIndexUrl:
|
|
def test_basic_url(self) -> None:
|
|
url = _build_pip_extra_index_url(
|
|
"git.oblachno.oblachno.fyi",
|
|
"oblachno-oss",
|
|
"emil",
|
|
"tok123",
|
|
)
|
|
assert url == "https://emil:tok123@git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple/"
|
|
|
|
def test_custom_host_org(self) -> None:
|
|
url = _build_pip_extra_index_url(
|
|
"gitea.example.com",
|
|
"my-org",
|
|
"user",
|
|
"secret",
|
|
)
|
|
assert url == "https://user:secret@gitea.example.com/api/packages/my-org/pypi/simple/"
|
|
|
|
|
|
class TestInstallInImage:
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_link_and_install_no_token(self, mock_path: MagicMock, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = False
|
|
mock_path.return_value.is_symlink.return_value = False
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
|
|
|
mock_path.return_value.symlink_to.assert_called_once_with("/opt/venv")
|
|
mock_run.assert_called_once()
|
|
cmd = mock_run.call_args[0][0]
|
|
assert "--no-cache-dir" in cmd
|
|
assert "--no-deps" in cmd
|
|
assert "-e" in cmd
|
|
assert "." in cmd
|
|
# No extras → spec is "."
|
|
assert ".[]" not in " ".join(cmd)
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_link_and_install_with_extras(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_run: MagicMock,
|
|
tmp_path: Path,
|
|
) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = False
|
|
mock_path.return_value.is_symlink.return_value = False
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
_install_in_image(str(venv_link), "/opt/venv", "ci,lint", "host", "org")
|
|
|
|
cmd = mock_run.call_args[0][0]
|
|
assert ".[ci,lint]" in cmd
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_install_with_token_sets_pip_extra_index_url(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_run: MagicMock,
|
|
tmp_path: Path,
|
|
) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = False
|
|
mock_path.return_value.is_symlink.return_value = False
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{"CI_GITEA_TOKEN": "tok123", "CI_GITEA_USERNAME": "emil"},
|
|
clear=True,
|
|
):
|
|
_install_in_image(str(venv_link), "/opt/venv", "lint", "git.host", "org")
|
|
|
|
env = mock_run.call_args[1]["env"]
|
|
assert "PIP_EXTRA_INDEX_URL" in env
|
|
assert "emil:tok123@git.host" in env["PIP_EXTRA_INDEX_URL"]
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_install_with_token_defaults_username(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_run: MagicMock,
|
|
tmp_path: Path,
|
|
) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = False
|
|
mock_path.return_value.is_symlink.return_value = False
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
|
|
with patch.dict(os.environ, {"CI_GITEA_TOKEN": "tok123"}, clear=True):
|
|
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
|
|
|
env = mock_run.call_args[1]["env"]
|
|
assert "emil:tok123@host" in env["PIP_EXTRA_INDEX_URL"]
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_install_removes_existing_link(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_run: MagicMock,
|
|
tmp_path: Path,
|
|
) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = True
|
|
mock_path.return_value.is_symlink.return_value = False
|
|
mock_path.return_value.unlink = MagicMock()
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
|
|
|
mock_path.return_value.unlink.assert_called_once()
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_install_removes_existing_symlink(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_run: MagicMock,
|
|
tmp_path: Path,
|
|
) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = False
|
|
mock_path.return_value.is_symlink.return_value = True
|
|
mock_path.return_value.unlink = MagicMock()
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
|
|
|
mock_path.return_value.unlink.assert_called_once()
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_install_failure_raises(self, mock_path: MagicMock, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
venv_link = tmp_path / ".venv"
|
|
mock_path.return_value.exists.return_value = False
|
|
mock_path.return_value.is_symlink.return_value = False
|
|
mock_path.return_value.symlink_to = MagicMock()
|
|
mock_run.side_effect = subprocess.CalledProcessError(1, ["pip"])
|
|
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
with pytest.raises(subprocess.CalledProcessError):
|
|
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
|
|
|
|
|
class TestFallbackToSetupCi:
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
def test_fallback_runs_make_setup_ci(self, mock_run: MagicMock) -> None:
|
|
_fallback_to_setup_ci()
|
|
mock_run.assert_called_once_with(["make", "setup-ci"], check=True)
|
|
|
|
@patch("devx.tools.setup_image.subprocess.run")
|
|
def test_fallback_failure_raises(self, mock_run: MagicMock) -> None:
|
|
mock_run.side_effect = subprocess.CalledProcessError(1, ["make"])
|
|
with pytest.raises(subprocess.CalledProcessError):
|
|
_fallback_to_setup_ci()
|
|
|
|
|
|
class TestCli:
|
|
@patch("devx.tools.setup_image._fallback_to_setup_ci")
|
|
@patch("devx.tools.setup_image._install_in_image")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_cli_with_opt_venv_present(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_install: MagicMock,
|
|
mock_fallback: MagicMock,
|
|
) -> None:
|
|
mock_path.return_value.is_dir.return_value = True
|
|
runner = CliRunner()
|
|
result = runner.invoke(cli, ["--extras", "ci,lint"])
|
|
assert result.exit_code == 0
|
|
mock_install.assert_called_once()
|
|
|
|
@patch("devx.tools.setup_image._install_in_image")
|
|
@patch("devx.tools.setup_image._fallback_to_setup_ci")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_cli_falls_back_when_no_opt_venv(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_fallback: MagicMock,
|
|
mock_install: MagicMock,
|
|
) -> None:
|
|
mock_path.return_value.is_dir.return_value = False
|
|
runner = CliRunner()
|
|
result = runner.invoke(cli, [])
|
|
assert result.exit_code == 0
|
|
mock_fallback.assert_called_once()
|
|
|
|
@patch("devx.tools.setup_image._fallback_to_setup_ci")
|
|
@patch("devx.tools.setup_image._install_in_image")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_cli_default_values(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_install: MagicMock,
|
|
mock_fallback: MagicMock,
|
|
) -> None:
|
|
mock_path.return_value.is_dir.return_value = True
|
|
runner = CliRunner()
|
|
result = runner.invoke(cli, [])
|
|
assert result.exit_code == 0
|
|
call_args = mock_install.call_args[0]
|
|
assert call_args[0] == ".venv"
|
|
assert call_args[1] == "/opt/venv"
|
|
assert call_args[2] == "" # no extras
|
|
assert call_args[3] == "git.oblachno.oblachno.fyi"
|
|
assert call_args[4] == "oblachno-oss"
|
|
|
|
@patch("devx.tools.setup_image._fallback_to_setup_ci")
|
|
@patch("devx.tools.setup_image._install_in_image")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_cli_custom_venv_and_gitea(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_install: MagicMock,
|
|
mock_fallback: MagicMock,
|
|
) -> None:
|
|
mock_path.return_value.is_dir.return_value = True
|
|
runner = CliRunner()
|
|
result = runner.invoke(
|
|
cli,
|
|
["--venv", ".custom-venv", "--gitea-host", "gitea.io", "--gitea-org", "myorg"],
|
|
)
|
|
assert result.exit_code == 0
|
|
call_args = mock_install.call_args[0]
|
|
assert call_args[0] == ".custom-venv"
|
|
assert call_args[3] == "gitea.io"
|
|
assert call_args[4] == "myorg"
|
|
|
|
@patch("devx.tools.setup_image._fallback_to_setup_ci")
|
|
@patch("devx.tools.setup_image._install_in_image")
|
|
@patch("devx.tools.setup_image.Path")
|
|
def test_cli_with_extras(
|
|
self,
|
|
mock_path: MagicMock,
|
|
mock_install: MagicMock,
|
|
mock_fallback: MagicMock,
|
|
) -> None:
|
|
mock_path.return_value.is_dir.return_value = True
|
|
runner = CliRunner()
|
|
result = runner.invoke(cli, ["--extras", "lint"])
|
|
assert result.exit_code == 0
|
|
assert mock_install.call_args[0][2] == "lint"
|