name: CI # Run on every push and PR to main/dev/stage* branches. on: push: branches: [main, dev, "stage*"] pull_request: branches: [main, dev, "stage*"] jobs: # --------------------------------------------------------------------------- # Lint — ruff for style + import sorting # --------------------------------------------------------------------------- lint: name: Lint (ruff) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install ruff run: pip install --no-cache-dir "ruff>=0.9" - name: Check style and imports run: ruff check src/ tests/ scripts/ # --------------------------------------------------------------------------- # Phase 2 / TEST-02 — per-marker test jobs. # `--strict-markers` is already set globally in pyproject.toml [tool.pytest.ini_options].addopts. # --------------------------------------------------------------------------- test-unit: name: Test (unit) Py${{ matrix.python-version }} runs-on: ubuntu-latest needs: lint strategy: fail-fast: false matrix: python-version: ["3.11", "3.12"] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: pip - name: Install system deps (OpenCV headless) run: | sudo apt-get update -qq sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 - name: Install package + dev extras run: pip install --no-cache-dir -e ".[dev]" - name: Run unit tests run: python -m pytest tests/ -m unit -q --tb=short test-integration: name: Test (integration) Py3.11 runs-on: ubuntu-latest needs: lint steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" cache: pip - run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 - run: pip install --no-cache-dir -e ".[dev]" - name: Run integration tests run: python -m pytest tests/ -m integration -q --tb=short test-blackbox: name: Test (blackbox) Py3.11 runs-on: ubuntu-latest needs: lint if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" cache: pip - run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 - run: pip install --no-cache-dir -e ".[dev]" - name: Run blackbox tests run: python -m pytest tests/ -m blackbox -q --tb=short # --------------------------------------------------------------------------- # Phase 2 / AC-06 — AC traceability drift gate. # Two-step: (1) regenerate + git diff, (2) --check orphan/unknown. # --------------------------------------------------------------------------- ac-traceability: name: AC traceability (matrix drift + orphan check) runs-on: ubuntu-latest needs: lint steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" cache: pip - run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 - run: pip install --no-cache-dir -e ".[dev]" - name: Regenerate AC-TRACEABILITY.md run: python scripts/gen_ac_traceability.py - name: Fail if committed matrix is stale run: | if ! git diff --exit-code .planning/AC-TRACEABILITY.md; then echo "::error::.planning/AC-TRACEABILITY.md is stale. Run scripts/gen_ac_traceability.py and commit the result." exit 1 fi - name: Fail on orphan ACs or unknown AC IDs in tests run: python scripts/gen_ac_traceability.py --check - name: Upload matrix as artifact if: always() uses: actions/upload-artifact@v4 with: name: ac-traceability path: .planning/AC-TRACEABILITY.md # --------------------------------------------------------------------------- # Docker build smoke test # --------------------------------------------------------------------------- docker-build: name: Docker build smoke test runs-on: ubuntu-latest needs: [test-unit, test-integration] steps: - uses: actions/checkout@v4 - name: Build Docker image run: docker build -t gps-denied-onboard:ci . - name: Health smoke test (container start) run: | docker run -d --name smoke -p 8000:8000 gps-denied-onboard:ci sleep 5 curl --retry 5 --retry-delay 2 --fail http://localhost:8000/health docker stop smoke