fix(ci): unbreak notebook quality gates first CI exercise
All checks were successful
CI / lint (push) Successful in 29s
CI / notebooks-smoke (push) Successful in 1m31s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Deploy / report (push) Successful in 14s
CI / test (push) Successful in 13m32s
All checks were successful
CI / lint (push) Successful in 29s
CI / notebooks-smoke (push) Successful in 1m31s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Deploy / report (push) Successful in 14s
CI / test (push) Successful in 13m32s
Three failures from 187e776's first run: - notebooks-smoke: _template.py opens data/aco.duckdb read-only, which doesn't exist in a fresh checkout — stub an empty-but-valid database before the run (information_schema queries return zero rows, fine). - notebooks-integration FE smoke: treat CellNotInitializedError as benign. The nightly run regenerates session snapshots; with auto_instantiate=false the editor renders cached UI elements whose cells aren't running and logs this error on every such notebook. Verified against live prod: editor probe now passes. - notebooks-integration failure step: 'uv: command not found' — the job had no setup-uv step, so api.diag.ci could never file on failure.
This commit is contained in:
@@ -79,8 +79,17 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: uv sync --dev
|
run: uv sync --dev
|
||||||
|
|
||||||
|
- name: Stub aco.duckdb
|
||||||
|
# The checkout has no data volume; conf.connect.duckdb() opens
|
||||||
|
# data/aco.duckdb read-only and fails if it doesn't exist. An
|
||||||
|
# empty-but-valid database is enough for the ci-smoke notebooks
|
||||||
|
# (schema browsing over information_schema returns zero rows).
|
||||||
|
run: |
|
||||||
|
[ -f data/aco.duckdb ] || uv run python -c \
|
||||||
|
"import duckdb; duckdb.connect('data/aco.duckdb').close()"
|
||||||
|
|
||||||
- name: Run data-independent notebooks headless
|
- name: Run data-independent notebooks headless
|
||||||
# Executes the [ci_smoke] set from notebooks/nb-tests.toml via
|
# Executes the [ci_smoke] set from infra/marimo/nb-tests.toml via
|
||||||
# `marimo export session` and fails on any cell error. Runs on
|
# `marimo export session` and fails on any cell error. Runs on
|
||||||
# every push (not path-gated): notebooks import src/ modules, so
|
# every push (not path-gated): notebooks import src/ modules, so
|
||||||
# src changes can break them too.
|
# src changes can break them too.
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://github.com/actions/checkout@v4
|
uses: https://github.com/actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up uv
|
||||||
|
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
env:
|
||||||
|
UV_INSTALL_DIR: /usr/local/bin
|
||||||
|
|
||||||
- name: Run full notebook set in prod container
|
- name: Run full notebook set in prod container
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
||||||
|
|||||||
@@ -196,8 +196,17 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: uv sync --dev
|
run: uv sync --dev
|
||||||
|
|
||||||
|
- name: Stub aco.duckdb
|
||||||
|
# The checkout has no data volume; conf.connect.duckdb() opens
|
||||||
|
# data/aco.duckdb read-only and fails if it doesn't exist. An
|
||||||
|
# empty-but-valid database is enough for the ci-smoke notebooks
|
||||||
|
# (schema browsing over information_schema returns zero rows).
|
||||||
|
run: |
|
||||||
|
[ -f data/aco.duckdb ] || uv run python -c \\
|
||||||
|
"import duckdb; duckdb.connect('data/aco.duckdb').close()"
|
||||||
|
|
||||||
- name: Run data-independent notebooks headless
|
- name: Run data-independent notebooks headless
|
||||||
# Executes the [ci_smoke] set from notebooks/nb-tests.toml via
|
# Executes the [ci_smoke] set from infra/marimo/nb-tests.toml via
|
||||||
# `marimo export session` and fails on any cell error. Runs on
|
# `marimo export session` and fails on any cell error. Runs on
|
||||||
# every push (not path-gated): notebooks import src/ modules, so
|
# every push (not path-gated): notebooks import src/ modules, so
|
||||||
# src changes can break them too.
|
# src changes can break them too.
|
||||||
@@ -226,6 +235,7 @@ def _gen_deploy(
|
|||||||
name = img["name"]
|
name = img["name"]
|
||||||
job_names.append(name)
|
job_names.append(name)
|
||||||
paths = img.get("path_filter", [])
|
paths = img.get("path_filter", [])
|
||||||
|
|
||||||
# Gitea Actions doesn't support `paths:` on push without branches,
|
# Gitea Actions doesn't support `paths:` on push without branches,
|
||||||
# so use `if: contains(...)` on the modified files list.
|
# so use `if: contains(...)` on the modified files list.
|
||||||
def _clean_path(p: str) -> str:
|
def _clean_path(p: str) -> str:
|
||||||
@@ -505,7 +515,9 @@ jobs:
|
|||||||
return (".gitea/workflows/infra-ci.yml", content)
|
return (".gitea/workflows/infra-ci.yml", content)
|
||||||
|
|
||||||
|
|
||||||
def _gen_notebooks_integration(runner: str, **_kw: object) -> tuple[str, str]:
|
def _gen_notebooks_integration(
|
||||||
|
runner: str, uv_version: str, **_kw: object
|
||||||
|
) -> tuple[str, str]:
|
||||||
"""Nightly full-set notebook run inside the production container.
|
"""Nightly full-set notebook run inside the production container.
|
||||||
|
|
||||||
The full notebook set needs real data (aco.duckdb, ./data mounts) that
|
The full notebook set needs real data (aco.duckdb, ./data mounts) that
|
||||||
@@ -530,6 +542,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
{_checkout_step()}
|
{_checkout_step()}
|
||||||
|
|
||||||
|
{_setup_uv_step(uv_version)}
|
||||||
|
|
||||||
- name: Run full notebook set in prod container
|
- name: Run full notebook set in prod container
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{{{ secrets.DEPLOY_TOKEN }}}}
|
GITEA_TOKEN: ${{{{ secrets.DEPLOY_TOKEN }}}}
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ PLAYWRIGHT_IMAGE = "mcr.microsoft.com/playwright/python:v1.61.0-noble"
|
|||||||
PLAYWRIGHT_PKG = "playwright==1.61.0"
|
PLAYWRIGHT_PKG = "playwright==1.61.0"
|
||||||
READY_TIMEOUT_S = 120
|
READY_TIMEOUT_S = 120
|
||||||
|
|
||||||
|
# Console errors that are expected marimo behavior, not bundle breakage.
|
||||||
|
# CellNotInitializedError: with auto_instantiate=false the editor renders
|
||||||
|
# cached UI elements from a session snapshot whose cells aren't running in
|
||||||
|
# the kernel — every interaction with them logs this error. Appears on any
|
||||||
|
# notebook that has a __marimo__/session snapshot (e.g. right after the
|
||||||
|
# nightly integration run regenerates them).
|
||||||
|
BENIGN_ERRORS = ("CellNotInitializedError",)
|
||||||
|
|
||||||
# Dependency-free notebook shipped into the throwaway container. Markdown
|
# Dependency-free notebook shipped into the throwaway container. Markdown
|
||||||
# only, so it renders identically under any runtime config (the bare image
|
# only, so it renders identically under any runtime config (the bare image
|
||||||
# has no marimo.toml, and marimo's default auto_instantiate=true would run
|
# has no marimo.toml, and marimo's default auto_instantiate=true would run
|
||||||
@@ -146,6 +154,7 @@ def check(result: dict, *, expect_text: str | None) -> list[str]:
|
|||||||
f"[{e['type']}] {e['text'][:300]}"
|
f"[{e['type']}] {e['text'][:300]}"
|
||||||
for e in result["events"]
|
for e in result["events"]
|
||||||
if e["type"] in ("error", "pageerror")
|
if e["type"] in ("error", "pageerror")
|
||||||
|
and not any(b in e["text"] for b in BENIGN_ERRORS)
|
||||||
]
|
]
|
||||||
if expect_text and expect_text not in result["body"]:
|
if expect_text and expect_text not in result["body"]:
|
||||||
problems.append(
|
problems.append(
|
||||||
|
|||||||
Reference in New Issue
Block a user