#!/bin/bash # Upgrade DevDesk from the LotusGuild apt registry. Run by the host's webhook # listener (hook "devdesk-deploy") when CI publishes a v* tag; the tag's ref is # passed as $1. Safe for running sessions: package upgrades restart only # devdesk.service (ttyd), never devdesk-tmux.service where Claude lives. # # The hook runs this synchronously and returns its output, with HTTP 500 when # it fails, so CI's "Deploy to CT 126" job shows the real result (devdesk#12). set -euo pipefail LOG=${DEVDESK_DEPLOY_LOG:-/var/log/devdesk-deploy.log} SOURCES=${DEVDESK_APT_SOURCES:-sources.list.d/lotusguild.list} log() { printf '%s %s\n' "$(date '+%F %T')" "$*" >>"$LOG" } # The outcome goes to the log and to stdout (the webhook response). say() { log "$*" printf '%s\n' "$*" } fail() { say "deploy FAILED: $*" exit 1 } on_error() { local rc=$? say "deploy FAILED: line $1 exited $rc (details in $LOG)" exit "$rc" } trap 'on_error $LINENO' ERR # Wait for dpkg/apt rather than fail when unattended-upgrades or a manual apt # run holds the lock. APT_OPTS=(-o DPkg::Lock::Timeout=120 -o Dpkg::Use-Pty=0) exec 9>/run/devdesk-deploy.lock flock -w 900 9 || fail "another deploy is still running" want=${1:-} want=${want#refs/tags/} want=${want#v} before=$(dpkg-query -W -f='${Version}' devdesk 2>/dev/null || echo none) log "=== deploy: installed $before, release ${want:-latest}" refresh() { apt-get update -q "${APT_OPTS[@]}" -o Dir::Etc::sourcelist="$SOURCES" -o Dir::Etc::sourceparts=- \ -o APT::Get::List-Cleanup=0 >>"$LOG" 2>&1 } # The registry can lag the release by a few seconds: wait for the tagged version. candidate="" for _ in $(seq 1 18); do refresh || true candidate=$(apt-cache policy devdesk | awk '/Candidate:/ {print $2}') if [ -z "$want" ] || [ "$candidate" = "$want" ]; then break fi sleep 10 done if [ -n "$want" ] && [ "$candidate" != "$want" ]; then fail "the registry still offers ${candidate:-nothing}, not $want" fi if [ "$candidate" = "$before" ]; then say "already at $before; nothing to do" exit 0 fi DEBIAN_FRONTEND=noninteractive apt-get install -y -q --only-upgrade "${APT_OPTS[@]}" \ -o Dpkg::Options::=--force-confold devdesk >"$LOG" 2>&1 after=$(dpkg-query -W -f='${Version}' devdesk) if [ -n "$want" ] && [ "$after" != "$want" ]; then fail "installed $after, not $want" fi say "devdesk $before -> $after"