Build & test¶
Prerequisites¶
- Go 1.22+ for the server
- Node 20+ for the SPA build
- make (BSD make works; GNU make works)
- Optional: ffmpeg for the docs gif conversion, yt-dlp for voice library URL imports during dev
Build targets¶
make build # vite + go → single binary at ./pluma
make web-build # vite only → server/embedded/
make go-build # go only (assumes server/embedded/ is up to date)
make clean # remove ./pluma + server/embedded/
make build is the canonical "I want a fresh binary" command. It runs web-build then go-build.
The Go binary embeds server/embedded/ at compile time via //go:embed. Without the SPA build first, the binary still compiles (the embed FS is empty) but the served UI is broken.
Tests¶
make test-go runs go test ./... under server/. An in-memory SecretStore stub (secret_store_stub_test.go) swaps the package-level keyring so the suite runs headless on CI without macOS Keychain / libsecret access.
make test-web runs pnpm test --run under web/. Vitest + jsdom + a localStorage stub for Node v25+ compatibility.
Type-check + lint¶
CI runs both; warnings don't fail the build but errors do.
CI workflow¶
.github/workflows/ci.yml runs on every push to main + every PR:
setup-go@v5(1.26)setup-node@v4(20)make buildmake testmake check
Green CI is a prerequisite for merge. Tag push triggers the release workflow separately (see Adding a provider for the release flow).
Quick smoke after build¶
./pluma --version # should print 'pluma dev' or 'pluma vX.Y.Z'
./pluma # serves on :8787, auto-opens browser
If the wizard pops, the SPA embedded correctly. If you see a blank page, server/embedded/ is probably empty — rerun make web-build.