name: Build and deploy on: push: branches: [main, staging, devel] workflow_dispatch: {} jobs: build-and-deploy: runs-on: self-hosted container: python:3.12-slim steps: - name: Install system dependencies run: | apt-get update apt-get install -y --no-install-recommends git rsync openssh-client nodejs - name: Checkout uses: actions/checkout@v4 with: submodules: false - name: Set up SSH key and pinned host keys # Same key used both as the theme repo's deploy key (Gitea) and for # the webserver login (below) — one secret, two authorized_keys entries. # Host keys are pinned via a var (known_hosts-format lines, pasted # directly from a known_hosts file that already trusts both hosts) # rather than fetched via ssh-keyscan — no extra network calls, no # TOFU, and no risk of tripping aquaria's connection-rate limiting. # KNOWN_HOSTS is shared between prod/test (just more lines in the # same blob); the deploy key itself picks PROD_/TEST_ by branch, # each falling back to the generic DEPLOY_SSH_KEY if unset. env: REF_NAME: ${{ github.ref_name }} PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }} TEST_DEPLOY_SSH_KEY: ${{ secrets.TEST_DEPLOY_SSH_KEY }} DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} KNOWN_HOSTS: ${{ vars.KNOWN_HOSTS }} run: | if [ "$REF_NAME" = "main" ]; then KEY="${PROD_DEPLOY_SSH_KEY:-$DEPLOY_SSH_KEY}" else KEY="${TEST_DEPLOY_SSH_KEY:-$DEPLOY_SSH_KEY}" fi mkdir -p ~/.ssh printf '%s\n' "$KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key printf '%s\n' "$KNOWN_HOSTS" >> ~/.ssh/known_hosts - name: Fetch theme submodule run: | GIT_SSH_COMMAND="ssh -4 -i ~/.ssh/deploy_key -o StrictHostKeyChecking=yes" \ git submodule update --init --recursive - name: Install Python dependencies run: pip install --no-cache-dir -r requirements.txt - name: Build site # main -> real prod config; staging -> prod-like preview (feeds, # absolute URLs) pointed at the dev webserver; devel (or anything # else) -> bare pelicanconf.py, same as a plain local build. # SITE_COMMIT/SITE_BRANCH are picked up by pelicanconf.py (and thus # every config that imports it) for the footer build-info line. env: REF_NAME: ${{ github.ref_name }} GITEA_SHA: ${{ github.sha }} run: | export SITE_COMMIT=$(echo "$GITEA_SHA" | cut -c1-8) export SITE_BRANCH="$REF_NAME" if [ "$REF_NAME" = "main" ]; then pelican -s publishconf.py elif [ "$REF_NAME" = "staging" ]; then pelican -s stagingconf.py else pelican fi - name: Deploy via rsync # main -> production, anything else (i.e. devel/staging) -> test. Host is # required per-target (no generic fallback); port/path/user each # fall back to a shared generic var/secret, then (port only) 22. env: REF_NAME: ${{ github.ref_name }} PROD_DEPLOY_HOST: ${{ vars.PROD_DEPLOY_HOST }} TEST_DEPLOY_HOST: ${{ vars.TEST_DEPLOY_HOST }} PROD_DEPLOY_PORT: ${{ vars.PROD_DEPLOY_PORT }} TEST_DEPLOY_PORT: ${{ vars.TEST_DEPLOY_PORT }} DEPLOY_PORT: ${{ vars.DEPLOY_PORT }} PROD_DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }} TEST_DEPLOY_PATH: ${{ vars.TEST_DEPLOY_PATH }} DEPLOY_PATH: ${{ vars.DEPLOY_PATH }} PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} TEST_DEPLOY_USER: ${{ secrets.TEST_DEPLOY_USER }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} run: | if [ "$REF_NAME" = "main" ]; then HOST="$PROD_DEPLOY_HOST" PORT="${PROD_DEPLOY_PORT:-$DEPLOY_PORT}" DPATH="${PROD_DEPLOY_PATH:-$DEPLOY_PATH}" USER_="${PROD_DEPLOY_USER:-$DEPLOY_USER}" else HOST="$TEST_DEPLOY_HOST" PORT="${TEST_DEPLOY_PORT:-$DEPLOY_PORT}" DPATH="${TEST_DEPLOY_PATH:-$DEPLOY_PATH}" USER_="${TEST_DEPLOY_USER:-$DEPLOY_USER}" fi echo "Deploying $REF_NAME -> $HOST" rsync -avz --delete \ -e "ssh -4 -i ~/.ssh/deploy_key -p ${PORT:-22} -o StrictHostKeyChecking=yes" \ output/ "${USER_}@${HOST}:${DPATH}"