diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e0a82d5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: test-and-build + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + test: + name: test (${{ matrix.os }}, Python ${{ matrix.python-version }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + python-version: ["3.10", "3.13"] + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: pip + - name: Install test dependencies + run: python -m pip install --disable-pip-version-check -e ".[dev]" + - name: Run test suite + run: python -m pytest -q + + build-wheel: + name: build wheel + runs-on: ubuntu-latest + needs: test + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + cache: pip + - name: Install build tools + run: python -m pip install --disable-pip-version-check build + - name: Build wheel + run: python -m build --wheel + - name: Upload wheel evidence + uses: actions/upload-artifact@v4 + with: + name: simulation-invariant-wheel + path: dist/*.whl + if-no-files-found: error diff --git a/pyproject.toml b/pyproject.toml index 0967a34..904d7a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,10 @@ Issues = "https://github.com/Deathburgerz013/Simulation_Invariant/issues" simulation-invariant = "sim.__main__:main" [project.optional-dependencies] -dev = ["pytest>=8"] +dev = [ + "pytest>=8", + "tomli>=2; python_version < '3.11'", +] [tool.setuptools.packages.find] where = ["."] diff --git a/tests/test_ci_workflow.py b/tests/test_ci_workflow.py new file mode 100644 index 0000000..3a2b15b --- /dev/null +++ b/tests/test_ci_workflow.py @@ -0,0 +1,39 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +WORKFLOW = ROOT / ".github" / "workflows" / "ci.yml" + + +def _workflow_text() -> str: + return WORKFLOW.read_text(encoding="utf-8") + + +def test_ci_workflow_has_read_only_repository_authority() -> None: + text = _workflow_text() + assert "permissions:\n contents: read\n" in text + assert "contents: write" not in text + assert "pull-requests: write" not in text + + +def test_ci_runs_supported_cross_platform_matrix() -> None: + text = _workflow_text() + assert "os: [ubuntu-latest, windows-latest]" in text + assert 'python-version: ["3.10", "3.13"]' in text + assert "python -m pytest -q" in text + + +def test_ci_builds_and_retains_wheel_without_publishing() -> None: + text = _workflow_text() + assert "python -m build --wheel" in text + assert "actions/upload-artifact@v4" in text + assert "dist/*.whl" in text + assert "publish" not in text.lower() + assert "pypi" not in text.lower() + assert "id-token: write" not in text + + +def test_wheel_build_waits_for_tests() -> None: + text = _workflow_text() + build_section = text.split(" build-wheel:\n", 1)[1] + assert " needs: test\n" in build_section diff --git a/tests/test_packaging_surface.py b/tests/test_packaging_surface.py index b1fd1a9..abcacd6 100644 --- a/tests/test_packaging_surface.py +++ b/tests/test_packaging_surface.py @@ -4,9 +4,13 @@ import subprocess import sys -import tomllib from pathlib import Path +try: + import tomllib +except ModuleNotFoundError: # Python 3.10 + import tomli as tomllib + ROOT = Path(__file__).resolve().parents[1] @@ -23,6 +27,9 @@ def test_project_metadata_is_bounded_and_installable() -> None: assert project["requires-python"] == ">=3.10" assert project["dependencies"] == [] assert project["license"] == {"file": "LICENSE"} + dev_dependencies = project["optional-dependencies"]["dev"] + assert "pytest>=8" in dev_dependencies + assert "tomli>=2; python_version < '3.11'" in dev_dependencies def test_console_command_uses_existing_dispatcher() -> None: