mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Two bots bumped the one baudolo version independently. The pip pin updater rewrites the literal package_name pin in roles/svc-bkp-volume-2-local/tasks/01_install.yml and opens a PR scoped to roles/<entry>/, and dependabot bumps the same package in pyproject.toml. Each PR alone splits the pins that tests/lint/repository/dependencies/test_baudolo_pin.py holds equal; #995 merged such a split and turned main's test-lint red until #996, and the next upstream release (7.1.2 is tagged) would repeat it. The version lookup now takes an optional distribution name and returns its exact == pin from [project.dependencies]. The install task asks it for backup-docker-to-local, so pyproject.toml is the only place the version lives, dependabot is the only bot that moves it, and the pip updater no longer finds a literal to bump. The lint now forbids a literal pin in the task and requires the lookup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
137 lines
3.9 KiB
Python
137 lines
3.9 KiB
Python
import importlib
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
class TestVersionLookup(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
try:
|
|
cls.plugin_module = importlib.import_module("plugins.lookup.version")
|
|
cls.LookupModule = cls.plugin_module.LookupModule
|
|
except ModuleNotFoundError as exc:
|
|
raise unittest.SkipTest(
|
|
"Could not import lookup plugin 'plugins.lookup.version'. "
|
|
"Make sure tests run with repo root on PYTHONPATH."
|
|
) from exc
|
|
except Exception as exc:
|
|
raise unittest.SkipTest(f"Failed importing lookup plugin: {exc}") from exc
|
|
|
|
# Ensure ansible is importable (plugin depends on it)
|
|
try:
|
|
import ansible # noqa: F401
|
|
except Exception as exc:
|
|
raise unittest.SkipTest(
|
|
f"Ansible not available for unit tests: {exc}"
|
|
) from exc
|
|
|
|
def _run_with_repo_layout(self, pyproject_content: str | None, terms=()):
|
|
"""
|
|
Creates a temporary repo-like layout:
|
|
<tmp>/pyproject.toml (optional)
|
|
Then executes the lookup plugin with PROJECT_ROOT pointing at <tmp>.
|
|
"""
|
|
plugin_mod = self.plugin_module
|
|
original_root = plugin_mod.PROJECT_ROOT
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
if pyproject_content is not None:
|
|
pyproject_path = str(Path(tmp) / "pyproject.toml")
|
|
with Path(pyproject_path).open("w", encoding="utf-8") as f:
|
|
f.write(pyproject_content)
|
|
|
|
plugin_mod.PROJECT_ROOT = Path(tmp)
|
|
|
|
try:
|
|
plugin = self.LookupModule()
|
|
return plugin.run(list(terms))
|
|
finally:
|
|
plugin_mod.PROJECT_ROOT = original_root
|
|
|
|
def test_reads_project_version(self):
|
|
result = self._run_with_repo_layout(
|
|
"""
|
|
[project]
|
|
name = "demo"
|
|
version = "1.2.3"
|
|
"""
|
|
)
|
|
self.assertEqual(result, ["1.2.3"])
|
|
|
|
def test_falls_back_to_poetry_version(self):
|
|
result = self._run_with_repo_layout(
|
|
"""
|
|
[tool.poetry]
|
|
name = "demo"
|
|
version = "2.3.4"
|
|
"""
|
|
)
|
|
self.assertEqual(result, ["2.3.4"])
|
|
|
|
def test_reads_the_exact_pin_of_a_dependency(self):
|
|
result = self._run_with_repo_layout(
|
|
"""
|
|
[project]
|
|
name = "demo"
|
|
version = "1.2.3"
|
|
dependencies = ["bcrypt", "backup-docker-to-local==7.1.1", "PyYAML"]
|
|
""",
|
|
terms=["backup-docker-to-local"],
|
|
)
|
|
self.assertEqual(result, ["7.1.1"])
|
|
|
|
def test_a_dependency_without_an_exact_pin_raises(self):
|
|
from ansible.errors import AnsibleError
|
|
|
|
for dependencies in ('["backup-docker-to-local>=7"]', '["bcrypt"]'):
|
|
with (
|
|
self.subTest(dependencies=dependencies),
|
|
self.assertRaises(AnsibleError),
|
|
):
|
|
self._run_with_repo_layout(
|
|
f"""
|
|
[project]
|
|
name = "demo"
|
|
version = "1.2.3"
|
|
dependencies = {dependencies}
|
|
""",
|
|
terms=["backup-docker-to-local"],
|
|
)
|
|
|
|
def test_more_than_one_term_raises(self):
|
|
from ansible.errors import AnsibleError
|
|
|
|
with self.assertRaises(AnsibleError):
|
|
self._run_with_repo_layout(
|
|
"""
|
|
[project]
|
|
name = "demo"
|
|
version = "1.2.3"
|
|
dependencies = ["a==1", "b==2"]
|
|
""",
|
|
terms=["a", "b"],
|
|
)
|
|
|
|
def test_missing_pyproject_raises(self):
|
|
from ansible.errors import AnsibleError
|
|
|
|
with self.assertRaises(AnsibleError):
|
|
self._run_with_repo_layout(pyproject_content=None)
|
|
|
|
def test_missing_version_raises(self):
|
|
from ansible.errors import AnsibleError
|
|
|
|
with self.assertRaises(AnsibleError):
|
|
self._run_with_repo_layout(
|
|
"""
|
|
[project]
|
|
name = "demo"
|
|
# no version here
|
|
"""
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|