#!/usr/bin/env bash # # The Great Bear deploy — push the current commit, build it with podman, and # install the Quadlet unit on emily with ansible. # # The image is built from the committed tree (`git archive HEAD`) and tagged # with its commit id, so what runs on the host is exactly what git knows about. # # ./deploy.sh deploy HEAD (tracked tree must be clean and pushed) # ./deploy.sh --force skip the guards (know what you are doing) # ./deploy.sh --no-push skip the push, if you already pushed # # Log in to the registry once beforehand: podman login registry.tanshu.com set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" BRANCH="${BRANCH:-main}" FORCE=false NO_PUSH=false for arg in "$@"; do case "$arg" in --force) FORCE=true ;; --no-push) NO_PUSH=true ;; *) echo "Usage: $0 [--force] [--no-push]" >&2 exit 1 ;; esac done # The build takes HEAD, so push first: otherwise the registry collects an image # for a commit that exists only on this machine. if [ "$NO_PUSH" != true ]; then echo "==> pushing" git push fi # Guards. Only tracked-file state matters — untracked and ignored files never # enter a `git archive HEAD` build. HEAD must match origin/$BRANCH so the commit # the image is tagged with is one the remote actually has. if [ "$FORCE" != true ]; then if [ -n "$(git status --porcelain --untracked-files=no)" ]; then echo "x tracked files modified - commit or stash first (or --force)" >&2 exit 1 fi git fetch origin --quiet if [ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/$BRANCH")" ]; then echo "x HEAD != origin/$BRANCH - push or pull first (or --force)" >&2 exit 1 fi fi TAG=$(git rev-parse --short HEAD) echo "==> deploying commit $TAG" echo "========================================================" echo " Building & Uploading Container Image (Podman)" echo "========================================================" make build-production COMMIT="$TAG" echo "" echo "========================================================" echo " Executing Ansible Deployment" echo "========================================================" # The play configures rootless Podman Quadlet units that belong to the # connecting user, so it must connect as that user and must NOT become root. # `-u` is the account that owns ~/.config/containers/systemd on the target. deploy_user="${ANSIBLE_USER:-tanshu}" cd ansible || exit # image_tag pins the exact commit; rollback is -e image_tag=. ansible-playbook -u "$deploy_user" playbook.yml -e "image_tag=$TAG"