ci: bump the github-actions group across 1 directory with 2 updates #2898
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: Tests | |
| # NOTE: deliberately NO top-level `paths:` filter. "Test Suite" is a required | |
| # status check (branch ruleset), and a path-filtered workflow that is skipped | |
| # leaves that check perpetually "Expected", which blocks every PR that does not | |
| # touch Rust files (CI, build scripts, docs) until an admin bypasses it. Instead | |
| # the workflow always runs and the `changes` job below decides whether the | |
| # expensive Rust jobs actually execute — so "Test Suite" always reports a result. | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| CARGO_INCREMENTAL: 0 # Faster CI builds | |
| # Use sccache to cache compiled artifacts across runs. Complements | |
| # swatinem/rust-cache (which caches target/) by caching at the object-file | |
| # granularity, so dependency recompiles after a Cargo.lock bump or a | |
| # feature-flag change are served from cache. On a self-hosted runner the | |
| # default cache dir (~/.cache/sccache) persists across runs on disk, so | |
| # no actions/cache step is needed. | |
| RUSTC_WRAPPER: sccache | |
| # Use the mold linker on Linux for much faster linking of the large test | |
| # binaries (5-crate workspace, ~400 deps). We pass -fuse-ld=mold through | |
| # the default cc driver rather than setting mold as the linker directly, | |
| # because mold is a linker, not a driver, and does not understand gcc | |
| # driver flags like -m64. | |
| # | |
| # NOTE: Setting RUSTFLAGS here replaces the target.cfg.rustflags from | |
| # .cargo/config.toml (cargo treats these as mutually exclusive sources). | |
| # That is intentional for CI: the dropped flags (--remap-path-prefix, | |
| # --build-id=none, --hash-style=gnu, --no-undefined) are reproducibility- | |
| # only and irrelevant for tests. We keep -C debuginfo=0 for faster test | |
| # compiles. The Docker reproducible build does not set RUSTFLAGS, so it | |
| # keeps using the full .cargo/config.toml rustflags with ld. | |
| RUSTFLAGS: "-C debuginfo=0 -C link-arg=-fuse-ld=mold" | |
| jobs: | |
| # Decide whether the Rust test jobs need to run. Covers the same path set the | |
| # old `on:` filter used, plus rust-toolchain.toml and .cargo/config.toml (which | |
| # affect the build but the old filter omitted). Fails safe: anything we can't | |
| # classify (new branch, detection error) is treated as "run the tests". | |
| changes: | |
| name: Detect changes | |
| runs-on: [self-hosted, infra] | |
| permissions: | |
| contents: read | |
| outputs: | |
| rust: ${{ steps.detect.outputs.rust }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 # need history to diff the PR / push range | |
| - name: Detect Rust-relevant changes | |
| id: detect | |
| run: | | |
| EVENT="${{ github.event_name }}" | |
| CHANGED="" | |
| if [ "$EVENT" = "pull_request" ]; then | |
| CHANGED=$(git diff --name-only \ | |
| "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" 2>/dev/null) | |
| elif [ "$EVENT" = "push" ] && \ | |
| [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then | |
| CHANGED=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" 2>/dev/null) | |
| fi | |
| echo "Changed files:" | |
| echo "$CHANGED" | |
| # Default to running tests; only skip when we have a concrete file list | |
| # and none of it is Rust-relevant. | |
| RUST=true | |
| if [ -n "$CHANGED" ] && ! echo "$CHANGED" | grep -qE \ | |
| '(\.rs$|(^|/)Cargo\.(toml|lock)$|^crates/database/src/migrations/|^\.github/workflows/test\.yml$|^\.github/actions/setup-rust-ci/|^\.config/nextest\.toml$|^rust-toolchain\.toml$|^\.cargo/config\.toml$)'; then | |
| RUST=false | |
| fi | |
| echo "rust=$RUST" >> "$GITHUB_OUTPUT" | |
| echo "Decision: run Rust test jobs = $RUST" | |
| lint: | |
| name: Lint | |
| needs: changes | |
| if: ${{ needs.changes.outputs.rust == 'true' }} | |
| runs-on: [self-hosted, infra] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup Rust CI | |
| uses: ./.github/actions/setup-rust-ci | |
| with: | |
| cache-key: lint | |
| components: rustfmt, clippy | |
| - name: Run cargo fmt | |
| run: cargo fmt --all -- --check | |
| # Clippy reuses the same target/ dir as tests, so this also warms the | |
| # sccache + rust-cache for the parallel test jobs. | |
| - name: Run cargo clippy | |
| run: cargo clippy --all-targets --all-features -- -D warnings | |
| # Unit tests (library + binary tests) run without PostgreSQL: the in-crate | |
| # #[test] functions use mocks and do not establish real DB connections. | |
| unit-test: | |
| name: Unit tests | |
| needs: changes | |
| if: ${{ needs.changes.outputs.rust == 'true' }} | |
| runs-on: [self-hosted, infra] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup Rust CI | |
| uses: ./.github/actions/setup-rust-ci | |
| with: | |
| cache-key: unit | |
| - name: Run unit tests | |
| run: cargo nextest run --lib --bins | |
| env: | |
| POSTGRES_PRIMARY_APP_ID: ${{ secrets.POSTGRES_PRIMARY_APP_ID }} | |
| DATABASE_HOST: localhost | |
| DATABASE_PORT: 5432 | |
| DATABASE_NAME: platform_api | |
| DATABASE_USERNAME: postgres | |
| DATABASE_PASSWORD: postgres | |
| DATABASE_MAX_CONNECTIONS: 5 | |
| DATABASE_TLS_ENABLED: "false" | |
| MODEL_DISCOVERY_SERVER_URL: ${{ secrets.MODEL_DISCOVERY_SERVER_URL }} | |
| MODEL_DISCOVERY_API_KEY: ${{ secrets.MODEL_DISCOVERY_API_KEY }} | |
| AUTH_ADMIN_DOMAINS: ${{ secrets.AUTH_ADMIN_DOMAINS }} | |
| AUTH_ENCODING_KEY: ${{ secrets.AUTH_ENCODING_KEY }} | |
| BRAVE_SEARCH_PRO_API_KEY: ${{ secrets.BRAVE_SEARCH_PRO_API_KEY }} | |
| DEV: "true" | |
| # vLLM provider integration tests. Uses MockProvider by default | |
| # (USE_REAL_VLLM is not set), so these run without external dependencies | |
| # and without PostgreSQL. Kept as a separate job so a flake here doesn't | |
| # block the e2e suite. | |
| integration-test: | |
| name: Integration tests | |
| needs: changes | |
| if: ${{ needs.changes.outputs.rust == 'true' }} | |
| runs-on: [self-hosted, infra] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup Rust CI | |
| uses: ./.github/actions/setup-rust-ci | |
| with: | |
| cache-key: integration | |
| - name: Run integration tests | |
| run: cargo nextest run --test integration_tests | |
| env: | |
| VLLM_BASE_URL: ${{ secrets.VLLM_BASE_URL }} | |
| VLLM_API_KEY: ${{ secrets.VLLM_API_KEY }} | |
| # End-to-end tests. All e2e tests are compiled into a single binary | |
| # (tests/e2e_all/) for faster linking. Isolation comes from UUID-scoped | |
| # orgs/workspaces/keys on a shared database, not separate databases. | |
| # nextest concurrency is capped by .config/nextest.toml (e2e-db group | |
| # max-threads = 16; 16 * 4 pool conns = 64 < PG default max_connections | |
| # = 100), so no ALTER SYSTEM / restart step is needed. | |
| e2e-test: | |
| name: E2E tests | |
| needs: changes | |
| if: ${{ needs.changes.outputs.rust == 'true' }} | |
| runs-on: [self-hosted, infra] | |
| environment: Cloud API test env | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: platform_api | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| --shm-size=256mb | |
| ports: | |
| - 5432:5432 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup Rust CI | |
| uses: ./.github/actions/setup-rust-ci | |
| with: | |
| cache-key: e2e | |
| - name: Run e2e tests | |
| run: cargo nextest run --test e2e_all | |
| env: | |
| POSTGRES_PRIMARY_APP_ID: ${{ secrets.POSTGRES_PRIMARY_APP_ID }} | |
| DATABASE_HOST: localhost | |
| DATABASE_PORT: 5432 | |
| DATABASE_NAME: platform_api | |
| DATABASE_USERNAME: postgres | |
| DATABASE_PASSWORD: postgres | |
| DATABASE_MAX_CONNECTIONS: 5 | |
| DATABASE_TLS_ENABLED: "false" | |
| MODEL_DISCOVERY_SERVER_URL: ${{ secrets.MODEL_DISCOVERY_SERVER_URL }} | |
| MODEL_DISCOVERY_API_KEY: ${{ secrets.MODEL_DISCOVERY_API_KEY }} | |
| AUTH_ENCODING_KEY: ${{ secrets.AUTH_ENCODING_KEY }} | |
| AUTH_ADMIN_DOMAINS: ${{ secrets.AUTH_ADMIN_DOMAINS }} | |
| BRAVE_SEARCH_PRO_API_KEY: ${{ secrets.BRAVE_SEARCH_PRO_API_KEY }} | |
| TEST_DATABASE_NAME: platform_api_e2e | |
| RUST_LOG: debug | |
| DEV: "true" | |
| # Aggregates all test jobs into a single required status check. The branch | |
| # ruleset requires "Test Suite", so this job MUST always run and always report | |
| # a result (note `if: always()` plus no `paths:` filter on the workflow) — | |
| # otherwise the required check stays "Expected" forever and blocks the PR. | |
| # When there are no Rust-relevant changes the test jobs are skipped and this | |
| # gate passes; otherwise every test job must have succeeded. | |
| test-suite: | |
| name: Test Suite | |
| runs-on: [self-hosted, infra] | |
| needs: [changes, lint, unit-test, integration-test, e2e-test] | |
| if: always() | |
| steps: | |
| - name: Check all tests passed | |
| run: | | |
| # Fail closed if change detection itself failed — we can't safely | |
| # conclude tests were unnecessary. | |
| if [[ "${{ needs.changes.result }}" != "success" ]]; then | |
| echo "Change-detection job did not succeed (${{ needs.changes.result }}); failing closed." | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.changes.outputs.rust }}" != "true" ]]; then | |
| echo "No Rust-relevant changes — test jobs were skipped. Nothing to verify." | |
| exit 0 | |
| fi | |
| failed=0 | |
| for jr in "Lint=${{ needs.lint.result }}" \ | |
| "Unit tests=${{ needs.unit-test.result }}" \ | |
| "Integration tests=${{ needs.integration-test.result }}" \ | |
| "E2E tests=${{ needs.e2e-test.result }}"; do | |
| name="${jr%%=*}"; res="${jr#*=}" | |
| if [[ "$res" != "success" ]]; then | |
| echo "FAIL ${name}: ${res}" | |
| failed=1 | |
| else | |
| echo "OK ${name}: success" | |
| fi | |
| done | |
| if [[ "$failed" -ne 0 ]]; then | |
| echo "One or more test jobs did not succeed" | |
| exit 1 | |
| fi | |
| echo "All test jobs passed" | |
| # Release build, only on main pushes. Split into its own job so it does | |
| # not block the test jobs and does not pull in PostgreSQL or test env vars | |
| # (there is no build.rs; cargo build --release needs none of them). | |
| build-release: | |
| name: Build release | |
| needs: changes | |
| if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.rust == 'true' }} | |
| runs-on: [self-hosted, infra] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup Rust CI | |
| uses: ./.github/actions/setup-rust-ci | |
| with: | |
| cache-key: release | |
| - name: Build release | |
| run: cargo build --release |