Add FX Borzoi score cache #329
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Continuous integration for GenoLeWM. | |
| # | |
| # Jobs: | |
| # lint — ruff format check, ruff lint | |
| # types — mypy --strict | |
| # tests — pytest matrix (Python × OS), coverage upload | |
| # ml-smoke — fast fixture-backed ML smoke suite | |
| # eval-smoke — generated fixture eval regression gate | |
| # gates — custom AST linters + public-API snapshot | |
| # build — package build smoke test (sdist + wheel) | |
| # docs — mkdocs strict build | |
| # ci-required — required-check fan-in | |
| # | |
| # All jobs run on every PR and on pushes to main. The matrix is | |
| # intentionally lean on PRs (Linux only by default; macOS/Windows | |
| # included via matrix.include) and full on main / releases. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} | |
| env: | |
| PYTHONDONTWRITEBYTECODE: "1" | |
| PYTHONUNBUFFERED: "1" | |
| PIP_DISABLE_PIP_VERSION_CHECK: "1" | |
| FORCE_COLOR: "1" | |
| jobs: | |
| lint: | |
| name: Lint (ruff) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: python -m pip install -e ".[dev]" | |
| - name: ruff format --check | |
| run: ruff format --check geno_lewm tools tests | |
| - name: ruff check | |
| run: ruff check geno_lewm tools tests --output-format=github | |
| types: | |
| name: Types (mypy --strict) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: python -m pip install -e ".[dev]" | |
| - name: mypy | |
| run: mypy geno_lewm tools | |
| gates: | |
| name: Contract gates (errors / events / surface / net / print / spdx) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: python -m pip install -e ".[dev]" | |
| - name: check_error_codes | |
| run: python -m tools.lint.check_error_codes | |
| - name: check_event_names | |
| run: python -m tools.lint.check_event_names | |
| - name: check_no_print | |
| run: python -m tools.lint.check_no_print | |
| - name: check_network_confined | |
| run: python -m tools.lint.check_network_confined | |
| - name: check_scope_language (project scope) | |
| run: python -m tools.lint.check_scope_language | |
| - name: check first-experiment dataset spec | |
| run: >- | |
| python -m tools.release.dataset_snapshot | |
| --spec-json configs/first_experiment/dataset-snapshot-snv.json | |
| --check-spec | |
| - name: check_license_headers (SPDX) | |
| run: python -m tools.lint.check_license_headers | |
| - name: public-API snapshot | |
| run: python -m tools.api.snapshot check | |
| tests: | |
| name: Tests (Python ${{ matrix.python }} on ${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest] | |
| python: ["3.10", "3.11", "3.12", "3.13"] | |
| include: | |
| - os: macos-latest | |
| python: "3.12" | |
| - os: windows-latest | |
| python: "3.12" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| # Fetch enough history for the changed-files coverage gate to | |
| # diff against the PR base branch (`origin/<base_ref>`). | |
| fetch-depth: 0 | |
| - name: Set up Python | |
| if: runner.os != 'Windows' | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Set up Python (Windows) | |
| if: runner.os == 'Windows' | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Install | |
| # Install the torch-backed extras on the canonical coverage combo | |
| # (ubuntu-latest / 3.12) so ML paths are exercised and counted by the | |
| # changed-files coverage gate; keep the other matrix legs lean. | |
| run: | | |
| if [ "${{ matrix.os }}" = "ubuntu-latest" ] && [ "${{ matrix.python }}" = "3.12" ]; then | |
| python -m pip install -e ".[dev,train,eval]" | |
| else | |
| python -m pip install -e ".[dev]" | |
| fi | |
| shell: bash | |
| - name: pytest | |
| # xdist on Windows uses spawn-based workers that re-import the | |
| # package per worker; combined with module-level state in | |
| # observability/metrics, this surfaces flaky failures on Windows | |
| # specifically. Run serially on Windows, parallel elsewhere. | |
| run: | | |
| if [ "${{ runner.os }}" = "Windows" ]; then | |
| pytest --cov=geno_lewm --cov-branch --cov-report=xml --cov-report=term-missing -v --tb=long 2>&1 | tee pytest.out | |
| else | |
| pytest --cov=geno_lewm --cov-branch --cov-report=xml --cov-report=term-missing -n auto -v --tb=long 2>&1 | tee pytest.out | |
| fi | |
| shell: bash | |
| - name: Upload pytest output (on failure) | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: pytest-${{ matrix.os }}-${{ matrix.python }} | |
| path: pytest.out | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| - name: Upload coverage to Codecov | |
| if: matrix.os == 'ubuntu-latest' && matrix.python == '3.12' | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./coverage.xml | |
| fail_ci_if_error: false | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Changed-files coverage gate (PRs only) | |
| # Runs on the canonical matrix combo only; one signal is enough. | |
| # Skipped on pushes to main / tags because there is no PR base to diff against. | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| matrix.os == 'ubuntu-latest' && | |
| matrix.python == '3.12' | |
| run: | | |
| git fetch --no-tags --depth=50 origin "${{ github.base_ref }}" | |
| python -m tools.ci.coverage_gate \ | |
| --coverage-xml coverage.xml \ | |
| --base "origin/${{ github.base_ref }}" \ | |
| --threshold 0.83 | |
| shell: bash | |
| ml-smoke: | |
| name: ML smoke (fixture-backed) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: python -m pip install -e ".[dev]" | |
| - name: pytest tests/ml | |
| run: pytest tests/ml -q --tb=long --durations=10 | |
| eval-smoke: | |
| name: Eval smoke (fixture-backed) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: python -m pip install -e ".[dev]" | |
| - name: Run eval smoke gate | |
| run: >- | |
| python -m tools.ci.eval_smoke_gate | |
| --work-dir .eval-smoke | |
| --summary-json .eval-smoke/eval_smoke_summary.json | |
| - name: Upload eval smoke summary | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: eval-smoke-summary | |
| path: .eval-smoke/eval_smoke_summary.json | |
| retention-days: 14 | |
| build: | |
| name: Build (sdist + wheel) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install build deps | |
| run: python -m pip install build twine | |
| - name: Build | |
| run: python -m build | |
| - name: Twine check | |
| run: twine check dist/* | |
| - name: Check sdist release assets | |
| run: python -m tools.release.check_sdist_assets dist/*.tar.gz | |
| - name: Smoke install | |
| run: | | |
| python -m pip install dist/*.whl | |
| python -c "import geno_lewm; print(geno_lewm.__version__)" | |
| python -c "from geno_lewm import EditSpec, apply_edit; print(EditSpec(chrom='1', pos=1, ref='A', alt='T'))" | |
| - name: Upload dist artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: dist | |
| path: dist/ | |
| retention-days: 14 | |
| docs: | |
| name: Docs (mkdocs --strict) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: python -m pip install -e ".[docs]" | |
| - name: Build docs (strict) | |
| run: mkdocs build --strict | |
| - name: Upload site artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: docs-site | |
| path: site/ | |
| retention-days: 14 | |
| # Single required check that fans-in all the matrix jobs above. | |
| # Branch protection just needs to require this one. | |
| ci-required: | |
| name: CI required | |
| if: always() | |
| needs: [lint, types, gates, tests, ml-smoke, eval-smoke, build, docs] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check jobs | |
| if: >- | |
| needs.lint.result != 'success' || | |
| needs.types.result != 'success' || | |
| needs.gates.result != 'success' || | |
| needs.tests.result != 'success' || | |
| needs.ml-smoke.result != 'success' || | |
| needs.eval-smoke.result != 'success' || | |
| needs.build.result != 'success' || | |
| needs.docs.result != 'success' | |
| run: | | |
| echo "One or more required CI jobs failed; see job logs above." | |
| exit 1 | |
| - run: echo "All required CI jobs passed." |