Skip to content

chore(ci): GitHub owner maonakamoto -> catomean #586

chore(ci): GitHub owner maonakamoto -> catomean

chore(ci): GitHub owner maonakamoto -> catomean #586

name: Deploy production app
# Push to main → build + rsync to production app revampit.orangecat.ch.
# One-time setup (Settings → Secrets → Actions):
# HETZNER_SSH_PRIVATE_KEY — private key for ubuntu@167.233.22.31
# SELFHOST_ENV — full contents of .env.selfhost.local (multiline OK)
# AUTH_TEST_USER_PASSWORD — non-admin E2E account (butaeff@gmail.com)
# AUTH_TEST_ADMIN_PASSWORD — staff E2E account (georgy.butaev@revamp-it.ch)
# Without deploy secrets the job logs a notice and exits cleanly.
# Without E2E passwords the post-deploy inventory step is skipped.
on:
workflow_dispatch: {}
push:
branches: [main]
concurrency:
group: deploy-selfhost-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy:
name: revampit.orangecat.ch
runs-on: ubuntu-latest
timeout-minutes: 45
outputs:
deployed: ${{ steps.mark-deployed.outputs.deployed }}
env:
HETZNER_SSH_PRIVATE_KEY: ${{ secrets.HETZNER_SSH_PRIVATE_KEY }}
SELFHOST_ENV: ${{ secrets.SELFHOST_ENV }}
steps:
- name: Check secrets configured
id: secrets
run: |
if [ -z "$HETZNER_SSH_PRIVATE_KEY" ] || [ -z "$SELFHOST_ENV" ]; then
echo "::notice::HETZNER_SSH_PRIVATE_KEY and/or SELFHOST_ENV not set — skipping self-host deploy. Push from a machine with .env.selfhost.local still deploys via the pre-push hook."
echo "configured=false" >> "$GITHUB_OUTPUT"
else
echo "configured=true" >> "$GITHUB_OUTPUT"
fi
- name: Checkout code
if: steps.secrets.outputs.configured == 'true'
uses: actions/checkout@v7
- name: Setup Node.js
if: steps.secrets.outputs.configured == 'true'
uses: actions/setup-node@v7
with:
node-version: '20'
cache: npm
- name: Install dependencies
if: steps.secrets.outputs.configured == 'true'
run: npm ci
# Persist Next.js's incremental compiler cache across runs. The build runs
# on this ephemeral runner, so without this every build is COLD (full
# recompile). restore-keys falls back to the latest cache for the same
# lockfile, making subsequent builds incremental (warm).
- name: Cache Next.js build
if: steps.secrets.outputs.configured == 'true'
uses: actions/cache@v6
with:
path: .next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
restore-keys: |
nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-
# ONE definition of "verified" — the same bundle ci.yml runs, called
# verbatim. These four steps used to be re-inlined here, which quietly made
# the DEPLOY gate weaker than the MERGE gate: it omitted `lint:chrome`
# (the card-shell ratchet) and ran only the i18n subset instead of the
# full unit suite. A regression those cover could not block a merge but
# could still ship. `verify` = lint + umlauts + chrome + typecheck + test
# + build, and it already includes the i18n structure gate via `test`.
- name: Verify (lint + umlauts + chrome + typecheck + test + build)
if: steps.secrets.outputs.configured == 'true'
run: npm run verify
env:
# Same build-time placeholders ci.yml uses: this step runs BEFORE
# .env.selfhost.local is written, so strict env validation would
# otherwise fail during compile. The deploy script rebuilds after
# this with the real env and the release SHA; that second build is
# warm (the .next/cache step above), so the gate costs little.
AUTH_SECRET: ci-build-placeholder-secret-32chars
DB_HOST: localhost
DB_NAME: revampit_ci
DB_USER: ci
DB_PASSWORD: ci
- name: Write selfhost env
if: steps.secrets.outputs.configured == 'true'
run: |
printf '%s' "$SELFHOST_ENV" > .env.selfhost.local
chmod 600 .env.selfhost.local
- name: Setup SSH
if: steps.secrets.outputs.configured == 'true'
run: |
mkdir -p ~/.ssh
printf '%s\n' "$HETZNER_SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H 167.233.22.31 >> ~/.ssh/known_hosts
- name: Deploy
if: steps.secrets.outputs.configured == 'true'
run: bash scripts/selfhost-deploy-revampit.sh
- name: Mark deployed
id: mark-deployed
if: steps.secrets.outputs.configured == 'true'
run: echo "deployed=true" >> "$GITHUB_OUTPUT"
post-deploy-smoke:
name: Read-only prod smoke
runs-on: ubuntu-latest
needs: deploy
if: needs.deploy.outputs.deployed == 'true'
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v7
# Read-only: public pages render + DB-backed public APIs return success.
# No login, no prod mutation. The heavier authenticated dual-persona
# journeys (which mutate prod) are manual: npm run test:e2e:inventory:prod.
- name: Run read-only smoke (public pages + APIs)
run: bash scripts/post-deploy-smoke.sh