Skip to content

Deploy to amvara9

Deploy to amvara9 #255

# Deploy to amvara9 only when the production branch is pushed (this repo: `master`).
# Pushes to `development` do not run this workflow (merge to `master` to deploy). Use workflow_dispatch for manual runs.
# Repository: https://github.com/satisfecho/pos — workflow must run from satisfecho/pos; server clone must have origin = satisfecho/pos.
# Requires repository secret: SSH_PRIVATE_KEY_AMVARA9 (private key for root@amvara9; raw PEM or base64).
# Optional: DEPLOY_HOST (default 167.235.138.59), DEPLOY_USER (default root), DEPLOY_PATH (default /development/pos).
# Marketing sites under /<slug>/ (see config/marketing-sites.json): optional GUSTAZO_ARTIFACT_TOKEN / MARKETING_ARTIFACT_TOKEN (PAT with Actions read on each repo). CI rsync runs after git reset so bundles are not wiped.
# Optional repo Variables: GUSTAZO_BRANCH, GUSTAZO_ARTIFACT_NAME per legacy Gustazo defaults.
# Smoke test uses SMOKE_TEST_BASE_URL (default https://www.satisfecho.de) so SSL validates.
name: Deploy to amvara9
on:
push:
branches:
- master
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
# One deploy at a time to the same host/path regardless of branch (avoids overlapping git/build/up).
concurrency:
group: deploy-amvara9
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GUSTAZO_REPO: satisfecho/040_gustazo
GUSTAZO_BRANCH: ${{ vars.GUSTAZO_BRANCH }}
GUSTAZO_ARTIFACT_NAME: ${{ vars.GUSTAZO_ARTIFACT_NAME }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Fetch marketing site artifacts (curl + GitHub API)
env:
MARKETING_ARTIFACT_TOKEN: ${{ secrets.GUSTAZO_ARTIFACT_TOKEN }}
GH_TOKEN: ${{ secrets.GUSTAZO_ARTIFACT_TOKEN }}
MARKETING_SYNC_FORCE: "1"
# Fails the job if any listed site is still the placeholder (e.g. fine-grained PAT only on 040_gustazo)
MARKETING_VERIFY_NO_PLACEHOLDERS: "1"
run: bash scripts/sync-all-marketing-sites.sh
- name: Set up SSH
run: |
mkdir -p ~/.ssh
KEY="${{ secrets.SSH_PRIVATE_KEY_AMVARA9 }}"
echo "Key length: ${#KEY} chars, looks like PEM: $(echo \"$KEY\" | grep -q 'BEGIN' && echo \"$KEY\" | grep -q 'PRIVATE KEY' && echo yes || echo no)"
# If secret contains PEM markers, use as raw key; else decode as base64
if echo "$KEY" | grep -q "BEGIN" && echo "$KEY" | grep -q "PRIVATE KEY"; then
# Preserve newlines: interpret \n if stored literally, strip CR
printf '%b' "$KEY" | tr -d '\r' > ~/.ssh/deploy_key
else
echo "$KEY" | tr -d '\n\r\t ' | sed 's/[^A-Za-z0-9+\/=]//g' | base64 -d > ~/.ssh/deploy_key
fi
chmod 600 ~/.ssh/deploy_key
if ! ssh-keygen -y -f ~/.ssh/deploy_key > /dev/null 2>&1; then
echo "::error::Invalid SSH_PRIVATE_KEY_AMVARA9: ssh-keygen could not read the key. Paste the full raw key (-----BEGIN...END-----) or a single-line base64 string (base64 -w 0 keyfile)."
exit 1
fi
ssh-keyscan -H "${{ secrets.DEPLOY_HOST || '167.235.138.59' }}" >> ~/.ssh/known_hosts 2>/dev/null || true
# Git reset must run BEFORE rsync of marketing bundles: deploy-amvara9.sh uses `docker compose build`
# which COPYs front/sites/*. If we rsync before `git reset --hard`, placeholders from Git overwrite
# fetched artifacts on the server (explains Gustazo staying on placeholder in prod).
- name: Checkout latest code on amvara9 (git fetch / reset — marketing dirs reset to placeholders)
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST || '167.235.138.59' }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER || 'root' }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH || '/development/pos' }}
run: |
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
"${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '${DEPLOY_PATH}/front/sites'"
BRANCH="${{ github.ref_name }}"
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
"${DEPLOY_USER}@${DEPLOY_HOST}" \
"cd '${DEPLOY_PATH}' && git fetch origin && git checkout -f '${BRANCH}' && git reset --hard 'origin/${BRANCH}' && git clean -fd"
- name: Sync marketing sites to server (after git reset; bundles from Fetch step above)
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST || '167.235.138.59' }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER || 'root' }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH || '/development/pos' }}
run: |
rsync -az -e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new -o ServerAliveInterval=60" \
./front/sites/ "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/front/sites/"
- name: Build and restart stack on amvara9
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST || '167.235.138.59' }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER || 'root' }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH || '/development/pos' }}
timeout-minutes: 20
run: |
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new -o ServerAliveInterval=60 -o ServerAliveCountMax=10 \
"${DEPLOY_USER}@${DEPLOY_HOST}" "cd '${DEPLOY_PATH}' && bash scripts/deploy-amvara9.sh"
- name: Smoke test (landing, version, API health)
env:
SMOKE_TEST_BASE_URL: ${{ vars.SMOKE_TEST_BASE_URL || 'https://www.satisfecho.de' }}
run: |
BASE="${SMOKE_TEST_BASE_URL}"
echo "Smoke test: $BASE (landing), version in footer, $BASE/api/health"
LANDING_OK=""
for attempt in 1 2 3 4 5 6; do
echo "Landing HTTP check attempt ${attempt}/6..."
if curl -sf -o /dev/null -w "%{http_code}" "$BASE/" | grep -q 200; then
LANDING_OK=1
break
fi
[ "$attempt" -lt 6 ] && sleep 15
done
[ -n "$LANDING_OK" ] || (echo "Landing page failed after retries"; exit 1)
HTML=""
for attempt in 1 2 3 4 5 6; do
echo "Landing HTML + version meta attempt ${attempt}/6..."
HTML=$(curl -sfL "$BASE/?t=$(date +%s)") && break
[ "$attempt" -lt 6 ] && sleep 15
done
[ -n "$HTML" ] || (echo "Failed to fetch landing page after retries"; exit 1)
if echo "$HTML" | grep -qE 'name="app-version"[^>]*content="[0-9]+\.[0-9]+\.[0-9]+"'; then
echo "Version meta tag found in landing page."
elif echo "$HTML" | grep -q 'name="app-version"' && echo "$HTML" | grep -qE 'content="[0-9]+\.[0-9]+\.[0-9]+"'; then
echo "Version meta (split) found in landing page."
else
echo "Version meta tag missing in landing page HTML (expected app-version with semver)."
echo "First 500 chars of head: $(echo "$HTML" | head -c 500)"
exit 1
fi
echo "Version correctly shown in landing page (no login required)."
HEALTH_OK=""
for attempt in 1 2 3 4 5 6; do
echo "API health attempt ${attempt}/6..."
if curl -sf -o /dev/null -w "%{http_code}" "$BASE/api/health" | grep -q 200; then
HEALTH_OK=1
break
fi
[ "$attempt" -lt 6 ] && sleep 15
done
[ -n "$HEALTH_OK" ] || (echo "API health failed after retries"; exit 1)
echo "Smoke test passed."
echo "Marketing /gustazo/ (expect real bundle, not repo placeholder)"
if ! curl -sf -o /dev/null "$BASE/gustazo/"; then
echo "::warning::GET $BASE/gustazo/ did not return 200."
else
GZ_HTML=$(curl -sfL "$BASE/gustazo/?t=$(date +%s)" || true)
if echo "$GZ_HTML" | grep -q 'bundle not loaded'; then
echo "::warning::Gustazo still serves placeholder HTML (verify GUSTAZO_ARTIFACT_TOKEN and deploy rsync runs after git reset)."
else
echo "Gustazo path OK (no placeholder title)."
fi
fi