ci: GitHub Actions — lint + unit tests per component #1
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
| # adscope CI — lint + unit tests per component, no paid services, no secrets. | |
| # | |
| # Design: the GATE is four fast jobs that need NO heavy runtime services | |
| # (no Postgres, no Redpanda, no Ollama, no built warehouse). Each mirrors | |
| # exactly how a developer runs that component locally, so a green check here | |
| # means the component compiles, lints clean, and its self-contained tests pass. | |
| # | |
| # Deliberately scoped OUT of CI (run locally against `docker compose up`): | |
| # * collectors integration tests — the 10 `#[ignore]` tests in | |
| # crates/cli/tests/compose_it.rs need the live compose stack; `cargo test` | |
| # skips them by default, which is what we want here. | |
| # * full `dbt build` — needs Postgres + the collector-loaded raw | |
| # layer; this workflow only does `dbt deps` + `dbt parse` (compiles the | |
| # project graph, no database connection). See the `warehouse` job. | |
| # * rag pgvector integration + eval CLI — the pgvector test is behind the | |
| # `integration` marker (needs a live pgvector Postgres) and the eval CLI | |
| # needs the built DuckDB marts; both are deselected/omitted here. | |
| # Pulling any of those into CI would require standing up the whole stack per | |
| # run — slow and flaky. They are covered by `make` targets against a local | |
| # `docker compose up` instead. | |
| # | |
| # Free-tier friendly: cargo + uv caches, concurrency cancels superseded runs, | |
| # read-only token, all actions pinned to a major version. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| # One in-flight run per ref; a new push cancels the previous one (saves minutes). | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Least privilege — CI only needs to read the checked-out code. | |
| permissions: | |
| contents: read | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # collectors (Rust workspace) — fmt + clippy (warnings = errors) + unit tests. | |
| # SQLX_OFFLINE makes the sqlx compile-time query macros read the committed | |
| # `.sqlx/` cache instead of connecting to Postgres, so no database is needed. | |
| # `cargo test --workspace` runs unit tests; the `#[ignore]` compose-stack | |
| # integration tests stay skipped. | |
| # --------------------------------------------------------------------------- | |
| collectors: | |
| name: collectors (rust) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: collectors | |
| env: | |
| SQLX_OFFLINE: "true" | |
| CARGO_TERM_COLOR: always | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Honors collectors/rust-toolchain.toml (channel = stable); adds the two | |
| # components the lint steps need. | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Cache cargo build | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: collectors | |
| - name: Format check | |
| run: cargo fmt --check | |
| - name: Clippy (deny warnings) | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: Unit tests | |
| run: cargo test --workspace | |
| # --------------------------------------------------------------------------- | |
| # simulator (FastAPI, Python/uv) — ruff lint + format check + pytest. | |
| # 93 tests, all in-process (FastAPI TestClient); no external services. | |
| # Dev tools (pytest, ruff) live in [dependency-groups], synced by default. | |
| # --------------------------------------------------------------------------- | |
| simulator: | |
| name: simulator (python) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: services/simulator | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: services/simulator/uv.lock | |
| - name: Sync (locked) | |
| run: uv sync --locked | |
| - name: Ruff lint | |
| run: uv run ruff check | |
| - name: Ruff format check | |
| run: uv run ruff format --check | |
| - name: Pytest | |
| run: uv run pytest | |
| # --------------------------------------------------------------------------- | |
| # rag (NL -> guarded DuckDB SQL, Python/uv) — ruff lint + pytest. | |
| # The default suite is deterministic and dependency-free: hashing embedder, | |
| # in-memory vector store, FakeLLM — no model, no network, no Postgres. | |
| # Dev tools live in [project.optional-dependencies].dev, hence `--extra dev`. | |
| # `-m "not integration and not live_llm"` drops the pgvector + live-model | |
| # tests (they self-skip anyway, but excluding them keeps intent explicit). | |
| # --------------------------------------------------------------------------- | |
| rag: | |
| name: rag (python) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: rag | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: rag/uv.lock | |
| - name: Sync (locked, dev extra) | |
| run: uv sync --locked --extra dev | |
| - name: Ruff lint | |
| run: uv run ruff check | |
| - name: Pytest (deterministic core) | |
| run: uv run pytest -m "not integration and not live_llm" | |
| # --------------------------------------------------------------------------- | |
| # warehouse (dbt-duckdb) — lightweight graph check, NOT a full build. | |
| # `dbt parse` compiles the whole project (models, sources, refs, macros, | |
| # Jinja, dbt_utils tests) into a manifest WITHOUT opening a database | |
| # connection, so it catches broken SQL/refs with zero services. A real | |
| # `dbt build` needs Postgres + the collector-loaded raw layer and is run | |
| # locally via `make` against `docker compose up`. `dbt deps` fetches | |
| # dbt_utils from the (free, no-auth) dbt Hub; DBT_PROFILES_DIR points at the | |
| # in-repo profiles.yml. | |
| # --------------------------------------------------------------------------- | |
| warehouse: | |
| name: warehouse (dbt) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: warehouse | |
| env: | |
| DBT_PROFILES_DIR: ${{ github.workspace }}/warehouse | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: warehouse/uv.lock | |
| - name: Sync (locked) | |
| run: uv sync --locked | |
| - name: dbt deps | |
| run: uv run dbt deps | |
| - name: dbt parse (compile graph, no database) | |
| run: uv run dbt parse |