Public Access
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33b09c162d | ||
|
|
a2c856d8b2 |
@@ -10,6 +10,8 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.1.0] - 2026-06-22
|
||||
|
||||
## [0.1.0] - 2026-06-22
|
||||
|
||||
### Features
|
||||
|
||||
- Extract reusable dev/CI tools from GRM into devx package
|
||||
|
||||
+22
-1
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Project setup: install Python deps, pre-commit hooks, and tea CLI login.
|
||||
"""Project setup: install Python deps, Ansible collections, pre-commit hooks, and tea CLI login.
|
||||
|
||||
Usage::
|
||||
|
||||
@@ -38,6 +38,16 @@ def _install_pre_commit_hooks(bin_dir: str) -> None:
|
||||
_run([pre_commit, "install", "--hook-type", hook_type])
|
||||
|
||||
|
||||
def _install_ansible_collections(bin_dir: str) -> None:
|
||||
"""Install required Ansible Galaxy collections if requirements exist."""
|
||||
galaxy = str(Path(bin_dir) / "ansible-galaxy")
|
||||
requirements = Path("ansible/requirements.yml")
|
||||
if not requirements.exists():
|
||||
click.echo(" ansible/requirements.yml not found — skipping collections.")
|
||||
return
|
||||
_run([galaxy, "collection", "install", "-r", str(requirements)])
|
||||
|
||||
|
||||
def _configure_tea_login() -> None:
|
||||
"""Configure tea CLI login from .env if REPO_TOKEN is set.
|
||||
|
||||
@@ -119,11 +129,18 @@ def _verify(bin_dir: str) -> None:
|
||||
default=False,
|
||||
help="Skip tea CLI login configuration.",
|
||||
)
|
||||
@click.option(
|
||||
"--no-ansible-collections",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Skip Ansible Galaxy collection installation.",
|
||||
)
|
||||
def main(
|
||||
bin_dir: str,
|
||||
extras: str,
|
||||
no_pre_commit: bool,
|
||||
no_tea_login: bool,
|
||||
no_ansible_collections: bool,
|
||||
) -> None:
|
||||
"""Install Python deps, pre-commit hooks, and configure tea CLI."""
|
||||
if not Path(bin_dir).exists():
|
||||
@@ -132,6 +149,10 @@ def main(
|
||||
click.echo(f"Installing Python dependencies (extras: {extras})...")
|
||||
_install_python_deps(bin_dir, extras)
|
||||
|
||||
if not no_ansible_collections:
|
||||
click.echo("Installing Ansible Galaxy collections...")
|
||||
_install_ansible_collections(bin_dir)
|
||||
|
||||
if not no_pre_commit:
|
||||
click.echo("Installing pre-commit hooks...")
|
||||
_install_pre_commit_hooks(bin_dir)
|
||||
|
||||
@@ -9,6 +9,7 @@ from click.testing import CliRunner
|
||||
|
||||
from devx.tools.setup import (
|
||||
_configure_tea_login,
|
||||
_install_ansible_collections,
|
||||
_install_pre_commit_hooks,
|
||||
_install_python_deps,
|
||||
_run,
|
||||
@@ -58,6 +59,24 @@ class TestInstallPreCommitHooks:
|
||||
assert "pre-push" in hook_types
|
||||
|
||||
|
||||
class TestInstallAnsibleCollections:
|
||||
@patch("devx.tools.setup._run")
|
||||
def test_installs_from_requirements(self, mock_run: MagicMock, tmp_path: Path) -> None:
|
||||
req = tmp_path / "ansible" / "requirements.yml"
|
||||
req.parent.mkdir(parents=True)
|
||||
req.write_text("collections: []")
|
||||
with patch("devx.tools.setup.Path") as mock_path:
|
||||
mock_path.return_value.exists.return_value = True
|
||||
mock_path.return_value.__str__ = lambda _: str(req)
|
||||
_install_ansible_collections(".venv/bin")
|
||||
mock_run.assert_called_once()
|
||||
|
||||
@patch("devx.tools.setup._run")
|
||||
def test_skips_when_no_requirements(self, mock_run: MagicMock) -> None:
|
||||
_install_ansible_collections(".venv/bin")
|
||||
mock_run.assert_not_called()
|
||||
|
||||
|
||||
class TestConfigureTeaLogin:
|
||||
@patch("devx.tools.setup.shutil.which", return_value=None)
|
||||
def test_tea_not_installed(self, mock_which: MagicMock) -> None:
|
||||
@@ -142,10 +161,12 @@ class TestMain:
|
||||
@patch("devx.tools.setup._configure_tea_login")
|
||||
@patch("devx.tools.setup._verify")
|
||||
@patch("devx.tools.setup._install_pre_commit_hooks")
|
||||
@patch("devx.tools.setup._install_ansible_collections")
|
||||
@patch("devx.tools.setup._install_python_deps")
|
||||
def test_main_success(
|
||||
self,
|
||||
mock_install_deps: MagicMock,
|
||||
mock_install_ansible: MagicMock,
|
||||
mock_install_hooks: MagicMock,
|
||||
mock_verify: MagicMock,
|
||||
mock_tea: MagicMock,
|
||||
@@ -157,6 +178,7 @@ class TestMain:
|
||||
result = runner.invoke(main, ["--bin", str(bin_dir)])
|
||||
assert result.exit_code == 0
|
||||
mock_install_deps.assert_called_once()
|
||||
mock_install_ansible.assert_called_once()
|
||||
mock_install_hooks.assert_called_once()
|
||||
mock_verify.assert_called_once()
|
||||
mock_tea.assert_called_once()
|
||||
@@ -164,10 +186,12 @@ class TestMain:
|
||||
@patch("devx.tools.setup._configure_tea_login")
|
||||
@patch("devx.tools.setup._verify")
|
||||
@patch("devx.tools.setup._install_pre_commit_hooks")
|
||||
@patch("devx.tools.setup._install_ansible_collections")
|
||||
@patch("devx.tools.setup._install_python_deps")
|
||||
def test_main_no_pre_commit(
|
||||
self,
|
||||
mock_install_deps: MagicMock,
|
||||
mock_install_ansible: MagicMock,
|
||||
mock_install_hooks: MagicMock,
|
||||
mock_verify: MagicMock,
|
||||
mock_tea: MagicMock,
|
||||
@@ -184,10 +208,33 @@ class TestMain:
|
||||
@patch("devx.tools.setup._configure_tea_login")
|
||||
@patch("devx.tools.setup._verify")
|
||||
@patch("devx.tools.setup._install_pre_commit_hooks")
|
||||
@patch("devx.tools.setup._install_ansible_collections")
|
||||
@patch("devx.tools.setup._install_python_deps")
|
||||
def test_main_no_ansible_collections(
|
||||
self,
|
||||
mock_install_deps: MagicMock,
|
||||
mock_install_ansible: MagicMock,
|
||||
mock_install_hooks: MagicMock,
|
||||
mock_verify: MagicMock,
|
||||
mock_tea: MagicMock,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
bin_dir = tmp_path / "bin"
|
||||
bin_dir.mkdir()
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--bin", str(bin_dir), "--no-ansible-collections"])
|
||||
assert result.exit_code == 0
|
||||
mock_install_ansible.assert_not_called()
|
||||
|
||||
@patch("devx.tools.setup._configure_tea_login")
|
||||
@patch("devx.tools.setup._verify")
|
||||
@patch("devx.tools.setup._install_pre_commit_hooks")
|
||||
@patch("devx.tools.setup._install_ansible_collections")
|
||||
@patch("devx.tools.setup._install_python_deps")
|
||||
def test_main_custom_extras(
|
||||
self,
|
||||
mock_install_deps: MagicMock,
|
||||
mock_install_ansible: MagicMock,
|
||||
mock_install_hooks: MagicMock,
|
||||
mock_verify: MagicMock,
|
||||
mock_tea: MagicMock,
|
||||
@@ -203,10 +250,12 @@ class TestMain:
|
||||
@patch("devx.tools.setup._configure_tea_login")
|
||||
@patch("devx.tools.setup._verify")
|
||||
@patch("devx.tools.setup._install_pre_commit_hooks")
|
||||
@patch("devx.tools.setup._install_ansible_collections")
|
||||
@patch("devx.tools.setup._install_python_deps")
|
||||
def test_main_no_tea_login(
|
||||
self,
|
||||
mock_install_deps: MagicMock,
|
||||
mock_install_ansible: MagicMock,
|
||||
mock_install_hooks: MagicMock,
|
||||
mock_verify: MagicMock,
|
||||
mock_tea: MagicMock,
|
||||
@@ -233,9 +282,10 @@ def test_main_module_block(tmp_path: Path) -> None:
|
||||
with patch.dict("os.environ", {}, clear=True):
|
||||
with patch("devx.tools.setup._install_python_deps") as mock_deps:
|
||||
with patch("devx.tools.setup._install_pre_commit_hooks"):
|
||||
with patch("devx.tools.setup._configure_tea_login"):
|
||||
with patch("devx.tools.setup._verify"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--bin", str(bin_dir)])
|
||||
assert result.exit_code == 0
|
||||
mock_deps.assert_called_once()
|
||||
with patch("devx.tools.setup._install_ansible_collections"):
|
||||
with patch("devx.tools.setup._configure_tea_login"):
|
||||
with patch("devx.tools.setup._verify"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--bin", str(bin_dir)])
|
||||
assert result.exit_code == 0
|
||||
mock_deps.assert_called_once()
|
||||
|
||||
Reference in New Issue
Block a user