diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e67348b --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,28 @@ +name: Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v4 + + - name: Install dependencies + run: uv sync --dev + + - name: Run unit tests + run: uv run pytest tests/unit -v + + - name: Run integration tests + run: uv run pytest tests/integration -v -m integration + + - name: Run e2e tests + run: uv run pytest tests/e2e -v -m e2e diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee3ef1c..f9152de 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,13 +15,6 @@ repos: types: [python] pass_filenames: false - - id: pytest - name: pytest - entry: uv run pytest - language: system - types: [python] - pass_filenames: false - - repo: https://github.com/compilerla/conventional-pre-commit rev: v3.4.0 hooks: diff --git a/README.md b/README.md index 4637f48..c80a483 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Brix -[![PyPI version](https://badge.fury.io/py/brix.svg)](https://badge.fury.io/py/brix) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://spycner.github.io/brix/) diff --git a/pyproject.toml b/pyproject.toml index 49c8ba5..8aecd23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ dependencies = [ "httpx>=0.28.1", "pydantic>=2.12.5", "pydantic-settings>=2.12.0", + "pyyaml>=6.0", "questionary>=2.1.1", "typer>=0.20.0", ] @@ -80,7 +81,7 @@ unfixable = ["B"] [tool.ruff.lint.per-file-ignores] "__init__.py" = ["E402"] -"tests/*" = ["S101", "ANN", "D"] +"tests/*" = ["S101", "ANN", "D", "S603", "S607"] [tool.ruff.lint.pydocstyle] convention = "google" diff --git a/tests/e2e/test_git_installation.py b/tests/e2e/test_git_installation.py new file mode 100644 index 0000000..378eff2 --- /dev/null +++ b/tests/e2e/test_git_installation.py @@ -0,0 +1,81 @@ +"""End-to-end tests for git source installation. + +These tests verify that brix can be installed from git source using release tags +with both uv and pip package managers. +""" + +import subprocess + +import pytest + +REPO_URL = "https://github.com/Spycner/brix.git" + + +def get_latest_tag() -> str: + """Get the latest release tag from the remote repository.""" + result = subprocess.run( + ["git", "ls-remote", "--tags", "--refs", REPO_URL], + capture_output=True, + text=True, + check=True, + ) + # Parse tags and sort by semantic version + tags = [line.split("refs/tags/")[1] for line in result.stdout.strip().split("\n") if line] + return sorted(tags, key=lambda t: [int(x) for x in t.lstrip("v").split(".")])[-1] + + +@pytest.fixture(scope="module") +def latest_tag(): + """Fixture to get latest tag once per test module.""" + return get_latest_tag() + + +@pytest.mark.e2e +class TestGitInstallation: + """E2E tests for installing brix from git source.""" + + @pytest.mark.xfail(reason="v1.3.0 missing pyyaml dependency - remove after next release") + def test_uv_install_from_git_tag(self, tmp_path, latest_tag): + """Test installing brix from git with release tag using uv.""" + venv_path = tmp_path / "venv" + git_url = f"git+{REPO_URL}@{latest_tag}" + + # Create venv with uv + result = subprocess.run(["uv", "venv", str(venv_path)], capture_output=True, text=True) + assert result.returncode == 0, f"Failed to create venv: {result.stderr}" + + # Install from git + python_path = venv_path / "bin" / "python" + result = subprocess.run( + ["uv", "pip", "install", git_url, "--python", str(python_path)], + capture_output=True, + text=True, + ) + assert result.returncode == 0, f"Failed to install from git: {result.stderr}" + + # Verify installation + brix_path = venv_path / "bin" / "brix" + result = subprocess.run([str(brix_path), "--version"], capture_output=True, text=True) + assert result.returncode == 0, f"brix --version failed: {result.stderr}" + assert "brix" in result.stdout.lower() or latest_tag.lstrip("v") in result.stdout + + @pytest.mark.xfail(reason="v1.3.0 missing pyyaml dependency - remove after next release") + def test_pip_install_from_git_tag(self, tmp_path, latest_tag): + """Test installing brix from git with release tag using pip.""" + venv_path = tmp_path / "venv_pip" + git_url = f"git+{REPO_URL}@{latest_tag}" + + # Create venv with python + result = subprocess.run(["python3", "-m", "venv", str(venv_path)], capture_output=True, text=True) + assert result.returncode == 0, f"Failed to create venv: {result.stderr}" + + # Install from git using pip + pip_path = venv_path / "bin" / "pip" + result = subprocess.run([str(pip_path), "install", git_url], capture_output=True, text=True) + assert result.returncode == 0, f"Failed to install from git: {result.stderr}" + + # Verify installation + brix_path = venv_path / "bin" / "brix" + result = subprocess.run([str(brix_path), "--version"], capture_output=True, text=True) + assert result.returncode == 0, f"brix --version failed: {result.stderr}" + assert "brix" in result.stdout.lower() or latest_tag.lstrip("v") in result.stdout diff --git a/uv.lock b/uv.lock index 0a5dd5e..282970f 100644 --- a/uv.lock +++ b/uv.lock @@ -93,12 +93,13 @@ wheels = [ [[package]] name = "brix" -version = "1.2.0" +version = "1.3.0" source = { editable = "." } dependencies = [ { name = "httpx" }, { name = "pydantic" }, { name = "pydantic-settings" }, + { name = "pyyaml" }, { name = "questionary" }, { name = "typer" }, ] @@ -139,6 +140,7 @@ requires-dist = [ { name = "mkdocstrings", extras = ["python"], marker = "extra == 'docs'", specifier = ">=0.27" }, { name = "pydantic", specifier = ">=2.12.5" }, { name = "pydantic-settings", specifier = ">=2.12.0" }, + { name = "pyyaml", specifier = ">=6.0" }, { name = "questionary", specifier = ">=2.1.1" }, { name = "typer", specifier = ">=0.20.0" }, ]