Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
175 commits
Select commit Hold shift + click to select a range
18a7fbd
docs: add CI performance and warm Docker CI research
paddymul Mar 1, 2026
963b499
WIP, questions for claude
paddymul Mar 1, 2026
bddcfe5
docs: address review questions on Hetzner CI plan
paddymul Mar 1, 2026
62aeddb
feat: implement Hetzner self-hosted CI
paddymul Mar 1, 2026
aea3201
feat: add ci/hetzner/lib helpers and fix .gitignore
paddymul Mar 1, 2026
282e357
fix: cloud-init owner/yaml bugs; status.sh no-op without GITHUB_TOKEN
paddymul Mar 1, 2026
5ee2550
fix: Dockerfile needs build-essential for cffi/cryptography; cloud-in…
paddymul Mar 1, 2026
76bf7e0
fix: git safe.directory in container, --allow-root for jupyter, remov…
paddymul Mar 1, 2026
58531f9
fix: bake CI runner scripts into image to survive git checkout of any…
paddymul Mar 1, 2026
34edec3
fix: remove uv sync from job_lint_python to prevent venv race condition
paddymul Mar 1, 2026
5e95917
fix: bake jupyter_lab_config.py to allow root in Docker container
paddymul Mar 1, 2026
acf9176
fix: deselect Docker-incompatible tests; skip Python 3.14 alpha
paddymul Mar 1, 2026
a373b9b
docs: update hetzner-ci-bringup with final clean run results
paddymul Mar 2, 2026
f05e4d7
perf: parallelize Phase 3 Python tests (3.11/3.12/3.14)
paddymul Mar 2, 2026
1773af1
docs: add warm cache and parallel Phase 3 timing results
paddymul Mar 2, 2026
66f8038
perf: parallelize Phase 5 playwright tests
paddymul Mar 2, 2026
b1ec8cd
fix: resolve parallel Phase 5 venv races
paddymul Mar 2, 2026
e130e1f
feat: add DAG-based CI orchestrator and research docs
paddymul Mar 2, 2026
185f3a7
fix: apply venv and HTML report isolation to run-ci-dag.sh
paddymul Mar 2, 2026
e9b102a
feat: add parallel Playwright jupyter test runner
paddymul Mar 2, 2026
29e8752
feat: use parallel jupyter playwright runner in CI
paddymul Mar 2, 2026
50bc763
fix: bake test_playwright_jupyter_parallel.sh into /opt/ci-runner/
paddymul Mar 2, 2026
1ed1e16
fix: preserve exit code through rm -rf in job_playwright_jupyter
paddymul Mar 2, 2026
06b65f9
fix: respect ROOT_DIR env var in parallel jupyter script
paddymul Mar 2, 2026
4064949
perf: split build-js from test-js in DAG for earlier wheel build
paddymul Mar 2, 2026
6acc85d
fix: move pw-marimo and pw-wasm-marimo to wheel-dependent jobs
paddymul Mar 2, 2026
9aa6a3e
fix: add XXXXXX to mktemp template for Linux compatibility
paddymul Mar 2, 2026
b27e42b
feat: log CI runner version at start of each run
paddymul Mar 2, 2026
73ad85a
docs: add implementation-notes.md with CI lessons learned
paddymul Mar 2, 2026
e14f2a0
fix: guard arithmetic ops with || true to prevent set -e early exit
paddymul Mar 2, 2026
8462cab
perf: lower PARALLEL jupyter to 3 (was 9, caused widget comm failures)
paddymul Mar 2, 2026
e49fe9b
perf: split Phase 5 — jupyter runs after other playwright jobs (5a→5b)
paddymul Mar 2, 2026
37fb477
docs: update implementation-notes with parallel jupyter bugs
paddymul Mar 2, 2026
6a8234b
fix: shutdown kernels between batches in parallel jupyter runner
paddymul Mar 2, 2026
ad02d52
fix: use explicit batching instead of sliding window for jupyter para…
paddymul Mar 2, 2026
b9cf8d3
fix: || true on shutdown_kernels pipelines, fix BATCH_PIDS re-declare
paddymul Mar 2, 2026
b23449a
fix: set PARALLEL=1 for jupyter notebooks (800ms wait too short for >1)
paddymul Mar 2, 2026
16ac102
feat: add stress-test.sh with safe, failing, and older commit sets
paddymul Mar 2, 2026
1759612
fix: trust notebooks and fix shutdown_kernels JSON parsing in paralle…
paddymul Mar 2, 2026
517e54a
docs: update implementation notes with run 26 results and new bugs found
paddymul Mar 2, 2026
60a22aa
feat: add stress-test.sh and download-ci-logs.sh for CI validation
paddymul Mar 2, 2026
affe14a
fix: clean stale kernel runtime files + enable PARALLEL=3 for Phase 5b
paddymul Mar 2, 2026
72c463c
docs: record stale runtime kernel files bug + PARALLEL=3 update
paddymul Mar 2, 2026
27297dd
revert: PARALLEL=3 → 1 for playwright-jupyter
paddymul Mar 2, 2026
c8b3ff9
docs: record PARALLEL=3 failure + batch-1 timing root cause
paddymul Mar 2, 2026
2ae4c00
ci: ignore mp_timeout_decorator_test.py entirely in Docker
paddymul Mar 2, 2026
f9dc8c1
ci: add stagger runner and stress-test --stagger flag
paddymul Mar 2, 2026
995e61d
ci: add serial runner to measure uncontended job timings
paddymul Mar 2, 2026
9635008
ci: harden playwright-jupyter batch-1 and fix mcp-wheel exit code
paddymul Mar 2, 2026
4871500
ci: fix warmup pipefail exit triggering cleanup trap
paddymul Mar 2, 2026
9a6122b
docs: update implementation notes with purpose, timings, and next steps
paddymul Mar 2, 2026
65d49b2
ci: replace static waitForTimeout with proper waitFor in Jupyter spec…
paddymul Mar 2, 2026
5e86490
ci: try PARALLEL=2 for playwright-jupyter (PARALLEL=3 causes WebSocke…
paddymul Mar 2, 2026
e8c429c
ci: increase cell execution timeout to 20s for concurrent kernel startup
paddymul Mar 2, 2026
55707c1
ci: revert to PARALLEL=1 for playwright-jupyter — PARALLEL>1 causes Z…
paddymul Mar 2, 2026
f46971d
ci: isolated JupyterLab server per parallel slot — eliminates ZMQ con…
paddymul Mar 2, 2026
d6bc031
fix: add sequential server startup to playwright-jupyter parallel runner
paddymul Mar 2, 2026
68fd933
fix: use DEFAULT_TIMEOUT in infinite-scroll-transcript fallback cell …
paddymul Mar 2, 2026
2c3d5a7
fix: increase warmup kernel polling to 60 iterations (30s timeout)
paddymul Mar 2, 2026
bf904a8
feat: add --phase=5b option and wheel cache to run-ci.sh
paddymul Mar 2, 2026
92a99aa
fix: replace warmup kernels with sleep 20s in parallel jupyter runner
paddymul Mar 2, 2026
5487f99
fix: pre-warm Python bytecaches + fix infinite-scroll test 2 scroll s…
paddymul Mar 2, 2026
f08937c
fix: extract static files from wheel in --phase=5b mode
paddymul Mar 2, 2026
6220264
fix: stagger batch-1 by 5s + increase CELL_EXEC_TIMEOUT to 45s + 2s s…
paddymul Mar 2, 2026
de8e37d
fix: test timeout 60s, scroll-to-top before cell checks, waitFor row-…
paddymul Mar 2, 2026
1b549cc
fix: textContent cell check, wait-for-detach in test2, 10s batch-1 st…
paddymul Mar 2, 2026
1014008
fix: outputArea textContent check, test2 use existing output + waitFo…
paddymul Mar 2, 2026
6f27b83
fix: rename duplicate outputText var, scope row-index=0 to data grid …
paddymul Mar 2, 2026
18faae2
exp19: revert test assertions to original, slack timing (30s sleep, 2…
paddymul Mar 2, 2026
a719762
exp20: CELL_EXEC_TIMEOUT 60s, waitForAgGrid state:visible, run_one 90s
paddymul Mar 2, 2026
14522d6
feat: DAG-based CI execution, replace 5-phase structure
paddymul Mar 2, 2026
f47af9e
fix: ignore all multiprocessing_executor_test.py in Docker CI
paddymul Mar 2, 2026
8c9eb16
fix: deselect test_server_starts_and_responds in Docker CI
paddymul Mar 2, 2026
f47ba16
fix: ignore test_mcp_server_integration.py in unit test runs
paddymul Mar 2, 2026
43af33f
fix: wait for marimo/wasm playwright before starting pw-jupyter
paddymul Mar 2, 2026
17db864
docs: add exp 8-9 and wheel cache infrastructure to experiment log
paddymul Mar 2, 2026
3865fd9
fix: add marimo server warmup and increase playwright-marimo timeouts
paddymul Mar 3, 2026
e35565a
fix: move playwright-marimo after build-wheel in DAG
paddymul Mar 3, 2026
e278032
fix: add --wheel-from=SHA option for iterating on test code
paddymul Mar 3, 2026
3abdcd7
fix: remove 'local' outside function in run-ci.sh
paddymul Mar 3, 2026
a25307e
fix: replace 30s sleep with active kernel warmup in jupyter runner
paddymul Mar 3, 2026
e3cb3fd
feat: PARALLEL=9 for playwright-jupyter with concurrent kernel warmup
paddymul Mar 3, 2026
a1594bd
fix: WebSocket-based kernel warmup + remove batch-1 stagger
paddymul Mar 3, 2026
7e5754a
fix: unique Playwright output dir per parallel notebook slot
paddymul Mar 3, 2026
a869d12
feat: pytest-xdist for parallel unit tests + fix infinite scroll time…
paddymul Mar 3, 2026
2207d1e
fix: reduce infinite scroll notebook to 500 rows, bump test timeout
paddymul Mar 3, 2026
6c1c743
fix: PARALLEL=8 so infinite_scroll runs alone in batch 2
paddymul Mar 3, 2026
c2a16ec
fix: bump CELL_EXEC_TIMEOUT to 120s and test timeout to 180s
paddymul Mar 3, 2026
4cd4ccb
fix: robust cell focus before Shift+Enter in Playwright specs
paddymul Mar 3, 2026
fac3cb5
fix: wait for kernel idle before Shift+Enter in Playwright specs
paddymul Mar 3, 2026
4cd68b7
exp: try PARALLEL=4 — 8 is too flaky under full DAG contention
paddymul Mar 3, 2026
61e9947
fix: retry Shift+Enter every 10s until cell output appears
paddymul Mar 3, 2026
dc360ac
fix: bump DEFAULT_TIMEOUT and NAVIGATION_TIMEOUT to 30s
paddymul Mar 3, 2026
35e0fc8
fix: use dispatchEvent for cell execution retry, avoid click() visibi…
paddymul Mar 3, 2026
7770774
fix: wait for ALL jobs before playwright-jupyter + add Playwright ret…
paddymul Mar 3, 2026
92ca618
exp: try PARALLEL=3 for more reliable playwright-jupyter
paddymul Mar 3, 2026
6a11b71
fix: wait for kernel idle before cell execution in Playwright specs
paddymul Mar 3, 2026
8695488
fix: reduce kernel idle wait to 15s, increase Playwright retries to 2
paddymul Mar 3, 2026
c2f7cbc
docs: update experiment log with results + plan non-jupyter experiments
paddymul Mar 3, 2026
cb585c2
docs: add exp 14e final results — 4/5 pass, 80% ceiling at PARALLEL=4
paddymul Mar 3, 2026
0fc5fb7
docs: add exp 21-22 — jupyterapp internal state query for kernel read…
paddymul Mar 3, 2026
5994612
fix: replace waitForTimeout with polling + jupyterapp kernel check
paddymul Mar 3, 2026
7f7621b
docs: add exp 15-21 results — 100% jupyter pass rate, 2m59s median
paddymul Mar 3, 2026
200bac6
feat: CI job queue, JS build cache, synthetic merge support
paddymul Mar 3, 2026
e7fff5b
fix: mount js-cache volume for build cache persistence
paddymul Mar 3, 2026
5445eb7
fix: ci-queue mkdir log dir before exec, avoid double log output
paddymul Mar 3, 2026
f30da68
fix: ci-queue worker double log lines — nohup to /dev/null
paddymul Mar 3, 2026
5c1e58f
fix: full_build.sh check index.es.js not index.js for skip logic
paddymul Mar 3, 2026
ec8956d
docs: update experiment log — exp 23/24, CPU data, projected impacts
paddymul Mar 3, 2026
60618ce
feat: implement exp 18/19/20 — parallel smoke, relaxed gate, marimo w…
paddymul Mar 3, 2026
d020744
feat: exp 29 — marimo assertion robustness from flakiness research
paddymul Mar 3, 2026
8fcbe9a
docs: update experiment doc with exp 18/19/20/23/24 results
paddymul Mar 3, 2026
137cc92
docs: fix exp 26 description — wheel bundles JS, cache key needs both
paddymul Mar 3, 2026
172158b
feat: exp 28 — early kernel warmup overlaps with Wave 0
paddymul Mar 3, 2026
c53967c
docs: update experiment log with exp 28 results
paddymul Mar 3, 2026
d24bbc4
docs: add CPU monitoring requirement for CI experiments
paddymul Mar 3, 2026
d369894
feat: exp 30 — remove heavyweight PW gate, add CPU monitoring
paddymul Mar 3, 2026
526a120
fix: use vmstat instead of mpstat for CPU monitoring
paddymul Mar 3, 2026
5970802
docs: add exp 30 results — remove heavyweight gate, 1m43s total
paddymul Mar 3, 2026
6c82f89
feat: exp 31 — PARALLEL=9 for pw-jupyter (all notebooks at once)
paddymul Mar 3, 2026
b2398d5
feat: exp 32 — revert P=4, move wasm-marimo after wheel, defer pytest
paddymul Mar 3, 2026
3340ce9
docs: add Exp 31/32 results — P=9 abandoned, lean Wave 0 +8s vs Exp 30
paddymul Mar 3, 2026
5279196
feat: exp 33 — staggered sub-waves, PARALLEL=6, fine-grain CPU (0.1s)
paddymul Mar 3, 2026
8478735
fix: exp 33 — batch 2 re-warmup, 120s pw-jupyter timeout, 210s CI wat…
paddymul Mar 3, 2026
076f40f
fix: remove `local` outside function in batch re-warmup loop
paddymul Mar 3, 2026
0e98e13
feat: exp 33 — try PARALLEL=9 for pw-jupyter (all 9 notebooks at once)
paddymul Mar 3, 2026
75a81b2
feat: exp 33 — stagger PARALLEL=9 Chromium launches by 1s
paddymul Mar 3, 2026
b566296
feat: exp 33 — try 2s stagger for PARALLEL=9
paddymul Mar 3, 2026
553bea0
feat: exp 33 — BASE_PORT=8900 for PARALLEL=9 (test port theory)
paddymul Mar 3, 2026
9dcc5e0
fix: add pre-run cleanup to run-ci.sh — kill stale processes, rm temp…
paddymul Mar 3, 2026
08724ad
docs: exp 33 results — P=6 batched wins, P=9 conclusively dead
paddymul Mar 3, 2026
630cf60
feat: exp 34+36 — SKIP_INSTALL, nice priority, auto-retry server asse…
paddymul Mar 3, 2026
da3a7ad
fix: use renice instead of nice for shell functions in run-ci.sh
paddymul Mar 3, 2026
2ba10e7
fix: don't renice jupyter-warmup (servers persist), SKIP_INSTALL in p…
paddymul Mar 3, 2026
5996d8c
docs: exp 34+36 results — pw-server flake fixed, pw-jupyter zombie re…
paddymul Mar 3, 2026
382c9e6
docs: split experiments doc into current state + historical archive
paddymul Mar 3, 2026
20fb931
fix: add init:true to docker-compose for zombie reaping (Exp 37)
paddymul Mar 3, 2026
46c165c
fix: use tini ENTRYPOINT instead of init:true for zombie reaping
paddymul Mar 3, 2026
54edcab
fix: clean workspace files in pre-run cleanup, PARALLEL=5 (Exp 38)
paddymul Mar 3, 2026
5416e0c
fix: aggressive pre-run cleanup — SIGKILL, port fuser, cache purge
paddymul Mar 3, 2026
8d9c638
fix: bump pw-jupyter timeout 120→180s, watchdog 210→270s
paddymul Mar 3, 2026
ef53834
revert: restore Exp 33 pw-jupyter config (P=6, 120s timeout, 210s wat…
paddymul Mar 3, 2026
fff99fa
fix: revert PARALLEL=6→4 — P=6 no longer reliable on current image
paddymul Mar 3, 2026
9a15704
docs: update experiments — tini validated, P=4 stable, P=6 regressed
paddymul Mar 3, 2026
98d0a64
docs: clarify Exp 26 scope — CI-dev-only edge case, not for real CI
paddymul Mar 3, 2026
c5a0498
docs: add research notes from CI optimization effort
paddymul Mar 3, 2026
4a7fefc
feat: Exp 35 split build-js/test-js + fix lockfile hash persistence
paddymul Mar 3, 2026
f5d2b55
docs: Exp 35+39 validated — build-js split saves 4s, lockfile hashes …
paddymul Mar 3, 2026
2fd049c
docs: update CPU profile with 4a7fefc data, add Exp 35+39 run history
paddymul Mar 3, 2026
2dff214
feat: add run-pw-jupyter.sh — fast pw-jupyter iteration script
paddymul Mar 3, 2026
0e7c66e
fix: bump pw-jupyter timeout 160→240s, parallelize notebook trust
paddymul Mar 3, 2026
87cb918
fix: wait for trust PIDs only, not all background jobs
paddymul Mar 3, 2026
8e4334b
feat: add per-process monitor script and exploration results log
paddymul Mar 3, 2026
54ae375
docs: Exp 1 complete — settle=0 works; fix kernel process capture in …
paddymul Mar 3, 2026
4012167
docs: Exp 2 P2 results — P=5 fails with system idle, not resource con…
paddymul Mar 3, 2026
e6ea620
fix: add --disable-dev-shm-usage to Chromium for Docker P=5+ support
paddymul Mar 3, 2026
338e40e
docs: Exp 2 complete — /dev/shm fix unlocks P=9 (49s, down from 94s)
paddymul Mar 3, 2026
228c7f7
feat: add Exp 4 back-to-back degradation test script
paddymul Mar 3, 2026
f82a1b4
docs: all experiments complete — /dev/shm fix resolves everything
paddymul Mar 4, 2026
176f6f6
feat: integrate /dev/shm fix — bump PARALLEL 4→9, settle 0, add --dis…
paddymul Mar 4, 2026
29b19fa
feat: delay smoke-test-extras, tighten stagger 5→2s, add MCP/server t…
paddymul Mar 4, 2026
1c49a02
feat: bind-mount CI runner scripts — no rebuild needed for script cha…
paddymul Mar 4, 2026
fd85f0a
fix: use awk instead of bc for timing (bc not in container)
paddymul Mar 4, 2026
676161f
docs: update experiments doc with Exp 40-41 results + bind-mount infra
paddymul Mar 4, 2026
c26897f
fix: clean all 9 jupyter ports (8889-8897) in pre-run cleanup
paddymul Mar 4, 2026
37aed6b
feat: remove all stagger delays — launch everything simultaneously
paddymul Mar 4, 2026
6c8590d
fix: restore 2s stagger between wheel-dependent jobs
paddymul Mar 4, 2026
7626c67
fix: cleanup esbuild, pw-results, expand port range to 8889-8897
paddymul Mar 4, 2026
09c6faa
fix: bump CI watchdog 210s → 360s for cold-start tolerance
paddymul Mar 4, 2026
7971896
docs: update CI research with Exp 42 results (64GB server, 2s stagger)
paddymul Mar 4, 2026
60f35f7
perf: start 9 JupyterLab servers in parallel during warmup
paddymul Mar 4, 2026
eca76b9
perf: remove 2s stagger between pw-jupyter Chromium launches
paddymul Mar 4, 2026
ef91d94
fix: use 0.5s stagger for pw-jupyter Chromium launches (0s hangs)
paddymul Mar 4, 2026
233a604
fix: use 1s stagger for pw-jupyter (0.5s still hangs 4/9)
paddymul Mar 4, 2026
a6de142
fix: revert pw-jupyter stagger to 2s (0s/0.5s/1s all fail)
paddymul Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ eggs/
.eggs/
lib/
lib64/
!ci/hetzner/lib/
parts/
sdist/
var/
Expand Down Expand Up @@ -167,6 +168,9 @@ docs/source/_static/*woff*

packages/buckaroo-js-core/tsconfig.tsbuildinfo

# Downloaded CI logs (stress-test analysis)
ci-logs/

# Large data files - should not be in repo
*.parq
*.parquet
Expand Down
11 changes: 11 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ Test suite should complete in under 40 seconds. If it doesn't, something is wron

Runs on push to main and PRs. Key jobs: LintPython, TestJS, BuildWheel, TestPython (3.11-3.14), Playwright (Storybook, Jupyter, Marimo, WASM). Uses `depot-ubuntu-latest` runners.

### Hetzner CI (manual/agent pre-push)

Fast self-hosted CI on Hetzner. Trigger: `docker exec buckaroo-ci bash /opt/ci-runner/run-ci.sh <SHA> <BRANCH>`.

**Every time a CI experiment completes, report:**
- Wallclock total runtime
- Runtime of each phase (Phase 1 / 2 / 3 / 4 / 5a / 5b)
- Pass/fail per job

Parse from `/opt/ci/logs/<sha>/ci.log` — lines like `[HH:MM:SS] START/PASS/FAIL <job>`.

## Architecture Notes

- **Column renaming**: Internally rewrites column names to a,b,c... — use `orig_col_name` to map back to real names.
Expand Down
15 changes: 15 additions & 0 deletions ci/hetzner/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copy to /opt/ci/.env and fill in values before starting the webhook service.

# Fine-grained PAT with "commit statuses: read & write" on buckaroo-data/buckaroo
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Random secret shared with GitHub webhook settings (Settings → Webhooks → Secret)
# Generate with: openssl rand -hex 32
WEBHOOK_SECRET=your_webhook_secret_here

# GitHub repo in "owner/name" format
GITHUB_REPO=buckaroo-data/buckaroo

# Hetzner server details (from `hcloud server list` after provisioning)
HETZNER_SERVER_ID=12345678
HETZNER_SERVER_IP=1.2.3.4
72 changes: 72 additions & 0 deletions ci/hetzner/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright
ENV PNPM_STORE_DIR=/opt/pnpm-store

# 1. OS + base tools
RUN apt-get update && apt-get install -y --no-install-recommends \
curl git ca-certificates gnupg \
build-essential libffi-dev libssl-dev tini \
&& rm -rf /var/lib/apt/lists/*

# 2. uv (pinned — bump when needed, not on a schedule)
COPY --from=ghcr.io/astral-sh/uv:0.6.6 /uv /usr/local/bin/uv

# 3. Python 3.11-3.14 via uv (no deadsnakes PPA needed)
RUN uv python install 3.11 3.12 3.13 3.14

# 4. Node 22 LTS + pnpm 9.10.0 (pinned)
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& corepack enable \
&& corepack prepare pnpm@9.10.0 --activate

# 5. JS deps — populate pnpm content-addressable store
# Reproduces the packages/ workspace structure so pnpm install works.
# At runtime, pnpm install is ~50ms (just creates hard links from the store).
WORKDIR /build-js
COPY packages/pnpm-lock.yaml packages/pnpm-workspace.yaml packages/package.json ./
COPY packages/buckaroo-js-core/package.json ./buckaroo-js-core/
COPY packages/js/package.json ./js/
RUN pnpm install --frozen-lockfile --store-dir /opt/pnpm-store

# 6. Python deps — one venv per Python version, all extras, no project install
# At runtime, `uv sync` installs only buckaroo itself (editable), which is instant.
WORKDIR /build-py
COPY pyproject.toml uv.lock ./
RUN for v in 3.11 3.12 3.13 3.14; do \
uv venv /opt/venvs/$v --python $v && \
UV_PROJECT_ENVIRONMENT=/opt/venvs/$v \
uv sync --locked --dev --all-extras --no-install-project; \
done

# 7. Playwright chromium — install system deps + browser for Python playwright.
# JS playwright (pnpm exec playwright) uses the same PLAYWRIGHT_BROWSERS_PATH,
# so it will find the same browser or install its version alongside it.
RUN /opt/venvs/3.13/bin/playwright install --with-deps chromium
RUN cd /build-js/buckaroo-js-core && pnpm exec playwright install chromium

# 8. Bake CI runner scripts into the image at a stable path so they survive
# `git checkout` of arbitrary SHAs inside /repo at runtime.
COPY ci/hetzner/run-ci.sh ci/hetzner/lib/ /opt/ci-runner/
COPY scripts/test_playwright_jupyter_parallel.sh /opt/ci-runner/
ARG GIT_SHA=unknown
RUN echo "$GIT_SHA" > /opt/ci-runner/VERSION && \
chmod +x /opt/ci-runner/run-ci.sh /opt/ci-runner/test_playwright_jupyter_parallel.sh

# Allow JupyterLab to start as root (container runs as root).
# This avoids needing --allow-root in every script that starts Jupyter.
RUN mkdir -p /root/.jupyter && \
echo "c.ServerApp.allow_root = True" >> /root/.jupyter/jupyter_lab_config.py

# Source code is bind-mounted at /repo at runtime — not baked in.
# Allow git to operate on the bind-mounted repo (owned by ci on host, root in container).
RUN git config --system --add safe.directory /repo
WORKDIR /repo
# tini as PID 1 reaps zombie processes from docker exec'd CI runs.
# Without it, sleep-infinity PID 1 doesn't call wait(), zombies accumulate,
# and back-to-back CI runs fail.
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["sleep", "infinity"]
Loading
Loading