ci(deploy): add deploy-placeholder workflow
Manual-trigger workflow that substitutes PUBLIC_SALES_EMAIL into placeholder/index.html, rsyncs placeholder/ to the Hetzner docroot over SSH:222, then smoke-tests the live origin for the sentinel string, mailto link, and logo URL. Shares the deploy-production concurrency group with deploy.yml so the two workflows can never race on the same docroot. Recovery is the regular deploy.yml — no separate un-placeholder workflow.
This commit is contained in:
99
.gitea/workflows/deploy-placeholder.yml
Normal file
99
.gitea/workflows/deploy-placeholder.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# cameleer-website — Deploy under-construction placeholder
|
||||
#
|
||||
# MANUAL TRIGGER ONLY. Replaces the live cameleer.io docroot with a static
|
||||
# "back shortly" page. Recovery: trigger Actions → deploy → Run workflow on
|
||||
# the desired main commit.
|
||||
#
|
||||
# Shares the deploy-production concurrency group with deploy.yml so the two
|
||||
# workflows queue rather than race on the same docroot.
|
||||
#
|
||||
# This workflow does NOT run npm/astro. The placeholder is hand-authored
|
||||
# static HTML in placeholder/, deliberately decoupled from the main build so
|
||||
# it can ship even when the main build is broken (which is the worst case in
|
||||
# which a placeholder is needed).
|
||||
#
|
||||
# Required secrets (repo settings → Actions → Secrets):
|
||||
# SFTP_HOST, SFTP_USER, SFTP_PATH, SFTP_KEY, SFTP_KNOWN_HOSTS
|
||||
# PUBLIC_SALES_EMAIL
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
name: deploy-placeholder
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-production
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Substitute sales email into placeholder
|
||||
env:
|
||||
PUBLIC_SALES_EMAIL: ${{ secrets.PUBLIC_SALES_EMAIL }}
|
||||
run: |
|
||||
set -e
|
||||
: "${PUBLIC_SALES_EMAIL:?PUBLIC_SALES_EMAIL secret must be set}"
|
||||
sed -i "s|__SALES_EMAIL__|${PUBLIC_SALES_EMAIL}|g" placeholder/index.html
|
||||
if grep -q '__SALES_EMAIL__' placeholder/index.html; then
|
||||
echo "Token __SALES_EMAIL__ still present after substitution — refusing to ship."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Configure SSH
|
||||
env:
|
||||
SFTP_KEY: ${{ secrets.SFTP_KEY }}
|
||||
SFTP_KNOWN_HOSTS: ${{ secrets.SFTP_KNOWN_HOSTS }}
|
||||
run: |
|
||||
set -e
|
||||
: "${SFTP_KEY:?SFTP_KEY secret must be set}"
|
||||
: "${SFTP_KNOWN_HOSTS:?SFTP_KNOWN_HOSTS secret must be set}"
|
||||
mkdir -p ~/.ssh
|
||||
printf '%s\n' "$SFTP_KEY" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||||
chmod 644 ~/.ssh/known_hosts
|
||||
if ! command -v rsync >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then
|
||||
if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi
|
||||
$SUDO apt-get update -qq
|
||||
$SUDO apt-get install -y --no-install-recommends rsync openssh-client
|
||||
fi
|
||||
|
||||
- name: Deploy via rsync
|
||||
env:
|
||||
SFTP_USER: ${{ secrets.SFTP_USER }}
|
||||
SFTP_HOST: ${{ secrets.SFTP_HOST }}
|
||||
SFTP_PATH: ${{ secrets.SFTP_PATH }}
|
||||
run: |
|
||||
: "${SFTP_USER:?SFTP_USER secret must be set}"
|
||||
: "${SFTP_HOST:?SFTP_HOST secret must be set}"
|
||||
: "${SFTP_PATH:?SFTP_PATH secret must be set}"
|
||||
# Hetzner Webhosting splits SSH into two ports:
|
||||
# port 22 — SFTP only, no remote command exec
|
||||
# port 222 — full SSH with shell exec (rsync needs this)
|
||||
# `--rsync-path=/usr/bin/rsync` tells the local rsync where to find
|
||||
# the remote binary on Hetzner's locked-down PATH.
|
||||
# `BatchMode=yes` disables interactive prompts.
|
||||
rsync -avz --delete --rsync-path=/usr/bin/rsync \
|
||||
-e "ssh -p 222 -i $HOME/.ssh/id_ed25519 -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts" \
|
||||
placeholder/ "$SFTP_USER@$SFTP_HOST:$SFTP_PATH/"
|
||||
|
||||
- name: Post-deploy smoke test
|
||||
run: |
|
||||
set -e
|
||||
echo "Confirming the placeholder is live on www.cameleer.io..."
|
||||
BODY=$(curl -sf https://www.cameleer.io/)
|
||||
echo "$BODY" | grep -qF 'Routes are remapping' \
|
||||
|| { echo "Sentinel string missing — placeholder did not land."; exit 1; }
|
||||
echo "$BODY" | grep -qF 'mailto:' \
|
||||
|| { echo "mailto: link missing — sales email substitution may have failed."; exit 1; }
|
||||
curl -sfI https://www.cameleer.io/cameleer-logo.png > /dev/null \
|
||||
|| { echo "cameleer-logo.png not reachable on the live origin."; exit 1; }
|
||||
echo "Placeholder is live."
|
||||
Reference in New Issue
Block a user