hsa-app/deploy/INSTALL.md
Jean-Michel Tremblay f47e611e2c
All checks were successful
Build and Test / build-and-test (push) Successful in 36s
Deploy tagged releases via versioned dir + symlink swap
On tag push, scp the binary to ~/hsa-app/releases/hsa-app-V<tag>/hsa,
repoint the ~/hsa-app/hsa symlink, and restart the user systemd
service. Add deploy/hsa_app.service unit and deploy/INSTALL.md with
host layout, one-time install, deploy, and rollback steps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:08:20 -04:00

3 KiB

Deploying hsa-app

The app runs as a user systemd service (no sudo). Tagged releases are pushed by CI into ~/hsa-app/releases/hsa-app-V<tag>/hsa, and a current symlink (~/hsa-app/hsa) points at the live release. Restarting the service picks up whatever the symlink resolves to.

Layout on the host

Mutable state (DB, env, config) lives at the top of ~/hsa-app/ and survives every deploy. Only the binaries live under releases/.

~/hsa-app/
  hsa_app.sh                     # launcher: sources env file, exec's the binary
  hsa_app.env                    # environment (KEY=VALUE)
  config.json
  hsa.db, hsa.db-shm, hsa.db-wal # SQLite state
  releases/
    hsa-app-V0.0.0a0/hsa
    hsa-app-V0.0.1/hsa
  hsa -> releases/hsa-app-V0.0.1/hsa   # current symlink, swapped on deploy

Create/repoint it from inside ~/hsa-app so the relative target resolves against the link's own directory (running ln -s from ~ produces a broken link that points at ~/hsa-app/hsa-app/...):

cd ~/hsa-app
chmod +x releases/hsa-app-V<tag>/hsa
ln -sfn releases/hsa-app-V<tag>/hsa hsa   # -f replace, -n don't follow existing link
ls -l hsa                                  # target must resolve (not broken)

This same ln -sfn + chmod +x is what the CI deploy step runs on each tag.

Install the service (once)

Save hsa_app.service to ~/.config/systemd/user/hsa_app.service, then:

loginctl enable-linger "$USER"     # run the service without an active login session
systemctl --user daemon-reload
systemctl --user enable --now hsa_app
systemctl --user status hsa_app
journalctl --user -u hsa_app -f    # follow logs

Why these choices

  • User service (systemctl --user) — no sudo, matches the home-dir deploy. enable-linger lets it start at boot / stay up without an interactive login.
  • Type=exechsa_app.sh ends in exec "$BIN", so the binary becomes the unit's main process; signals and exit codes propagate correctly.
  • WorkingDirectory=%h/hsa-app — relative paths in the env file resolve here. The launcher's comment recommends absolute paths for DB_PATH / STORAGE_DIR / BACKUP_DIR / CONFIG_PATH; either works.
  • ExecStart passes the env file as $1 — matches hsa_app.sh's first-arg precedence, so no /etc/hsa-app/... file is needed. %h expands to the home dir.
  • The launcher defaults its binary to ./hsa next to itself (~/hsa-app/hsa, the symlink), so a restart after a symlink swap runs the new release automatically.

Deploy a tagged release

CI pushes the binary on tag and runs the swap + restart. To do it manually:

cd ~/hsa-app
chmod +x releases/hsa-app-V<tag>/hsa
ln -sfn releases/hsa-app-V<tag>/hsa hsa
systemctl --user restart hsa_app

Roll back

Every release stays under releases/, so rollback is a symlink repoint:

cd ~/hsa-app
ln -sfn releases/hsa-app-V<old-tag>/hsa hsa
systemctl --user restart hsa_app