diff --git a/.env.deploy.example b/.env.deploy.example new file mode 100644 index 0000000..8bdf80e --- /dev/null +++ b/.env.deploy.example @@ -0,0 +1,7 @@ +# Copy to .env.deploy for local runs: set -a && source .env.deploy && set +a && ./scripts/deploy-talkpro.sh +# In Gitea, use repository secrets instead (see .gitea/workflows/deploy-talkpro.yml). + +TALKPRO_HOST=13.214.179.69 +TALKPRO_USER=ubuntu +TALKPRO_REMOTE_ROOT=/home/ubuntu/talkpro +TALKPRO_SSH_KEY_FILE=/absolute/path/to/luis-only.pem diff --git a/.gitea/workflows/deploy-talkpro.yml b/.gitea/workflows/deploy-talkpro.yml new file mode 100644 index 0000000..563a8b8 --- /dev/null +++ b/.gitea/workflows/deploy-talkpro.yml @@ -0,0 +1,50 @@ +# Build talk-pro and rsync dist/ to the marketing VPS (SSH host talkpro). +# +# Gitea repo secrets (Settings → Secrets): +# TALKPRO_SSH_PRIVATE_KEY full PEM for ubuntu@talkpro (same as luis-only.pem) +# TALKPRO_HOST e.g. 13.214.179.69 +# +# Optional secrets: +# TALKPRO_USER default ubuntu +# TALKPRO_REMOTE_ROOT default /home/ubuntu/talkpro +# +# Requires a runner with: node 22+, npm, rsync, ssh, ssh-keyscan. +# Site-links API (/api/site-links) is deployed separately from the parent talkpro repo. + +name: Deploy to talkpro + +on: + push: + branches: + - main + - master + workflow_dispatch: + +jobs: + build-and-sync: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + + - name: Trust host key + env: + TALKPRO_HOST: ${{ secrets.TALKPRO_HOST }} + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + ssh-keyscan -H "$TALKPRO_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true + + - name: Build and rsync to talkpro + env: + TALKPRO_HOST: ${{ secrets.TALKPRO_HOST }} + TALKPRO_USER: ${{ secrets.TALKPRO_USER }} + TALKPRO_REMOTE_ROOT: ${{ secrets.TALKPRO_REMOTE_ROOT }} + TALKPRO_SSH_PRIVATE_KEY: ${{ secrets.TALKPRO_SSH_PRIVATE_KEY }} + run: bash scripts/deploy-talkpro.sh diff --git a/.gitignore b/.gitignore index 7e07c2b..c6dae63 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ dist/ .env .env.* !.env.example +!.env.deploy.example +.env.deploy diff --git a/README.md b/README.md index d68a29c..a589a2a 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,29 @@ Open [http://localhost:4321](http://localhost:4321) | `npm run build` | Build for production into `dist/` | | `npm run preview` | Preview production build locally | +## Deploy (Gitea Actions → talkpro.info) + +Pushes to **`main`** or **`master`** run [`.gitea/workflows/deploy-talkpro.yml`](.gitea/workflows/deploy-talkpro.yml): `npm ci` → `npm run build` → `rsync` `dist/` to the marketing server (`/home/ubuntu/talkpro`). + +**Repository secrets** (Gitea → Settings → Secrets): + +| Secret | Value | +|--------|--------| +| `TALKPRO_SSH_PRIVATE_KEY` | SSH private key (PEM) for `ubuntu@talkpro` | +| `TALKPRO_HOST` | Server IP, e.g. `13.214.179.69` | +| `TALKPRO_USER` | Optional; default `ubuntu` | +| `TALKPRO_REMOTE_ROOT` | Optional; default `/home/ubuntu/talkpro` | + +Manual deploy from this repo: + +```bash +cp .env.deploy.example .env.deploy # edit paths +set -a && source .env.deploy && set +a +bash scripts/deploy-talkpro.sh +``` + +`/api/site-links` (APK / App Store URLs) is still updated via the parent **talkpro** repo: `./scripts/post-talkpro-site-links.sh` on your laptop. + ## Project Structure ``` diff --git a/scripts/deploy-talkpro.sh b/scripts/deploy-talkpro.sh new file mode 100755 index 0000000..718e83a --- /dev/null +++ b/scripts/deploy-talkpro.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Build Astro dist/ and rsync to the Talk Pro marketing host (talkpro.info). +# Used by Gitea Actions and for manual deploys from this repo. +# +# Required env: +# TALKPRO_HOST e.g. 13.214.179.69 +# Optional: +# TALKPRO_USER default ubuntu +# TALKPRO_REMOTE_ROOT default /home/ubuntu/talkpro +# TALKPRO_SSH_PRIVATE_KEY PEM contents (CI / Gitea secret) +# TALKPRO_SSH_KEY_FILE path to PEM (local) +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +HOST="${TALKPRO_HOST:?Set TALKPRO_HOST (server IP or hostname)}" +USER="${TALKPRO_USER:-ubuntu}" +REMOTE_ROOT="${TALKPRO_REMOTE_ROOT:-/home/ubuntu/talkpro}" +[[ -n "$USER" ]] || USER=ubuntu +[[ -n "$REMOTE_ROOT" ]] || REMOTE_ROOT=/home/ubuntu/talkpro + +KEY_FILE="${TALKPRO_SSH_KEY_FILE:-}" +TMP_KEY="" +cleanup() { + [[ -n "$TMP_KEY" && -f "$TMP_KEY" ]] && rm -f "$TMP_KEY" +} +trap cleanup EXIT + +if [[ -n "${TALKPRO_SSH_PRIVATE_KEY:-}" ]]; then + TMP_KEY="$(mktemp)" + chmod 600 "$TMP_KEY" + printf '%s\n' "$TALKPRO_SSH_PRIVATE_KEY" > "$TMP_KEY" + KEY_FILE="$TMP_KEY" +elif [[ -z "$KEY_FILE" || ! -f "$KEY_FILE" ]]; then + echo "Set TALKPRO_SSH_PRIVATE_KEY (PEM) or TALKPRO_SSH_KEY_FILE (path)" >&2 + exit 1 +fi +chmod 600 "$KEY_FILE" + +SSH_OPTS=(-i "$KEY_FILE" -o BatchMode=yes -o StrictHostKeyChecking=accept-new) +RSYNC_SSH="ssh -i ${KEY_FILE} -o BatchMode=yes -o StrictHostKeyChecking=accept-new" + +if [[ -f package-lock.json ]]; then + npm ci +else + npm install +fi +npm run build + +"${SSH[@]}" "${USER}@${HOST}" "mkdir -p ${REMOTE_ROOT}" + +rsync -avz --delete \ + -e "$RSYNC_SSH" \ + dist/ \ + "${USER}@${HOST}:${REMOTE_ROOT}/" + +echo "Deployed dist/ → ${USER}@${HOST}:${REMOTE_ROOT}/"