Legendary Arena Lab

Deploy Pipeline

wiki

Deploy Pipeline

Migration in progress. api.legendary-arena.com and its PostgreSQL are moving off Render onto a self-hosted DigitalOcean Ubuntu droplet fronted by Cloudflare, per docs/PLAN.md . Until decommission, Render stays warm as the rollback target.

Summary

The deploy pipeline is a GitHub Actions workflow that ships the application to the droplet over SSH on every push to main. It pulls, installs, builds, migrates, and reloads the la-server service — replacing Render’s push-to-main auto-deploy.

Mechanics

The owning artifact is .github/workflows/deploy.yml . Step by step:

  1. Trigger — fires on push to branches: [main] or manually via workflow_dispatch, and the job is guarded by if: vars.DEPLOY_ENABLED == 'true' && github.ref == 'refs/heads/main'. Until the droplet exists, the DEPLOY_ENABLED repository variable is unset, so the job is skipped (neutral) rather than failing on the missing host; set DEPLOY_ENABLED=true once the deploy secrets point at a real droplet (Phase 1+).
  2. Checkoutactions/checkout@v4 checks out the repo on the ubuntu-latest runner.
  3. SSH inappleboy/ssh-action@v1.2.0 connects to the droplet using the DEPLOY_HOST, DEPLOY_USER, and DEPLOY_SSH_KEY GitHub secrets.
  4. On-host script — runs under set -euo pipefail:
cd /opt/legendary-arena
git pull --ff-only origin main
pnpm install --frozen-lockfile
pnpm -r build
node scripts/migrate.mjs
sudo systemctl reload la-server

This replaces Render’s push-to-main auto-deploy, per docs/PLAN.md . Note the pipeline runs migrations inline via node scripts/migrate.mjs — unlike the app-deploy path that gates migrations behind a RUN_MIGRATIONS flag, here they run unconditionally on every deploy.

Interactions

Edge Cases

  • Until DEPLOY_ENABLED is set to true, the job is skipped by design — a pre-Phase-1 guard so an unset DEPLOY_HOST does not red-X every merge to main. Enabling it before the droplet and its three secrets exist just restores the missing server host failure.
  • The three GitHub secrets DEPLOY_HOST, DEPLOY_USER, and DEPLOY_SSH_KEY must be set or the SSH step fails immediately.
  • git pull --ff-only fails if the on-host tree has diverged or carries local commits, halting the deploy before any build.
  • A failed migration leaves a half-deployed state: set -euo pipefail means the systemctl reload only happens if every prior step succeeds.
  • This is the load-bearing “develop from anywhere” loop; rollback of a bad deploy means repointing to Render or reverting the commit and re-pushing.

Execute

The pipeline runs automatically on any push to main. To trigger it manually (the workflow_dispatch path):

gh workflow run "Deploy API Host"

Verify

Check the run status from the workflow name:

gh run list --workflow="Deploy API Host"

Then confirm the service on the host:

systemctl status la-server
curl -s localhost:3000/health

A healthy service returns from /health on port 3000.

References