Add workflow runtime conformance and Docker acceptance #23
Workflow file for this run
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: | |
| - main | |
| - develop | |
| - codex/** | |
| pull_request: | |
| workflow_dispatch: | |
| jobs: | |
| extension: | |
| runs-on: ubuntu-latest | |
| name: Browser Extension | |
| defaults: | |
| run: | |
| working-directory: chrome/extension-src | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: npm | |
| cache-dependency-path: chrome/extension-src/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Typecheck | |
| run: npm run typecheck | |
| - name: Build | |
| run: npm run build | |
| - name: Upload extension dist | |
| uses: actions/upload-artifact@v4 | |
| if: success() | |
| with: | |
| name: extension-dist | |
| path: chrome/extension-src/dist | |
| backend: | |
| runs-on: ubuntu-latest | |
| name: Backend Quality | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[dev] | |
| - name: Backend syntax check | |
| run: python -m compileall backend | |
| # Coverage visibility, not a gate: pyproject.toml bakes in | |
| # `--cov-fail-under=80` via [tool.pytest.ini_options].addopts, but the | |
| # current suite sits at ~70% total. Enforcing 80% here would turn CI red | |
| # immediately for pre-existing gaps, not for anything this PR changes. | |
| # `--cov-fail-under=0` overrides the pyproject default (last CLI value | |
| # wins) so the job stays green while the report is printed every run. | |
| # TODO(ratchet): once real coverage is measured for a few weeks, raise | |
| # this floor incrementally (e.g. 70 -> 75 -> 80) instead of jumping | |
| # straight to the pyproject target. | |
| - name: Unit tests (with coverage report) | |
| run: pytest tests/unit -m "not live" --cov=backend --cov-report=term-missing --cov-fail-under=0 | |
| migrations: | |
| runs-on: ubuntu-latest | |
| name: Alembic Migrations | |
| services: | |
| postgres: | |
| image: postgres:16-alpine | |
| env: | |
| POSTGRES_DB: opencli_admin | |
| POSTGRES_USER: opencli | |
| POSTGRES_PASSWORD: opencli_secret | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U opencli" | |
| --health-interval 5s | |
| --health-timeout 3s | |
| --health-retries 10 | |
| env: | |
| # backend/config.py Settings.database_url (case-insensitive env, | |
| # see backend/migrations/env.py which overrides alembic.ini's | |
| # sqlalchemy.url from settings.database_url at runtime). | |
| DATABASE_URL: postgresql+asyncpg://opencli:opencli_secret@localhost:5432/opencli_admin | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[dev] | |
| - name: Wait for Postgres | |
| run: python -c "import time; time.sleep(2)" | |
| - name: alembic upgrade head | |
| run: alembic upgrade head | |
| # Catches broken downgrade() bodies / non-reversible migrations before | |
| # merge: a chain that only ever gets tested via upgrade() can silently | |
| # rot (dropped columns with no re-add, wrong op order, etc.). | |
| - name: alembic downgrade/upgrade smoke test | |
| run: | | |
| alembic downgrade -1 | |
| alembic upgrade head | |
| # AUDIT follow-up (c): the cursor concurrency tests run on SQLite in the | |
| # backend job, where `SELECT ... FOR UPDATE` is a silent no-op — they | |
| # prove the code path but not that the lock serializes writers. Re-run the | |
| # Postgres-gated variant here (schema already at head above, DATABASE_URL | |
| # is Postgres so the test's skip-gate activates), where the row lock is | |
| # actually enforced, so a regression in cursor_store's per-source locking | |
| # is caught. --no-cov: this is a targeted single-test step, not a coverage | |
| # run (pyproject's addopts would otherwise fail it under the 80% gate). | |
| - name: cursor FOR UPDATE locking (Postgres) | |
| run: pytest tests/unit/pipeline/test_db_cursor_store.py -k postgres --no-cov -p no:cacheprovider | |
| cargo: | |
| runs-on: ubuntu-latest | |
| name: ODP Rust (odp-rs) | |
| defaults: | |
| run: | |
| working-directory: odp-rs | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| odp-rs/target | |
| key: ${{ runner.os }}-cargo-odp-rs-${{ hashFiles('odp-rs/Cargo.lock', 'odp-rs/**/Cargo.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-odp-rs- | |
| # No live Redis/Postgres here: odp-bus/odp-ingest/odp-store tests are | |
| # unit-level (dedup logic, contract (de)serialization, stream naming). | |
| # If integration tests that need a real broker/DB are added later, gate | |
| # them behind a feature flag or #[ignore] + a service-container job, | |
| # the same way `pytest -m live` is deselected in the backend job. | |
| - name: cargo test --workspace | |
| run: cargo test --workspace | |
| - name: cargo clippy --workspace -- -D warnings | |
| run: cargo clippy --workspace --all-targets -- -D warnings |