feat(deploy): split deploy binary, download from releases, add CI #8

Merged
addison merged 19 commits from exe-dev-bot/kiosk:feat/arm64-cross-compile into main 2026-02-12 20:39:38 -05:00
Contributor

Changes

Architecture

  • Split into two binaries: kiosk (web server) and kiosk-deploy (TUI at cmd/kiosk-deploy/)
  • Removed deploy subcommand from main kiosk binary
  • Main binary no longer imports Bubble Tea or deploy packages

Download from releases

  • Deploy TUI downloads latest ARM64 kiosk binary from Forgejo releases API (git.kwila.cloud/kwila/kiosk/releases)
  • Replaced embedded binary approach — no more embed_binary.go files or build tags
  • DownloadBinary() added to Deployer interface; fetches latest release, finds arm64 asset
  • Binary download happens first in deploy flow (before flashing), so failures are caught early

CI

  • Added .forgejo/workflows/release.yml — triggers on v* tags
  • Builds kiosk-arm64 with CGO_ENABLED=0 GOOS=linux GOARCH=arm64
  • Creates Forgejo release with binary attached

Docs

  • New docs/deployment.md with step-by-step guide, configuration reference, and troubleshooting
  • Updated AGENTS.md with new binary layout

Justfile

  • build — kiosk web server
  • build-arm64 — ARM64 cross-compile (for releases)
  • build-deploy — deploy TUI binary
  • run-deploy — build and run deploy TUI with sudo
## Changes ### Architecture - **Split into two binaries:** `kiosk` (web server) and `kiosk-deploy` (TUI at `cmd/kiosk-deploy/`) - Removed `deploy` subcommand from main kiosk binary - Main binary no longer imports Bubble Tea or deploy packages ### Download from releases - Deploy TUI downloads latest ARM64 kiosk binary from Forgejo releases API (`git.kwila.cloud/kwila/kiosk/releases`) - Replaced embedded binary approach — no more `embed_binary.go` files or build tags - `DownloadBinary()` added to Deployer interface; fetches latest release, finds `arm64` asset - Binary download happens first in deploy flow (before flashing), so failures are caught early ### CI - Added `.forgejo/workflows/release.yml` — triggers on `v*` tags - Builds `kiosk-arm64` with `CGO_ENABLED=0 GOOS=linux GOARCH=arm64` - Creates Forgejo release with binary attached ### Docs - New `docs/deployment.md` with step-by-step guide, configuration reference, and troubleshooting - Updated `AGENTS.md` with new binary layout ### Justfile - `build` — kiosk web server - `build-arm64` — ARM64 cross-compile (for releases) - `build-deploy` — deploy TUI binary - `run-deploy` — build and run deploy TUI with sudo
Add BuildARM64Binary() to the Deployer interface, which cross-compiles
the kiosk binary with GOOS=linux GOARCH=arm64 CGO_ENABLED=0 and returns
the path to the built binary.

- RealDeployer: runs 'go build' to a temp file with arm64 env vars
- MockDeployer: returns a stub path for testing
- TUI: calls BuildARM64Binary before mounting root, passes the path
  to InstallBinary
- InstallBinary signature updated to accept binaryPath parameter
  instead of using os.Executable()
- All tests updated with new call sequence

Co-authored-by: Shelley <shelley@exe.dev>
Cover three sections from spec 1 documentation tasks:
- Step-by-step deployment walkthrough from prerequisites to working kiosk
- Configuration options: dietpi.txt, WiFi, systemd service, ports, database
- Troubleshooting: boot issues, WiFi, Chromium, SSH, logs, screen blanking

References README.md for the quick-start overview rather than duplicating it.

Co-authored-by: Shelley <shelley@exe.dev>
Co-authored-by: Shelley <shelley@exe.dev>
Replace runtime cross-compilation (BuildARM64Binary) with a two-stage
build approach:

1. Cross-compile ARM64 binary to deploy/embed/kiosk-arm64
2. Build host binary with -tags=deploy to embed it via go:embed

This removes the Go toolchain dependency from the deploy host.

- Remove BuildARM64Binary() from Deployer interface
- Update InstallBinary to write embedded bytes directly
- Use build tags: 'deploy' embeds real binary, default uses empty placeholder
- Add 'just build-deploy' recipe for the two-stage build
- Update MockDeployer and all tests accordingly

Co-authored-by: Shelley <shelley@exe.dev>
- Remove InstallBinary(rootMount) in favor of DownloadBinary() + InstallBinary(rootMount, binaryPath)
- DownloadBinary() fetches latest ARM64 binary from Forgejo releases API
- InstallBinary() copies the downloaded file to the root partition
- Remove embed_binary.go and embed_binary_dev.go (no longer needed)
- Update MockDeployer to match new interface

