Run #120 (v0.3.0 deploy) failed at the microservice step: every service folder and ecosystem.config.js were "absent", and pm2 reported "File ecosystem.config.js not found". Root cause: ~/pms on pms1 is a sparse checkout limited to App/, so `git checkout -f $TAG` never materialised the service folders or the root ecosystem.config.js. The app itself deployed fine (App/ is in the sparse set) and prod stayed healthy. - deploy.yml: before managing services, disable sparse-checkout (and clear the legacy core.sparseCheckout config + .git/info/sparse-checkout), then re-checkout the tag to materialise the full tree. Idempotent / no-op once expanded. - Guard the pm2 call: if ecosystem.config.js is still absent, fail with a clear diagnostic (+ sparse-checkout list) instead of the cryptic PM2 error. - README: note the sparse-checkout expansion. Needs a fresh tag (e.g. v0.3.1) to re-run the deploy. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
112 lines
4.6 KiB
YAML
112 lines
4.6 KiB
YAML
name: Deploy release to production
|
|
|
|
# Pushing a release tag (vX.Y.Z) deploys that tag to the portal at
|
|
# pms.pelagiamarine.com. Runs on the pms1 host runner (label: host),
|
|
# which executes as shad0w with direct access to the pm2-managed app.
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
|
|
jobs:
|
|
deploy:
|
|
runs-on: host
|
|
steps:
|
|
- name: Deploy tag to ~/pms and restart ppms
|
|
run: |
|
|
set -euo pipefail
|
|
export NVM_DIR="$HOME/.nvm"
|
|
. "$NVM_DIR/nvm.sh"
|
|
|
|
TAG="${GITHUB_REF_NAME}"
|
|
echo "=== Deploying $TAG ==="
|
|
|
|
cd "$HOME/pms"
|
|
git fetch origin --tags --force
|
|
git checkout -f "refs/tags/$TAG"
|
|
|
|
cd App
|
|
pnpm install --frozen-lockfile
|
|
pnpm build # includes prisma generate
|
|
pnpm db:migrate:deploy
|
|
|
|
# NOT --update-env: this job runs inside the Forgejo Actions runner, whose
|
|
# environment includes an ephemeral FORGEJO_TOKEN (the per-job token, revoked
|
|
# when the job ends). --update-env would inject it into ppms, where it shadows
|
|
# the real PAT from .env (Next.js does not override an already-set process.env
|
|
# var) and breaks the Report Issue button once the job token expires. A plain
|
|
# restart re-execs ppms from the pm2 daemon's clean env, so .env wins.
|
|
pm2 restart ppms
|
|
echo "=== Deployed $TAG ==="
|
|
|
|
- name: Build & (re)start microservices
|
|
run: |
|
|
set -euo pipefail
|
|
export NVM_DIR="$HOME/.nvm"
|
|
. "$NVM_DIR/nvm.sh"
|
|
|
|
cd "$HOME/pms"
|
|
|
|
# ~/pms has historically been a SPARSE checkout limited to App/ (only the
|
|
# app deployed), so the service folders + ecosystem.config.js never landed
|
|
# on disk. Expand the working tree to the full repo, then re-materialise
|
|
# the tag. Idempotent: a no-op once sparse is disabled / if never sparse.
|
|
git sparse-checkout disable 2>/dev/null || true
|
|
git config --unset core.sparseCheckout 2>/dev/null || true
|
|
rm -f .git/info/sparse-checkout 2>/dev/null || true
|
|
git checkout -f "refs/tags/${GITHUB_REF_NAME}"
|
|
|
|
# Pull only the few keys the services need out of the app's .env (the
|
|
# single source of truth on the host). Never import PORT (each service's
|
|
# port is fixed in ecosystem.config.js) or the runner's ephemeral
|
|
# FORGEJO_TOKEN. Missing keys → empty, which the services tolerate.
|
|
envget() { grep -E "^$1=" App/.env 2>/dev/null | head -1 | sed -E 's/^[^=]+=//; s/^"//; s/"$//'; }
|
|
export PDF_SERVICE_TOKEN="$(envget PDF_SERVICE_TOKEN)"
|
|
export ALLOWED_ORIGIN="$(envget ALLOWED_ORIGIN)"
|
|
export EPFO_LIVE="$(envget EPFO_LIVE)"
|
|
|
|
# Build each present service (skip any not yet in the tree, e.g. before
|
|
# its feature PR has merged). npm install (not ci) — not every service
|
|
# carries a lockfile. Playwright's postinstall fetches the browser; the
|
|
# explicit install is a cached, idempotent backstop.
|
|
for svc in GstService EpfoService PdfService; do
|
|
[ -f "$svc/package.json" ] || { echo "skip $svc (absent)"; continue; }
|
|
echo "=== Building $svc ==="
|
|
( cd "$svc" && npm install --no-audit --no-fund && npx playwright install chromium && npm run build )
|
|
done
|
|
|
|
# Create on first release, zero-downtime reload thereafter. The
|
|
# ecosystem registers only services whose dirs exist.
|
|
if [ ! -f ecosystem.config.js ]; then
|
|
echo "ERROR: ecosystem.config.js absent in $(pwd) after checkout — sparse-checkout not expanded?"
|
|
git sparse-checkout list 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
pm2 startOrReload ecosystem.config.js --update-env
|
|
pm2 save
|
|
pm2 list
|
|
echo "=== Microservices up ==="
|
|
|
|
- name: Verify services respond
|
|
run: |
|
|
sleep 3
|
|
cd "$HOME/pms"
|
|
check() {
|
|
local dir="$1" port="$2"
|
|
[ -f "$dir/package.json" ] || { echo "skip $dir (absent)"; return 0; }
|
|
local code
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$port/health" || echo "000")
|
|
echo "$dir on :$port /health → HTTP $code"
|
|
test "$code" = "200"
|
|
}
|
|
check GstService 3003
|
|
check EpfoService 3004
|
|
check PdfService 3005
|
|
|
|
- name: Verify portal responds
|
|
run: |
|
|
sleep 5
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/login)
|
|
echo "Portal /login returned HTTP $code"
|
|
test "$code" = "200"
|