From 0f5d503169aaad1f8bb3b221978c8030449b669b Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Mon, 20 Apr 2026 22:09:54 -0700 Subject: [PATCH] fix(ci): make e2e_ui_testing actually test the freshly built UI bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Build UI from source step used: cp -r out/ ../../litellm/proxy/_experimental/out/ GNU cp (CircleCI's Ubuntu image, coreutils 8.32) interprets this as copy the source directory as a CHILD of the destination when the destination already exists — so the command silently created litellm/proxy/_experimental/out/out/ instead of replacing the served bundle at litellm/proxy/_experimental/out/*. The proxy continued serving whatever bundle was checked in, so every e2e_ui_testing run between this job's introduction (d09d98a70a, 2026-04-08) and the bundle-rebuild commit (de790fd273, 2026-04-18) was effectively testing a STALE bundle — not the fresh build. That is why the double-prefix regression (NEXT_PUBLIC_BASE_URL="ui/" combined with networking.tsx reading the env var) was never caught in CI even though the source contained the trigger the whole time: the bundle the proxy served never picked up the source change. Replace cp -r with rm + mv so the destination is cleanly swapped. Verified end-to-end on an Ubuntu 22.04 / GNU coreutils 8.32 container: - Before fix: fresh build has 9 "ui/" literals in chunks; after cp, _experimental/out/* still has 0 (stale); _experimental/out/out/ is a nested dir the proxy does not serve. - After fix: _experimental/out/* has 9 "ui/" literals — the proxy now serves the freshly built (broken, in this repro) bundle, so globalSetup fails at login and every spec is blocked. Removing the bug from .env.production and rebuilding brings the count back to 0 and the suite passes. No spec changes, no fixtures, no new infrastructure. The existing Playwright suite already catches this class of regression via the login flow in globalSetup; it just needs the CI to actually hand it the freshly built bundle. --- .circleci/config.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9b976462b13..8c75bdc5f33 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3051,10 +3051,19 @@ jobs: - ui/litellm-dashboard/node_modules - run: name: Build UI from source + # Prior version used `cp -r out/ ../../litellm/proxy/_experimental/out/`. + # GNU cp (used on CircleCI's Ubuntu image) interprets that as "copy the + # source directory as a child of the destination" when the destination + # already exists — silently creating `_experimental/out/out/` instead of + # replacing the served bundle. The proxy continued serving whatever was + # checked into `_experimental/out/*`, so this job was effectively testing + # the pre-build bundle on every run. Replace-and-move guarantees the + # freshly built bundle is what the proxy actually serves. command: | cd ui/litellm-dashboard npm run build - cp -r out/ ../../litellm/proxy/_experimental/out/ + rm -rf ../../litellm/proxy/_experimental/out + mv out ../../litellm/proxy/_experimental/out # Restructure HTML so extensionless routes work (login.html -> login/index.html) find ../../litellm/proxy/_experimental/out -name '*.html' ! -name 'index.html' | while read -r f; do d="${f%.html}"; mkdir -p "$d"; mv "$f" "$d/index.html"