Files
minabot/deploy/README.md
2026-09-07 13:08:56 +02:00

3.8 KiB

Automatic production deployment

The server checks https://git.ayau.me/syntaxbullet/minabot.git, branch main, every minute after the last check finishes. A local commit is deployed after it is pushed to Gitea. Other branches are not deployed. If several commits arrive between checks, the latest fetched main commit is built.

git push origin main

The repository is public, so the server fetches over HTTPS without credentials. Gitea's SSH transport disconnected during transfer, so this checkout also pushes over HTTPS. Its repository-local credential helper reads the existing ayau Tea login only for this exact HTTPS host/repository; it stores no additional token copy. The personal Mac SSH key and Tea token are not copied to the server. If the repository becomes private, provision repository-scoped read credentials before the change.

The pipeline fetches into a bare repository and archives an exact commit into /opt/minabot/releases/<sha>. It builds a test image, runs typecheck and the full test suite, builds the runtime image, runs a disposable production smoke test, and validates Compose/Caddy. Secrets and production SQLite stay on the server; they are never synced from Git or development during a release.

After checks pass, Caddy and the old app stop briefly, a verified database snapshot is taken, and the new app starts before Caddy reopens public access. Discord workers never overlap. A lock prevents concurrent manual/timer deployments. Successful commits are recorded in /opt/minabot/deployed-sha and skipped on later checks.

A build/test failure leaves the old service running. Failed revisions are recorded in failed-sha and skipped until a new commit or an explicit retry. On startup failure, the old configuration/image is restored only if the schema and migration fingerprint is unchanged. Otherwise services remain stopped for operator recovery; the script never overwrites the production database with an old snapshot. Changes to .env.production or Caddy's pinned image remain explicit server operations.

Server operations

# Check status and recent deployment output
systemctl status minabot-deploy.timer minabot-deploy.service
journalctl -u minabot-deploy.service -n 100 --no-pager
cat /opt/minabot/deployed-sha

# Run a check now / retry a previously failed revision
sudo systemctl start minabot-deploy.service
/usr/local/bin/minabot-deploy --retry

# Pause / resume automatic deployment
sudo systemctl stop minabot-deploy.timer
sudo systemctl start minabot-deploy.timer

Build/test logs are inside each release directory. Retained release images and Docker build cache need occasional housekeeping; the script refuses a build when less than 2 GiB is free. Keep the current and previous known-good image and backups. Failures are logged locally; external alerts are not configured.

To install or update the controller from a reviewed checkout on the server:

sudo systemctl stop minabot-deploy.timer
# Let any running deployment finish before replacing its controller.
sudo systemctl start minabot-deploy.service
sudo install -m 755 deploy/deploy.sh /usr/local/bin/minabot-deploy
sudo install -m 644 deploy/minabot-deploy.service deploy/minabot-deploy.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now minabot-deploy.timer

Controller/service changes require this explicit installation; normal app, Dockerfile, Compose, and Caddyfile changes deploy automatically. Do not force-reset main to roll back: prefer a revert commit so the pipeline tests the result.

For first-time installation, omit the first two commands if the units do not exist.

bun test deploy/deploy.test.ts verifies success, idempotency, failure before cutover, safe rollback, and refusal to replace data after a schema change using isolated fake Git/Docker commands. It never contacts production.