Co-authored-by: Shelley <shelley@exe.dev>
- TUI now downloads binary before flashing image
- Update deploy step ordering: download binary → download image → flash → etc.
- Update test expectations for new call sequence

Co-authored-by: Shelley <shelley@exe.dev>
- Remove deploy subcommand and bubbletea import from main.go
- Create cmd/kiosk-deploy/main.go as standalone deploy TUI binary
- main.go is now purely the web server

Co-authored-by: Shelley <shelley@exe.dev>
- Replace build-deploy with cmd/kiosk-deploy build
- Add run-deploy recipe
- Update clean to remove kiosk-deploy
- Update AGENTS.md to reflect split binary and download approach

Co-authored-by: Shelley <shelley@exe.dev>
- Triggers on v* tag push
- Builds kiosk-arm64 with CGO_ENABLED=0 GOOS=linux GOARCH=arm64
- Creates a Forgejo release with the binary attached

Co-authored-by: Shelley <shelley@exe.dev>
Co-authored-by: Shelley <shelley@exe.dev>
exe-dev-bot changed title from feat(deploy): ARM64 cross-compilation and deployment docs to feat(deploy): split deploy binary, download from releases, add CI 2026-02-12 20:08:21 -05:00
Add channel-based progress reporting to the deploy flow so users see
each step as it happens instead of a static 'Working...' spinner.

- Add deployProgressMsg type and listenForProgress command that reads
  from a channel one message at a time, re-subscribing after each
- In runDeploy(), send descriptive progress strings before each step
  via an unbuffered channel, and track completed steps for the done msg
- deployDoneMsg now carries the full step list to avoid race between
  progress and done messages arriving in non-deterministic order
- viewDeploying() renders completed steps with green checkmarks and
  shows the spinner on the current in-progress step
- Update tests to use concurrent goroutine-based event loop simulation
  (runDeployToCompletion helper) instead of sequential batch processing
- Add TestDeployShowsProgressSteps to verify all 9 progress entries

Co-authored-by: Shelley <shelley@exe.dev>
- Replace 'kiosk deploy' subcommand references with 'kiosk-deploy' binary
- Remove 'Build the ARM64 Binary' section from deployment guide — the
  deploy tool downloads the latest ARM64 binary from Forgejo releases
- Update deploy flow steps to include binary download step
- Update README quick start to use 'just build-deploy && sudo ./kiosk-deploy'
- Update AGENTS.md architecture section for two-binary design
- Update spec deployment workflow and task list
- Add troubleshooting section for release download failures

Co-authored-by: Shelley <shelley@exe.dev>
- Defer unmount of boot/root partitions after successful mount, using
  a mounted flag that gets cleared after explicit unmount on the happy
  path. This ensures stale mounts are cleaned up if any subsequent
  step fails, preventing SD card ejection issues.

- Defer os.Remove(binaryPath) after successful DownloadBinary to
  clean up the temp file on both success and error paths. The DietPi
  image is intentionally cached (~/.cache/dietpi/) and left alone.

- Add FailOn map to MockDeployer for error injection in tests.

- Add tests verifying deferred unmount behavior:
  - InstallBinary failure -> both boot and root unmounted
  - MountRoot failure -> only boot unmounted

Co-authored-by: Shelley <shelley@exe.dev>
Charset length 55 does not evenly divide 256, causing ~25% relative
bias for some characters. Use rejection sampling: discard random bytes
>= 220 (256 - 256%55) and re-sample.

Co-authored-by: Shelley <shelley@exe.dev>
Add escapeQuote template function that replaces ' with '\'' (shell
quoting). Apply it to WifiSSID and WifiPassword in dietpi-wifi.txt.tmpl
to prevent broken config when credentials contain single quotes.

Co-authored-by: Shelley <shelley@exe.dev>
The kiosk binary needs to bind to port 80, which requires the
CAP_NET_BIND_SERVICE capability when running as a non-root user.

Co-authored-by: Shelley <shelley@exe.dev>
softprops/action-gh-release is GitHub-specific and may not work with
Forgejo. Use curl-based approach with the Forgejo releases API instead.

Also build and upload kiosk-deploy (linux/amd64) alongside kiosk-arm64.

Co-authored-by: Shelley <shelley@exe.dev>
Merge configuration details, update instructions, and troubleshooting
from docs/deployment.md into the README's Deploy section. Troubleshooting
is in a collapsible <details> block to keep the README scannable.

Remove docs/deployment.md and the docs/ directory.

Co-authored-by: Shelley <shelley@exe.dev>
Co-authored-by: Shelley <shelley@exe.dev>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kwila/kiosk!8
No description provided.