| name: CI |
|
|
| on: |
| push: |
| branches: [main] |
| pull_request: |
| workflow_dispatch: |
|
|
| concurrency: |
| group: ${{ github.workflow }}-${{ github.ref }} |
| cancel-in-progress: true |
|
|
| env: |
| |
| LEXORA_VAR_DIR: ${{ github.workspace }}/var |
|
|
| jobs: |
| api: |
| name: API — lint, types, tests |
| runs-on: ubuntu-latest |
| timeout-minutes: 25 |
| steps: |
| - uses: actions/checkout@v7 |
|
|
| |
| |
| - uses: astral-sh/setup-uv@v9.0.0 |
| with: |
| enable-cache: true |
|
|
| - name: Install |
| run: | |
| uv venv --python 3.12 apps/api/.venv |
| uv pip install --python apps/api/.venv/bin/python -e "apps/api[dev]" |
| |
| |
| |
| - name: Cache ONNX models |
| uses: actions/cache@v6 |
| with: |
| path: var/models |
| key: onnx-${{ runner.os }}-${{ hashFiles('apps/api/pyproject.toml') }} |
|
|
| - name: Fetch the corpus |
| run: apps/api/.venv/bin/python corpus/download.py |
|
|
| - name: Build the index |
| run: apps/api/.venv/bin/python -m app.rag.index |
| env: |
| PYTHONPATH: apps/api |
|
|
| - name: Verify the eval labels against the corpus |
| run: apps/api/.venv/bin/python eval/build_questions.py |
|
|
| - name: ruff |
| run: | |
| apps/api/.venv/bin/ruff check . |
| apps/api/.venv/bin/ruff format --check . |
| |
| - name: mypy --strict |
| run: apps/api/.venv/bin/mypy |
|
|
| - name: pytest |
| run: apps/api/.venv/bin/python -m pytest |
|
|
| |
| |
| |
| - name: Evaluate retrieval and gate on it |
| run: | |
| apps/api/.venv/bin/python eval/ragas_run.py |
| apps/api/.venv/bin/python scripts/quality_gate.py |
| |
| - uses: actions/upload-artifact@v7 |
| if: always() |
| with: |
| name: eval-results |
| path: eval/results/ |
|
|
| web: |
| name: Web — types, lint, build |
| runs-on: ubuntu-latest |
| timeout-minutes: 15 |
| defaults: |
| run: |
| working-directory: apps/web |
| steps: |
| - uses: actions/checkout@v7 |
|
|
| - uses: actions/setup-node@v7 |
| with: |
| node-version: "22" |
| cache: npm |
| cache-dependency-path: apps/web/package-lock.json |
|
|
| - run: npm ci |
| - run: npx tsc --noEmit |
| - run: npx eslint . --max-warnings 0 |
| - run: npm run build |
|
|
| container: |
| name: Container builds |
| runs-on: ubuntu-latest |
| timeout-minutes: 30 |
| needs: api |
| steps: |
| - uses: actions/checkout@v7 |
| - uses: astral-sh/setup-uv@v9.0.0 |
| - name: Rebuild the portable index the image copies in |
| run: | |
| uv venv --python 3.12 apps/api/.venv |
| uv pip install --python apps/api/.venv/bin/python -e "apps/api" |
| apps/api/.venv/bin/python corpus/download.py |
| PYTHONPATH=apps/api apps/api/.venv/bin/python -m app.rag.index |
| |
| |
| - name: Build the image |
| shell: bash |
| run: docker build --progress=plain -t lexora-api:ci . 2>&1 | tee build.log |
|
|
| |
| |
| |
| - name: Bake stages stayed within their memory budget |
| run: apps/api/.venv/bin/python scripts/check_bake_budget.py build.log |
| - name: Boot it and check readiness |
| run: | |
| docker run -d --name lexora -p 7860:7860 lexora-api:ci |
| for _ in $(seq 1 60); do |
| if curl -fsS http://127.0.0.1:7860/api/health | grep -q '"status":"ok"'; then |
| echo "container healthy"; exit 0 |
| fi |
| sleep 5 |
| done |
| echo "container did not become healthy"; docker logs lexora; exit 1 |
| |