One command brings up a local Kubernetes cluster with the KubeSwift CRDs, realistic fixture objects with simulated statuses, and a freshly packed build of the extension, ready to be tried in a real Freelens installation. No KVM, no real VMs: statuses are injected exactly like in the E2E suite (see TESTING.md and SPEC-0005).
This procedure backs the per-milestone manual review gate described in PROCESS.md.
- A running Docker daemon (Docker Desktop, docker-ce, OrbStack, ...)
kind,kubectl,curl- Node.js >= 22 with
pnpm(the same toolchain used to build the extension;corepack installprovides the right pnpm, see the README's "Build from the source" section), andpnpm installalready run once in the repo - The Freelens app installed (>= 1.10.3)
pnpm demo:upWhen it finishes, the script prints the two paths you need:
- The demo kubeconfig (
.demo/kubeconfig, contextkind-kubeswift-demo). Add it to Freelens as a new cluster (File > Add Cluster, or copy it into a folder Freelens syncs kubeconfigs from). Your~/.kube/configis never touched. - The packed extension (
freelensapp-kubeswift-extension-<version>.tgzin the repo root). Install it from the Freelens Extensions page (paste the path or pick the file).
Then connect to the cluster: the KubeSwift entry appears in the cluster
sidebar and the fixture objects live in the kubeswift-e2e namespace.
Tear everything down with:
pnpm demo:downBoth commands are idempotent: demo:up re-applies CRDs and fixtures and
repacks the extension on every run, and reuses the cluster if it already
exists.
Docker without administrator rights exists only inside WSL2, so the script runs there while the Freelens app runs on the Windows side:
- Inside a WSL2 distribution with docker-ce (or Docker Desktop's WSL2
integration), clone the repo and run
pnpm demo:upas above. - In the Freelens app on Windows, use the WSL paths of the two files the
script printed, in the
\\wsl.localhost\<distro>\...form (for example\\wsl.localhost\Ubuntu\home\<user>\freelens-kubeswift-extension\.demo\kubeconfig). The cluster API server on127.0.0.1is reachable from Windows thanks to WSL2 localhost forwarding.
The reviewer walks through every view implemented in the milestone under review and checks, for each list page and detail drawer:
- the sidebar entry and page titles;
- columns: content, sorting, the search box filtering;
- status semantics: do phases/conditions read correctly at a glance;
- the detail drawer: field grouping, references to other objects, conditions;
- empty states (delete a fixture with
kubectland look at the page) and the N/A fallbacks; - both dark and light Freelens themes.
Fleet > Member Clusters reads differently from every other page, and
the reviewer should know which of three situations an empty one means
(SPEC-0009): the cluster is not a KubeSwift hub (the chart installs
this CRD everywhere, so the page exists on every KubeSwift cluster and
nothing ever writes a status on it); the cluster is a hub but the
namespace filter does not include the KubeSwift system namespace, which
is where Cluster objects live and which is never the default namespace
a freshly connected Freelens selects; or the hub genuinely has no members
registered yet. On the demo cluster the fixtures make the page non-empty,
and an "Unknown" badge with "N/A" in K8s and Guests is a correct steady
state there rather than a symptom: it is the member no gateway has
reported on.
From M6 on the Guests page WRITES (SPEC-0010), and the demo cluster is
a real cluster: Start and Stop are in the row kebab and in the drawer
toolbar, and confirming their dialog really patches spec.runPolicy and
really deletes a launcher pod. Nothing happens on a single click - every
action opens a dialog that lists the API calls it is about to make, and
cancelling writes nothing - so the surface is safe to explore, and the
dialogs are the part worth reading closely: they are where this extension
is furthest ahead of the upstream UI. Three things to look at that no
assert covers: the wording of the dialogs, the reason a disabled Start or
Stop gives (it is in the item's tooltip attribute and, durably, in the
drawer's Condition row), and whether Stopping reads correctly at a
glance next to Run Policy: Stopped. The demo cluster has no KubeSwift
controller, so a stopped guest stays Stopping forever there: that is
the fixture, not a bug.
Feedback goes into one issue per finding (or one umbrella issue per session), referenced from the spec of the feature it concerns; the spec's "Manual verification" section records date, tester, and result.
pnpm e2e and pnpm pre-review drive a real, locally built Freelens.
CI builds it on every run; on a developer machine you build it once and
reuse it. Budget 10-15 GB of disk and 20-40 minutes for the first build.
-
Clone the app at the version pinned in
.github/workflows/e2e-tests.yamlinto./freelens(gitignored):git clone --depth 1 --branch v1.10.3 \ https://github.com/freelensapp/freelens.git freelens
-
Use the Node version the app wants (
freelens/.nvmrc, currently 24.x- newer than this extension's own toolchain), then install:
nvm install "$(cat freelens/.nvmrc)" && corepack enable cd freelens PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 pnpm install --frozen-lockfile pnpx playwright install chromium
-
Build, in this order (it mirrors the E2E workflow):
pnpm build pnpm build:resources pnpm electron-rebuild -a x64 # arm64 on Apple Silicon / arm Linux -
Package the app. Resolve the electron-builder CLI path before swapping in the production node_modules - electron-builder is a dev dependency and disappears from the swapped tree (the resolved path points into the root pnpm store, which survives the swap):
EB_PATH=$(cd freelens && node -e "console.log(require.resolve('electron-builder/cli'))") pnpm deploy --legacy --prod --filter=freelens freelens/node_modules_prod mv freelens/node_modules freelens/node_modules_dev mv freelens/node_modules_prod freelens/node_modules (cd freelens && npm_config_user_agent=pnpm \ node "$EB_PATH" --publish never --mac dir --x64) # --linux on Linux rm -rf freelens/node_modules && mv freelens/node_modules_dev freelens/node_modules
The app lands in
freelens/freelens/dist/mac/Freelens.app(ordist/linux-*-unpacked). Code signing is skipped - fine for testing. -
From the repo root,
pnpm e2eandpnpm pre-reviewnow work. SetFREELENS_DIRto reuse a checkout living elsewhere.
macOS note: the very first launch of the freshly built, unsigned app can be slowed by Gatekeeper's first-run scan; the install helper tolerates this (it waits up to 90 seconds), and later runs are fast.
- No real VMs: a
SwiftGuesthere never boots. Behavior against a real KVM-backed KubeSwift installation is a manual-only area (see TESTING.md). - The statuses are frozen: no controller reconciles them, so nothing
changes over time unless you patch it with
kubectl. - A sandbox's Workload Console follows its console file and can never be
typed into: for a sandbox the hypervisor writes the guest's serial
line to a file rather than to a socket, so the console is read-only by
construction (SPEC-0017). For a shell inside a sandbox's microVM, use
swiftctl sandbox attach(orswiftctl sandbox exec): that channel is the guest agent's vsock protocol, which is not expressible as a command line in a terminal tab, so this extension deliberately offers no control for it rather than a broken one.