diff --git a/tests/__snapshots__/test_dockerfile.ambr b/tests/__snapshots__/test_dockerfile.ambr new file mode 100644 index 0000000..ace3cf3 --- /dev/null +++ b/tests/__snapshots__/test_dockerfile.ambr @@ -0,0 +1,139 @@ +# serializer version: 1 +# name: test_workflows_container[3.12-3.10] + ''' + FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim + + WORKDIR /app + + # Install dependencies first (cached layer, only invalidated by pyproject.toml changes) + COPY pyproject.toml ./ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev --no-install-project + + # Copy source and install project + COPY pkfire/ ./pkfire/ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + + RUN useradd --no-create-home --shell /bin/false app + USER app + + CMD ["uv", "run", "python", "-m", "pkfire"] + + ''' +# --- +# name: test_workflows_container[3.12-3.12] + ''' + FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim + + WORKDIR /app + + # Install dependencies first (cached layer, only invalidated by pyproject.toml changes) + COPY pyproject.toml ./ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev --no-install-project + + # Copy source and install project + COPY pkfire/ ./pkfire/ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + + RUN useradd --no-create-home --shell /bin/false app + USER app + + CMD ["uv", "run", "python", "-m", "pkfire"] + + ''' +# --- +# name: test_workflows_container[3.14-3.10] + ''' + FROM ghcr.io/astral-sh/uv:python3.14-bookworm-slim + + WORKDIR /app + + # Install dependencies first (cached layer, only invalidated by pyproject.toml changes) + COPY pyproject.toml ./ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev --no-install-project + + # Copy source and install project + COPY pkfire/ ./pkfire/ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + + RUN useradd --no-create-home --shell /bin/false app + USER app + + CMD ["uv", "run", "python", "-m", "pkfire"] + + ''' +# --- +# name: test_workflows_container[3.14-3.12] + ''' + FROM ghcr.io/astral-sh/uv:python3.14-bookworm-slim + + WORKDIR /app + + # Install dependencies first (cached layer, only invalidated by pyproject.toml changes) + COPY pyproject.toml ./ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev --no-install-project + + # Copy source and install project + COPY pkfire/ ./pkfire/ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + + RUN useradd --no-create-home --shell /bin/false app + USER app + + CMD ["uv", "run", "python", "-m", "pkfire"] + + ''' +# --- +# name: test_workflows_container[No maximum-3.10] + ''' + FROM ghcr.io/astral-sh/uv:python3.14-bookworm-slim + + WORKDIR /app + + # Install dependencies first (cached layer, only invalidated by pyproject.toml changes) + COPY pyproject.toml ./ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev --no-install-project + + # Copy source and install project + COPY pkfire/ ./pkfire/ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + + RUN useradd --no-create-home --shell /bin/false app + USER app + + CMD ["uv", "run", "python", "-m", "pkfire"] + + ''' +# --- +# name: test_workflows_container[No maximum-3.12] + ''' + FROM ghcr.io/astral-sh/uv:python3.14-bookworm-slim + + WORKDIR /app + + # Install dependencies first (cached layer, only invalidated by pyproject.toml changes) + COPY pyproject.toml ./ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev --no-install-project + + # Copy source and install project + COPY pkfire/ ./pkfire/ + RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + + RUN useradd --no-create-home --shell /bin/false app + USER app + + CMD ["uv", "run", "python", "-m", "pkfire"] + + ''' +# --- diff --git a/tests/__snapshots__/test_workflows.ambr b/tests/__snapshots__/test_workflows.ambr index 7c7481a..5e7fe56 100644 --- a/tests/__snapshots__/test_workflows.ambr +++ b/tests/__snapshots__/test_workflows.ambr @@ -319,6 +319,566 @@ ''' # --- +# name: test_workflows_ci_versions[3.12-3.10] + ''' + name: CI + + on: + push: + branches: + - main + pull_request: + + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + + jobs: + ci: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.10' + - '3.11' + - '3.12' + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📐 Lint + run: uv run poe lint + + - name: 🔥 Test + run: uv run poe test + + - name: 🔍 Collect coverage results + run: uv run coverage xml + if: ${{ matrix.python-version == '3.12' }} + + - name: 📊 Upload coverage to Codecov + uses: codecov/codecov-action@v6 + if: ${{ matrix.python-version == '3.12' }} + with: + fail_ci_if_error: true + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: '3.12' + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📖 Build documentation + run: uv run poe docs-build + + gitleaks: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🔍 Check for secrets + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ''' +# --- +# name: test_workflows_ci_versions[3.12-3.12] + ''' + name: CI + + on: + push: + branches: + - main + pull_request: + + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + + jobs: + ci: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.12' + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📐 Lint + run: uv run poe lint + + - name: 🔥 Test + run: uv run poe test + + - name: 🔍 Collect coverage results + run: uv run coverage xml + if: ${{ matrix.python-version == '3.12' }} + + - name: 📊 Upload coverage to Codecov + uses: codecov/codecov-action@v6 + if: ${{ matrix.python-version == '3.12' }} + with: + fail_ci_if_error: true + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: '3.12' + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📖 Build documentation + run: uv run poe docs-build + + gitleaks: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🔍 Check for secrets + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ''' +# --- +# name: test_workflows_ci_versions[3.14-3.10] + ''' + name: CI + + on: + push: + branches: + - main + pull_request: + + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + + jobs: + ci: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.10' + - '3.11' + - '3.12' + - '3.13' + - '3.14' + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📐 Lint + run: uv run poe lint + + - name: 🔥 Test + run: uv run poe test + + - name: 🔍 Collect coverage results + run: uv run coverage xml + if: ${{ matrix.python-version == '3.14' }} + + - name: 📊 Upload coverage to Codecov + uses: codecov/codecov-action@v6 + if: ${{ matrix.python-version == '3.14' }} + with: + fail_ci_if_error: true + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: '3.14' + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📖 Build documentation + run: uv run poe docs-build + + gitleaks: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🔍 Check for secrets + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ''' +# --- +# name: test_workflows_ci_versions[3.14-3.12] + ''' + name: CI + + on: + push: + branches: + - main + pull_request: + + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + + jobs: + ci: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.12' + - '3.13' + - '3.14' + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📐 Lint + run: uv run poe lint + + - name: 🔥 Test + run: uv run poe test + + - name: 🔍 Collect coverage results + run: uv run coverage xml + if: ${{ matrix.python-version == '3.14' }} + + - name: 📊 Upload coverage to Codecov + uses: codecov/codecov-action@v6 + if: ${{ matrix.python-version == '3.14' }} + with: + fail_ci_if_error: true + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: '3.14' + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📖 Build documentation + run: uv run poe docs-build + + gitleaks: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🔍 Check for secrets + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ''' +# --- +# name: test_workflows_ci_versions[No maximum-3.10] + ''' + name: CI + + on: + push: + branches: + - main + pull_request: + + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + + jobs: + ci: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.10' + - '3.11' + - '3.12' + - '3.13' + - '3.14' + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📐 Lint + run: uv run poe lint + + - name: 🔥 Test + run: uv run poe test + + - name: 🔍 Collect coverage results + run: uv run coverage xml + if: ${{ matrix.python-version == '3.14' }} + + - name: 📊 Upload coverage to Codecov + uses: codecov/codecov-action@v6 + if: ${{ matrix.python-version == '3.14' }} + with: + fail_ci_if_error: true + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: '3.14' + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📖 Build documentation + run: uv run poe docs-build + + gitleaks: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🔍 Check for secrets + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ''' +# --- +# name: test_workflows_ci_versions[No maximum-3.12] + ''' + name: CI + + on: + push: + branches: + - main + pull_request: + + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + + jobs: + ci: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.12' + - '3.13' + - '3.14' + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📐 Lint + run: uv run poe lint + + - name: 🔥 Test + run: uv run poe test + + - name: 🔍 Collect coverage results + run: uv run coverage xml + if: ${{ matrix.python-version == '3.14' }} + + - name: 📊 Upload coverage to Codecov + uses: codecov/codecov-action@v6 + if: ${{ matrix.python-version == '3.14' }} + with: + fail_ci_if_error: true + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🦀 Set up Python project with uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: '3.14' + + - name: 🐍 Install dependencies + run: uv sync + + - name: 📖 Build documentation + run: uv run poe docs-build + + gitleaks: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: 💾 Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: 🔍 Check for secrets + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ''' +# --- # name: test_workflows_release[no_pypi] ''' name: Release diff --git a/tests/test_dockerfile.py b/tests/test_dockerfile.py new file mode 100644 index 0000000..cd2922f --- /dev/null +++ b/tests/test_dockerfile.py @@ -0,0 +1,27 @@ +"""Snapshot tests for Dockerfile templates.""" + +from collections.abc import Callable +from pathlib import Path + +import pytest +from syrupy.assertion import SnapshotAssertion + + +@pytest.mark.parametrize("python_version_minimum", ["3.10", "3.12"]) +@pytest.mark.parametrize( + "python_version_maximum", ["3.12", "3.14", "No maximum"] +) +def test_workflows_container( + render_template: Callable[..., Path], + snapshot: SnapshotAssertion, + *, + python_version_minimum: str, + python_version_maximum: str, +) -> None: + rendered = render_template( + project_visibility="public", + enable_container=True, + python_version_minimum=python_version_minimum, + python_version_maximum=python_version_maximum, + ) + assert (rendered / "Dockerfile").read_text() == snapshot diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 3bf7cc7..31f0acb 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -33,6 +33,27 @@ def test_workflows_ci( ).read_text() == snapshot +@pytest.mark.parametrize("python_version_minimum", ["3.10", "3.12"]) +@pytest.mark.parametrize( + "python_version_maximum", ["3.12", "3.14", "No maximum"] +) +def test_workflows_ci_versions( + render_template: Callable[..., Path], + snapshot: SnapshotAssertion, + *, + python_version_minimum: str, + python_version_maximum: str, +) -> None: + rendered = render_template( + project_visibility="public", + python_version_minimum=python_version_minimum, + python_version_maximum=python_version_maximum, + ) + assert ( + rendered / ".github" / "workflows" / "ci.yaml" + ).read_text() == snapshot + + @pytest.mark.parametrize( "enable_pypi", [pytest.param(True, id="pypi"), pytest.param(False, id="no_pypi")],