Skip to content

brand(evig): finish the copy sweep — kill remaining old-tagline / non… #423

brand(evig): finish the copy sweep — kill remaining old-tagline / non…

brand(evig): finish the copy sweep — kill remaining old-tagline / non… #423

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:
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@v4
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@v4
with:
path: .next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
restore-keys: |
nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-
- name: Run ESLint
if: steps.secrets.outputs.configured == 'true'
run: npm run lint
- name: Type check
if: steps.secrets.outputs.configured == 'true'
run: npm run typecheck
- name: i18n structure gate
if: steps.secrets.outputs.configured == 'true'
run: npm run test:i18n
- 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