deploy: automatically test and release pushed main commits
This commit is contained in:
71
deploy/README.md
Normal file
71
deploy/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Automatic production deployment
|
||||
|
||||
The server checks `git@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.
|
||||
|
||||
```sh
|
||||
git push origin main
|
||||
```
|
||||
|
||||
The server uses a repository-only read key under `/opt/minabot/git-auth`, registered
|
||||
as `minabot-production-read-only` in Gitea. The personal Mac SSH key is not copied
|
||||
to the server. Host verification uses the existing trusted Gitea host keys.
|
||||
|
||||
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
|
||||
|
||||
```sh
|
||||
# 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:
|
||||
|
||||
```sh
|
||||
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.
|
||||
|
||||
`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.
|
||||
Reference in New Issue
Block a user