~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain

photography-focused photo sharing platform

grain.social
1 collaborator
0
2
71 lines · 2.9 KB Raw History
# Deploys main to the Hetzner host once this commit's test and check have
# passed. The appview image is built from this checkout on the host, over
# SSH, as a candidate, grain:build-<commit>, while the checks run; once
# they pass it becomes grain:current and the grain service is recreated
# from it, leaving the rest of the stack as it is. grain-deploy on the
# host rebuilds the whole stack by hand.
#
# When main has moved past this commit by the time the checks pass, the
# candidate is dropped and the run passes: the newer commit deploys. Once
# a deploy starts it finishes; a newer one waits for it (superseded:
# finish).
#
# It runs on ci.knotless.dev alone, the runner on knotless.dev's own host,
# so the key never reaches the hosted runner that checks pulls. There
# DEPLOY_SSH_KEY is sealed to pushes to main alone (`knotless secret
# knotless://grain.social/grain set DEPLOY_SSH_KEY --runner ci.knotless.dev
# --ref refs/heads/main`). Its public half is in root's authorized_keys on
# the host.
on:
  push: { refs: [refs/heads/main] }
superseded: finish
image: docker:28-cli
runners: [ci.knotless.dev]
secrets: [DEPLOY_SSH_KEY]
env:
  GRAIN_HOST: root@167.233.237.163
steps:
  - name: tools
    run: |
      apk add --no-cache curl openssh-client
      curl -fsSL https://knotless.dev/install.sh | KNOTLESS_INSTALL_DIR=/usr/local/bin sh
  - name: key
    run: |
      mkdir -p ~/.ssh && chmod 700 ~/.ssh
      printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519 && chmod 600 ~/.ssh/id_ed25519
      printf 'Host *\n  StrictHostKeyChecking accept-new\n' > ~/.ssh/config
  - name: build
    timeout: 30
    run: |
      DOCKER_HOST="ssh://$GRAIN_HOST" docker build -t "grain:build-$KNOTLESS_RUN_SHA" .
  - name: checks
    timeout: 30
    run: |
      repo="knotless://$KNOTLESS_RUN_REPO"
      end=$(($(date +%s) + 1500))
      for wf in test check; do
        left=$((end - $(date +%s)))
        [ "$left" -gt 0 ] || left=1
        out=$(knotless checks "$repo" --ref "$KNOTLESS_RUN_REF" --commit "$KNOTLESS_RUN_SHA" --workflow "$wf" --wait "$left")
        echo "$out"
        case "$out" in
          success*) ;;
          *)
            echo "$wf has not passed: not deploying"
            DOCKER_HOST="ssh://$GRAIN_HOST" docker rmi "grain:build-$KNOTLESS_RUN_SHA"
            exit 1
            ;;
        esac
      done
  - name: deploy
    run: |
      export DOCKER_HOST="ssh://$GRAIN_HOST"
      tip=$(knotless refs "knotless://$KNOTLESS_RUN_REPO" | awk -F '\t' -v ref="$KNOTLESS_RUN_REF" '$2 == ref { print $1 }')
      if [ "$tip" != "$KNOTLESS_RUN_SHA" ]; then
        echo "$KNOTLESS_RUN_REF is at ${tip:-nothing} now, not $KNOTLESS_RUN_SHA: a newer commit will deploy"
        docker rmi "grain:build-$KNOTLESS_RUN_SHA"
        exit 0
      fi
      docker tag "grain:build-$KNOTLESS_RUN_SHA" grain:current
      docker rmi "grain:build-$KNOTLESS_RUN_SHA"
      ssh "$GRAIN_HOST" 'docker compose -f /etc/grain/docker-compose.yml up -d --no-build grain && docker image prune -f'