From fe5371ac56913784e7f63f5e8006c9f4e6687a53 Mon Sep 17 00:00:00 2001 From: Adil Hafeez Date: Fri, 24 Apr 2026 16:53:43 -0700 Subject: [PATCH] ci: add zero-config smoke test for `planoai up` with no args The existing native-smoke-test always passes a config file, so the `synthesize_default_config` branch in `cli/planoai/main.py` is never exercised in CI. That branch was the source of a recent UnboundLocalError that only reproduced when invoking `planoai up` with no args in a directory without a `plano.yaml` (fixed in #916). Add a follow-up step in the same job that runs `planoai up` from an empty temp directory, asserts `~/.plano/default_config.yaml` is written, performs a healthz check, and shuts down. Reuses the binaries already built earlier in the job to keep CI time flat. Made-with: Cursor --- .github/workflows/ci.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e8722ce..4d980ec8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,6 +107,37 @@ jobs: if: always() run: planoai down || true + # ── Zero-config path: `planoai up` with no args, no plano.yaml in cwd. + # Exercises the synthesize_default_config branch in cli/planoai/main.py + # which is otherwise never hit by the smoke test above. + - name: Zero-config smoke test + env: + OPENAI_API_KEY: test-key-not-used + run: | + empty_dir="$(mktemp -d)" + cd "$empty_dir" + test ! -f plano.yaml + planoai up + test -f "$HOME/.plano/default_config.yaml" + + - name: Zero-config health check + run: | + for i in $(seq 1 30); do + if curl -sf http://localhost:12000/healthz > /dev/null 2>&1; then + echo "Zero-config health check passed" + exit 0 + fi + sleep 1 + done + echo "Zero-config health check failed after 30s" + cat ~/.plano/run/logs/envoy.log || true + cat ~/.plano/run/logs/brightstaff.log || true + exit 1 + + - name: Stop plano (zero-config) + if: always() + run: planoai down || true + # ────────────────────────────────────────────── # Single Docker build — shared by all downstream jobs # ──────────────────────────────────────────────