Files
pleno-vue/.github/workflows/deploy.yml
T
2401ebb674 TRU-96: Sergii Review Batch smoke test for truckwash.io dashboard (#320)
## Summary

Adds a Sergii-specific smoke test that validates the **Sergii Review
Batch** project surfaces (Linear project `Sergii Review Batch` — TRU-68,
TRU-72, TRU-75) are still functioning on the deployed truckwash.io
dashboard after a release. The test runs in the existing deploy workflow
alongside the generic smoke test and triggers auto-rollback if it fails.

## Why

TRU-96 ("SENERE 4: Deploy Sergii changes to truckwash.io dashboard (test
that it works first)") calls for deploying Sergii's batch of changes to
production with a test-first gate. The current generic
`scripts/smoke-test.sh` only covers `/login`, `/healthz`, and the public
self-serve vehicle step — it does not probe any of the Sergii-touch
surfaces. This PR closes that gap.

## What ships

| File | Purpose |
|---|---|
| `scripts/smoke-test-sergii.sh` | New release-gate smoke test covering
the Sergii Review Batch surfaces |
| `.github/workflows/deploy.yml` | Runs the Sergii smoke test after the
generic one, triggers auto-rollback if it fails, distinguishes failure
modes in the Slack status message |
| `tests/unit/smoke-test-sergii.spec.js` | 9 vitest assertions that lock
the script content and the deploy.yml wiring (prevents accidental
removal of the Sergii release gate) |

## Surfaces covered

- **TRU-72 — Sergii's pages 6-10 review** (`/admin/customer`,
`/admin/product`, `/admin/order`, `/admin/booking`, `/admin/invoicing`)
— must not 5xx.
- **TRU-68 — Sergii's customer email flow** (`/api/customer`,
`/kundeoprettelse`) — must remain 2xx.
- **TRU-75 — Sergii's UVS option** (`/self-serve/program`,
`/self-serve/vehicle`) — must remain 2xx.
- **Dashboard bootstrap sanity** (`/healthz`, `/api/ping`, `/login`) —
the generic smoke test also covers these, but the Sergii script
re-checks to fail-fast on a totally broken deploy.

## Behaviour

- Defaults to `https://staging.truckwash.io` and respects
`SMOKE_BASE_URL` and `SMOKE_TIMEOUT` env vars.
- Exits 0 on all-pass, 1 on any failure.
- `continue-on-error: true` on the workflow step so a failure does not
mask the actual deploy step outcome — the auto-rollback step separately
keys off the Sergii step outcome.
- No authenticated calls, so the test is safe to run unattended in the
deploy workflow.

## Test

```
npx vitest run tests/unit/smoke-test-sergii.spec.js
```

→ **9/9 passed** in 487ms.

## Linked Linear issues

- TRU-96 — https://linear.app/truck-wash-aps/issue/TRU-96 (this PR)
- TRU-68, TRU-72, TRU-75 — covered by the new smoke test

---------

Co-authored-by: Pleno Bugfix Bot <bugfix-bot@pleno.local>
Co-authored-by: Truck Wash Bugfix <bugfix@truckwash.io>
2026-08-16 22:06:06 +02:00

113 lines
3.4 KiB
YAML

name: Deploy pleno-vue to Hetzner (staging)
on:
push:
branches: [master]
workflow_dispatch:
concurrency:
group: deploy-pleno-vue
cancel-in-progress: false
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
jobs:
test-and-deploy:
name: Build + Deploy
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install + Build
run: |
npm ci --ignore-scripts
npm run build
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }}
- name: Add host key
run: |
mkdir -p ~/.ssh
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
- name: Pre-deploy snapshot
id: pre
run: |
ssh "$DEPLOY_USER@$DEPLOY_HOST" '
set -e
cd /opt/pleno-vue
git rev-parse HEAD > /tmp/last_deploy_sha
echo "pre_sha=$(cat /tmp/last_deploy_sha)" >> $GITHUB_OUTPUT
'
- name: Deploy
id: deploy
run: |
ssh "$DEPLOY_USER@$DEPLOY_HOST" '
set -e
cd /opt/pleno-vue
git fetch origin master
git reset --hard origin/master
npm ci --ignore-scripts
npm run build
sudo systemctl reload nginx || true
sudo systemctl reload pleno-vue || true
echo "Deploy complete: $(git rev-parse --short HEAD)"
'
- name: Smoke test
id: smoke
continue-on-error: true
env:
SMOKE_BASE_URL: ${{ secrets.SMOKE_BASE_URL }}
run: |
bash scripts/smoke-test.sh "$SMOKE_BASE_URL"
- name: Sergii Review Batch smoke test (TRU-96)
id: smoke_sergii
continue-on-error: true
env:
SMOKE_BASE_URL: ${{ secrets.SMOKE_BASE_URL }}
run: |
bash scripts/smoke-test-sergii.sh "$SMOKE_BASE_URL"
- name: Auto-rollback on smoke failure
if: steps.smoke.outcome == 'failure' || steps.smoke_sergii.outcome == 'failure'
run: |
reason="$([ "${{ steps.smoke.outcome }}" = 'failure' ] && echo 'generic smoke' || echo 'Sergii Review Batch smoke')"
echo "::error::$reason test failed — rolling back to ${{ steps.pre.outputs.pre_sha }}"
ssh "$DEPLOY_USER@$DEPLOY_HOST" '
set -e
cd /opt/pleno-vue
git reset --hard ${{ steps.pre.outputs.pre_sha }}
npm ci --ignore-scripts
npm run build
sudo systemctl reload nginx || true
'
- name: Post Slack status
if: always()
uses: slackapi/slack-github-action@v1.27.0
with:
channel-id: ${{ secrets.AI_DAILY_CHANNEL }}
payload: |
{
"text": "${{ job.status == 'success' && '✅' || '❌' }} Deploy *pleno-vue@${{ github.sha[0:7] }}* — ${{ job.status }}\n${{ steps.smoke.outcome == 'failure' && '⚠️ Generic smoke FAILED → auto-rolled back' || steps.smoke_sergii.outcome == 'failure' && '⚠️ Sergii Review Batch smoke FAILED → auto-rolled back' || '✓ Smoke (generic + Sergii) passed' }}"
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}