- tsconfig (allowJs, strict .ts), npm run build -> dist/, typecheck, dev via tsx, ts-jest. - src/index.js is now a launcher (dist build when it matches, else tsx); server moved to app.js. - /api/v2: defineRoute with zod -> request validation, response stripping, OpenAPI 3.1 at /docs/v2; one error shape and one paged-list shape. First endpoints: events, event, me, my registrations. - deploy.sh/install.sh build the backend; rollback to older releases skips the build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ls1vMdg2GYqbnKZmPaX1ot
92 lines
3.6 KiB
Bash
92 lines
3.6 KiB
Bash
#!/usr/bin/env bash
|
|
# Updates this install: back up the database, check out the release, install, migrate,
|
|
# build, and reload PM2. If anything fails before the reload, the previous version keeps
|
|
# running and the checkout goes back to it.
|
|
#
|
|
# Usage (on the server, from the repo folder):
|
|
# bash scripts/deploy.sh # the latest main
|
|
# bash scripts/deploy.sh v1.37.3 # a tagged release
|
|
#
|
|
# PM2 uses this install's own ecosystem.config.js (app names, ports). It isn't in git, so
|
|
# deploys never change it; the first deploy creates it from ecosystem.config.example.js.
|
|
set -Eeuo pipefail
|
|
|
|
# The checkout below replaces this file, and bash reads a script as it runs — so run from a
|
|
# copy that can't change underneath us.
|
|
if [ -z "${HOPE_DEPLOY_COPY:-}" ]; then
|
|
COPY="$(mktemp)"
|
|
cp "$0" "$COPY"
|
|
HOPE_DEPLOY_COPY=1 HOPE_DEPLOY_DIR="$(cd "$(dirname "$0")/.." && pwd)" exec bash "$COPY" "$@"
|
|
fi
|
|
|
|
cd "$HOPE_DEPLOY_DIR"
|
|
TARGET="${1:-main}"
|
|
PREVIOUS="$(git describe --tags --exact-match 2>/dev/null || git rev-parse --short HEAD)"
|
|
|
|
# Keep this install's PM2 config safe across the checkout (older releases tracked it in git).
|
|
PM2_CONFIG="ecosystem.config.js"
|
|
PM2_KEEP="$(mktemp)"
|
|
HAVE_PM2_CONFIG=0
|
|
if [ -f "$PM2_CONFIG" ]; then cp "$PM2_CONFIG" "$PM2_KEEP"; HAVE_PM2_CONFIG=1; fi
|
|
trap 'rm -f "$0" "$PM2_KEEP"' EXIT
|
|
# Out of the way before a checkout: back to the committed version if git tracks it in this
|
|
# release, otherwise removed (a release that still tracks it would refuse to overwrite it).
|
|
clear_pm2_config() {
|
|
git checkout -q -- "$PM2_CONFIG" 2>/dev/null || rm -f "$PM2_CONFIG"
|
|
}
|
|
restore_pm2_config() {
|
|
if [ "$HAVE_PM2_CONFIG" = 1 ]; then cp "$PM2_KEEP" "$PM2_CONFIG"; fi
|
|
}
|
|
|
|
# Check out a tag, or the latest main (detached, so local main is never in the way).
|
|
checkout() {
|
|
clear_pm2_config
|
|
if [ "$1" = "main" ]; then
|
|
git fetch --quiet origin main
|
|
git checkout -q --detach origin/main
|
|
else
|
|
git fetch --tags --quiet origin
|
|
git checkout -q "$1"
|
|
fi
|
|
restore_pm2_config
|
|
}
|
|
|
|
echo "==> Deploying $TARGET (currently $PREVIOUS)"
|
|
|
|
echo "==> Backing up the database"
|
|
(cd backend && node -e "require('dotenv').config(); require('./src/utils/backupUtils').runBackup().then(r => console.log(' ', r.filename)).catch(e => { console.error(' Backup failed:', e.message); process.exit(1); })")
|
|
|
|
rollback() {
|
|
# set -E passes this trap into ( … ) subshells too; only the script itself rolls back.
|
|
if [ "$BASH_SUBSHELL" -gt 0 ]; then return; fi
|
|
echo "!!> Deploy failed — going back to $PREVIOUS (the running version was not touched)"
|
|
clear_pm2_config
|
|
git checkout -q "$PREVIOUS"
|
|
restore_pm2_config
|
|
# Releases from 1.51.0 on have a TypeScript build; older ones run src/ as it is.
|
|
(cd backend && npm ci --include=dev --silent && { ! grep -q '"build":' package.json || npm run build --silent; }) || true
|
|
(cd frontend && npm ci --silent && npm run build --silent) || true
|
|
}
|
|
trap rollback ERR
|
|
|
|
checkout "$TARGET"
|
|
DEPLOYED="$(git describe --tags --exact-match 2>/dev/null || git rev-parse --short HEAD)"
|
|
|
|
if [ ! -f "$PM2_CONFIG" ]; then
|
|
cp ecosystem.config.example.js "$PM2_CONFIG"
|
|
echo " Created $PM2_CONFIG from the example — check its app names and port."
|
|
fi
|
|
|
|
echo "==> Backend: install, migrate and build"
|
|
# --include=dev: the TypeScript build needs the type packages even where NODE_ENV=production.
|
|
(cd backend && npm ci --include=dev && npm run prisma:deploy && npm run build)
|
|
|
|
echo "==> Frontend: install and build"
|
|
(cd frontend && npm ci && npm run build)
|
|
|
|
trap - ERR
|
|
echo "==> Reloading PM2"
|
|
pm2 reload "$PM2_CONFIG" --update-env
|
|
|
|
echo "==> Deployed $TARGET ($DEPLOYED)"
|