feat(deps): upgrade transformers to 5.x and sentence-transformers to 5.2+ #137
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
| name: CI | |
| on: | |
| push: | |
| branches: | |
| - dev | |
| pull_request: | |
| # `labeled` is required so adding the `full-ci` label re-triggers CI | |
| # with the full OS/Python matrix on an open PR. | |
| types: [opened, synchronize, reopened, labeled] | |
| # Manual coverage run. Never fired by push/PR, so coverage stays off the | |
| # per-commit hot path; on this event the test jobs toggle `--cov` and the | |
| # `coverage-report` job combines and publishes the total. | |
| workflow_dispatch: | |
| inputs: | |
| coverage: | |
| description: 'Measure test coverage and publish a combined report' | |
| type: boolean | |
| default: false | |
| python-version: | |
| description: 'Python version to measure coverage on' | |
| type: string | |
| default: '3.12' | |
| concurrency: | |
| # Include the event name so a manual coverage dispatch and a push on the | |
| # same ref land in separate groups instead of cancelling each other. | |
| group: ci-${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Decide matrix scope once and fan out to every downstream job. | |
| # Full matrix (all OSes + all Python versions) runs on push to dev and | |
| # on PRs carrying the `full-ci` label. Default PR commits only run | |
| # ubuntu-latest + Python 3.14 to keep per-commit cost low. | |
| setup: | |
| name: Setup | |
| runs-on: ubuntu-latest | |
| # The `labeled` trigger fires for *any* label, but only `full-ci` should | |
| # do work. Skip the whole run when some other label is added, so stray | |
| # labels don't burn a redundant CI run. Every non-`labeled` event (push, | |
| # opened/synchronize/reopened) proceeds because github.event.action is | |
| # then not 'labeled'. When this is false the run no-ops and `all-tests` | |
| # still reports success (see its guarded step below). | |
| if: github.event.action != 'labeled' || github.event.label.name == 'full-ci' | |
| outputs: | |
| matrix: ${{ steps.compute.outputs.matrix }} | |
| warm_os: ${{ steps.compute.outputs.warm_os }} | |
| full: ${{ steps.compute.outputs.full }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Compute matrix | |
| id: compute | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| LABELS_JSON: ${{ toJSON(github.event.pull_request.labels.*.name) }} | |
| DISPATCH_PYTHON: ${{ inputs.python-version }} | |
| run: python .ci/compute_matrix.py | |
| warm-cache: | |
| name: Warm HF cache | |
| needs: setup | |
| strategy: | |
| fail-fast: false | |
| # Per-OS runners are needed because actions/cache pins by ${{ runner.os }} | |
| # so Linux test jobs only restore caches saved by a Linux runner (likewise | |
| # for Windows). The prewarm config itself is shared (.ci/hf-prewarm.yaml). | |
| matrix: | |
| os: ${{ fromJSON(needs.setup.outputs.warm_os) }} | |
| runs-on: ${{ matrix.os }} | |
| # Best-effort: an HF outage here must not cancel every PR. Test jobs | |
| # `needs: warm-cache` but proceed regardless via continue-on-error. | |
| continue-on-error: true | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Cache Hugging Face | |
| id: cache-hf | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.cache/huggingface | |
| # Stable key (no github.run_id): when the prewarm config and the | |
| # SHA pins are unchanged from a previous run, the cache restores | |
| # with cache-hit=true and the warm script is skipped entirely. | |
| # Bumping a pinned SHA invalidates the cache automatically since | |
| # hashFiles includes _pinned_revisions.py. | |
| key: ${{ runner.os }}-hf-warmed-${{ hashFiles('.ci/hf-prewarm.yaml', 'src/autointent/configs/_pinned_revisions.py') }} | |
| - name: Install uv | |
| if: steps.cache-hf.outputs.cache-hit != 'true' | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "0.10.0" | |
| - name: Run warm-cache script | |
| if: steps.cache-hf.outputs.cache-hit != 'true' | |
| env: | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| # --no-project: skip the autointent install. The warm script loads | |
| # _pinned_revisions.py via importlib.util.spec_from_file_location | |
| # specifically so it doesn't need autointent on sys.path; without | |
| # --no-project, `uv run` syncs the full project dep tree (~83 | |
| # packages, ~20s) before running. | |
| run: uv run --no-project --with 'huggingface_hub[hf_xet]' --with pyyaml --with datasets python .ci/warm_hf_cache.py --config .ci/hf-prewarm.yaml | |
| unit-tests: | |
| name: unit-tests | |
| needs: [setup, warm-cache] | |
| uses: ./.github/workflows/reusable-test.yaml | |
| secrets: inherit | |
| with: | |
| test_command: pytest -n auto --ignore=tests/modules/scoring/ --ignore=tests/pipeline --ignore=tests/embedder | |
| # wandb + codecarbon so the real WandbCallback / EmissionsTrackerCallback | |
| # tests in tests/callback/ run here instead of being skipped. | |
| extras: --extra openai --extra wandb --extra codecarbon | |
| matrix: ${{ needs.setup.outputs.matrix }} | |
| coverage_artifact: ${{ inputs.coverage && 'unit' || '' }} | |
| test-embedder: | |
| name: test-embedder | |
| needs: [setup, warm-cache] | |
| uses: ./.github/workflows/reusable-test.yaml | |
| secrets: inherit | |
| with: | |
| # --extra openai so the real OpenaiEmbeddingBackend tests (respx-mocked, | |
| # importorskip'd) actually run here instead of being skipped. | |
| test_command: pytest -n auto tests/embedder/ | |
| extras: --extra sentence-transformers --extra transformers --extra openai | |
| matrix: ${{ needs.setup.outputs.matrix }} | |
| coverage_artifact: ${{ inputs.coverage && 'embedder' || '' }} | |
| test-scorers: | |
| name: test-scorers | |
| needs: [setup, warm-cache] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| dependency-group: [ "base", "transformers", "peft", "catboost" ] | |
| uses: ./.github/workflows/reusable-test.yaml | |
| secrets: inherit | |
| with: | |
| test_command: pytest -n auto tests/modules/scoring/ | |
| extras: ${{ matrix.dependency-group != 'base' && format('--extra {0}', matrix.dependency-group) || '' }} | |
| matrix: ${{ needs.setup.outputs.matrix }} | |
| coverage_artifact: ${{ inputs.coverage && format('scorers-{0}', matrix.dependency-group) || '' }} | |
| test-presets: | |
| name: test-presets | |
| needs: [setup, warm-cache] | |
| uses: ./.github/workflows/reusable-test.yaml | |
| secrets: inherit | |
| with: | |
| test_command: pytest -n auto tests/pipeline/test_presets.py | |
| extras: --extra catboost --extra peft --extra transformers --extra sentence-transformers | |
| matrix: ${{ needs.setup.outputs.matrix }} | |
| coverage_artifact: ${{ inputs.coverage && 'presets' || '' }} | |
| test-optimization: | |
| name: test-optimization | |
| needs: [setup, warm-cache] | |
| uses: ./.github/workflows/reusable-test.yaml | |
| secrets: inherit | |
| with: | |
| test_command: pytest -n auto tests/pipeline/test_optimization.py tests/pipeline/test_pipeline_interruption.py tests/pipeline/test_validation.py | |
| extras: --extra catboost --extra peft --extra transformers --extra sentence-transformers | |
| matrix: ${{ needs.setup.outputs.matrix }} | |
| coverage_artifact: ${{ inputs.coverage && 'optimization' || '' }} | |
| test-inference: | |
| name: test-inference | |
| needs: [setup, warm-cache] | |
| uses: ./.github/workflows/reusable-test.yaml | |
| secrets: inherit | |
| with: | |
| test_command: pytest -n auto tests/pipeline/test_inference.py | |
| extras: --extra catboost --extra peft --extra transformers --extra sentence-transformers | |
| matrix: ${{ needs.setup.outputs.matrix }} | |
| coverage_artifact: ${{ inputs.coverage && 'inference' || '' }} | |
| # Single aggregator over every test fan-out so the GitHub ruleset only | |
| # needs one required check ("all-tests") instead of 54 matrix entries. | |
| # needs.<job>.result for a matrix caller is already the aggregate, so | |
| # six needs cover all combinations. `if: always()` makes this job run | |
| # even when an upstream failed, and the inner step fails on | |
| # failure/cancelled/skipped — so a skipped required check (which most | |
| # rulesets treat as not-passing) can't slip through. | |
| all-tests: | |
| name: all-tests | |
| if: always() | |
| needs: | |
| - unit-tests | |
| - test-embedder | |
| - test-presets | |
| - test-optimization | |
| - test-inference | |
| - test-scorers | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check that every test job succeeded | |
| # First clause mirrors `setup.if`: a non-`full-ci` `labeled` event | |
| # skips the whole matrix on purpose, so those skips are not a | |
| # failure and `all-tests` stays green for the unchanged SHA. Every | |
| # other event keeps the strict failure/cancelled/skipped gate. | |
| if: >- | |
| (github.event.action != 'labeled' || github.event.label.name == 'full-ci') | |
| && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')) | |
| run: | | |
| echo "One or more test jobs did not succeed:" | |
| echo '${{ toJson(needs) }}' | |
| exit 1 | |
| # Combine the per-group `.coverage.<group>` artifacts uploaded by the test | |
| # jobs into a single report. Only runs on the manual coverage dispatch. | |
| # `always()` lets it still combine the groups that succeeded if one fails, | |
| # so a single flaky group doesn't sink the whole measurement. | |
| coverage-report: | |
| name: coverage-report | |
| if: always() && github.event_name == 'workflow_dispatch' && inputs.coverage | |
| needs: | |
| - unit-tests | |
| - test-embedder | |
| - test-presets | |
| - test-optimization | |
| - test-inference | |
| - test-scorers | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "0.10.0" | |
| # merge-multiple flattens every `coverage-data-*` artifact into the | |
| # workspace root so the `.coverage.<group>` files sit next to pyproject | |
| # for `coverage combine`. | |
| - name: Download coverage data | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: coverage-data-* | |
| merge-multiple: true | |
| - name: Combine and report coverage | |
| run: uv run --no-project --with 'coverage[toml]>=7.6,<8' python .ci/coverage_report.py | |
| - name: Upload coverage report | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: | | |
| coverage.xml | |
| htmlcov/ | |
| if-no-files-found: error |