name: CI on: pull_request: push: branches: - main permissions: contents: read concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_INPUT: "1" jobs: package: name: Package runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" cache: pip cache-dependency-path: | pyproject.toml requirements*.txt - name: Install build tooling run: python -m pip install "build==1.2.2.post1" "twine==7.0.0" - name: Build source and wheel distributions run: python -m build --sdist --wheel - name: Verify wheel contents and entry point run: | python - <<'PY' from pathlib import Path from zipfile import ZipFile wheels = list(Path("dist").glob("*.whl")) if len(wheels) != 1: raise SystemExit(f"expected one wheel, found: {wheels}") with ZipFile(wheels[0]) as archive: names = set(archive.namelist()) required = { "app.py", "obliteratus/__init__.py", "obliteratus/local_ui.py", } missing = sorted(required - names) if missing: raise SystemExit(f"wheel is missing required modules: {missing}") entry_points = [ name for name in names if name.endswith(".dist-info/entry_points.txt") ] if len(entry_points) != 1: raise SystemExit(f"expected one entry_points.txt, found: {entry_points}") contents = archive.read(entry_points[0]).decode("utf-8") if "obliteratus = obliteratus.cli:main" not in contents: raise SystemExit("wheel is missing the obliteratus console entry point") print(f"verified wheel contents: {wheels[0]}") PY - name: Validate distribution metadata run: | mkdir -p package-evidence python -m twine check dist/* | tee package-evidence/twine-check.txt sha256sum dist/* | tee package-evidence/SHA256SUMS - name: Verify installed wheel contract run: | mapfile -t wheels < <(find "$GITHUB_WORKSPACE/dist" -maxdepth 1 -type f -name '*.whl' -print) if [ "${#wheels[@]}" -ne 1 ]; then echo "expected exactly one wheel, found ${#wheels[@]}" exit 1 fi wheel_env="$RUNNER_TEMP/obliteratus-wheel-env" wheel_cwd="$RUNNER_TEMP/obliteratus-wheel-cwd" python -m venv "$wheel_env" mkdir -p "$wheel_cwd" "$wheel_env/bin/python" -m pip install --no-cache-dir "rich==15.0.0" "$wheel_env/bin/python" -m pip install --no-cache-dir --no-deps "${wheels[0]}" cd "$wheel_cwd" "$wheel_env/bin/python" -I - <<'PY' | tee "$GITHUB_WORKSPACE/package-evidence/wheel-import.txt" import importlib.metadata from pathlib import Path import obliteratus origin = Path(obliteratus.__file__).resolve() assert "site-packages" in origin.parts, origin assert obliteratus.__version__ == importlib.metadata.version("obliteratus") print(f"installed wheel import: {origin}") print(f"version: {obliteratus.__version__}") PY "$wheel_env/bin/python" -I -m obliteratus --help > "$GITHUB_WORKSPACE/package-evidence/wheel-module-help.txt" "$wheel_env/bin/obliteratus" --help > "$GITHUB_WORKSPACE/package-evidence/wheel-console-help.txt" - name: Verify installed sdist contract run: | mapfile -t sdists < <(find "$GITHUB_WORKSPACE/dist" -maxdepth 1 -type f -name '*.tar.gz' -print) if [ "${#sdists[@]}" -ne 1 ]; then echo "expected exactly one sdist, found ${#sdists[@]}" exit 1 fi sdist_env="$RUNNER_TEMP/obliteratus-sdist-env" sdist_cwd="$RUNNER_TEMP/obliteratus-sdist-cwd" python -m venv "$sdist_env" mkdir -p "$sdist_cwd" "$sdist_env/bin/python" -m pip install --no-cache-dir "rich==15.0.0" "$sdist_env/bin/python" -m pip install --no-cache-dir --no-deps "${sdists[0]}" cd "$sdist_cwd" "$sdist_env/bin/python" -I - <<'PY' | tee "$GITHUB_WORKSPACE/package-evidence/sdist-import.txt" import importlib.metadata from pathlib import Path import obliteratus origin = Path(obliteratus.__file__).resolve() assert "site-packages" in origin.parts, origin assert obliteratus.__version__ == importlib.metadata.version("obliteratus") print(f"installed sdist import: {origin}") print(f"version: {obliteratus.__version__}") PY "$sdist_env/bin/python" -I -m obliteratus --help > "$GITHUB_WORKSPACE/package-evidence/sdist-module-help.txt" "$sdist_env/bin/obliteratus" --help > "$GITHUB_WORKSPACE/package-evidence/sdist-console-help.txt" - name: Upload distributions and package evidence if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: distributions-py3.12 path: | dist/ package-evidence/ if-no-files-found: error retention-days: 14 lint: name: Ruff runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" cache: pip cache-dependency-path: pyproject.toml - name: Install Ruff run: python -m pip install "ruff==0.8.6" - name: Install actionlint with checksum verification env: ACTIONLINT_VERSION: "1.7.12" ACTIONLINT_SHA256: "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8" run: | archive="$RUNNER_TEMP/actionlint.tar.gz" curl -fsSLo "$archive" \ "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" echo "${ACTIONLINT_SHA256} ${archive}" | sha256sum -c - tar -xzf "$archive" -C "$RUNNER_TEMP" actionlint - name: Validate GitHub Actions workflows run: | "$RUNNER_TEMP/actionlint" -no-color - name: Enforce Ruff F gate run: >- python -m ruff check --select F obliteratus tests scripts/check_coverage_thresholds.py scripts/gemma4_12b_recursive_loop.py - name: Report E501 legacy baseline if: always() run: >- python -m ruff check --select E501 --statistics obliteratus tests scripts/check_coverage_thresholds.py scripts/gemma4_12b_recursive_loop.py || true test: name: Tests py${{ matrix.python-version }} runs-on: ubuntu-latest timeout-minutes: 45 strategy: fail-fast: false matrix: python-version: - "3.10" - "3.11" - "3.12" env: CUDA_VISIBLE_DEVICES: "" HF_DATASETS_OFFLINE: "1" HF_HUB_DISABLE_TELEMETRY: "1" HF_HUB_OFFLINE: "1" TOKENIZERS_PARALLELISM: "false" TRANSFORMERS_OFFLINE: "1" steps: - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python-version }} cache: pip cache-dependency-path: | pyproject.toml requirements*.txt - name: Install CPU PyTorch run: python -m pip install --index-url https://download.pytorch.org/whl/cpu "torch>=2.0" - name: Install package and test tools run: | python - <<'PY' > /tmp/torch-cpu-constraint.txt import torch print(f"torch=={torch.__version__}") PY python -m pip install -e ".[dev]" -c /tmp/torch-cpu-constraint.txt - name: Smoke import and CLI run: | python - <<'PY' import obliteratus version = getattr(obliteratus, "__version__", None) if version is not None: print(f"obliteratus version: {version}") else: print("obliteratus import: ok") PY python -m obliteratus --help - name: Run tests with coverage run: | mkdir -p test-results python -m pytest \ -m "not slow and not gpu and not mps and not mlx and not network and not download and not remote" \ --cov-branch \ --cov-fail-under=0 \ --junitxml="test-results/junit-py${{ matrix.python-version }}.xml" \ --cov-report="xml:test-results/coverage-py${{ matrix.python-version }}.xml" \ --cov-report="json:test-results/coverage-py${{ matrix.python-version }}.json" - name: Enforce line and branch coverage floors run: >- python scripts/check_coverage_thresholds.py "test-results/coverage-py${{ matrix.python-version }}.json" --min-line 49 --min-branch 36 - name: Upload test and coverage evidence if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test-evidence-py${{ matrix.python-version }} path: test-results/ if-no-files-found: error retention-days: 14