feat(fase-17): deploy script HEAD-tag check + tag column in deploy log

deploy-erosi.sh now runs `git describe --exact-match --tags HEAD` up
front. When HEAD is not at a tag, prints a yellow warning and sleeps
5s so the operator can Ctrl-C and tag before the rsync starts (no
abort — keeps untagged hotfix deploys possible). When a tag is
present, surfaces it in the banner next to the SHA.

`.deploys.log` gains a 4th tab-separated column: the tag (empty when
absent). The 3-column compat for pre-Fase-17 rows is preserved — the
rollback script's existing `cut -f1/-f2/-f3` keeps working, and `cut
-f4` returns the empty string for the older rows.

rollback-erosi.sh:
- `--list` reformats each row through awk so the tag is visible (with
  "(no tag)" placeholder for older rows), falling back to the raw log
  when awk isn't on PATH.
- The target banner shows `git tag: <tag>` when present.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 01:21:23 +02:00
parent f549dc53a2
commit 489fc3ec87
2 changed files with 49 additions and 4 deletions

View File

@@ -40,7 +40,26 @@ REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
# rsync without `.git`, so the remote can't run `git rev-parse`.
GIT_SHA="$(cd "$REPO_ROOT" && git rev-parse --short HEAD 2>/dev/null || echo dev)"
echo "==> Deploying to $DEPLOY_HOST:$DEPLOY_PATH (commit $GIT_SHA)"
# Fase 17.3 — capture the exact-match tag on HEAD (if any). Empty
# string when HEAD is between tags. Warn (don't block) when missing
# so untaggable hotfix deploys still go through, and stamp the tag
# into .deploys.log so the rollback script can surface it.
GIT_TAG="$(cd "$REPO_ROOT" && git describe --exact-match --tags HEAD 2>/dev/null || true)"
if [ -z "$GIT_TAG" ]; then
# ANSI yellow — visible enough to read past a terminal full of
# rsync output, but no exit. Sleep gives the operator a 5s window
# to Ctrl-C and tag HEAD before the rsync starts.
printf '\033[33mWARNING:\033[0m HEAD is not at a tagged commit. Deploys without a tag\n'
printf ' won'\''t map cleanly to CHANGELOG entries. Continue? [5s abort]\n'
sleep 5
fi
if [ -n "$GIT_TAG" ]; then
echo "==> Deploying to $DEPLOY_HOST:$DEPLOY_PATH (commit $GIT_SHA, tag $GIT_TAG)"
else
echo "==> Deploying to $DEPLOY_HOST:$DEPLOY_PATH (commit $GIT_SHA, no tag)"
fi
# ── 1. Ensure target dir exists ────────────────────────────────────────────
ssh "$DEPLOY_HOST" "sudo mkdir -p $DEPLOY_PATH && sudo chown \$(id -u):\$(id -g) $DEPLOY_PATH"
@@ -154,10 +173,15 @@ REMOTE
# can substitute it into the Dockerfile build-arg (compose reads it from
# the same shell, not from .env, so a transient export is enough). ssh
# doesn't accept VAR=value args directly, so we prefix `env`.
ssh "$DEPLOY_HOST" env GIT_SHA="$GIT_SHA" bash -s << 'REMOTE'
#
# Fase 17.3.2: also forward GIT_TAG so the deploy log gets a 4th tab-
# separated column (empty string when HEAD is not at a tag — preserves
# the 3-column compat the rollback script's `cut -f1,2,3` already reads).
ssh "$DEPLOY_HOST" env GIT_SHA="$GIT_SHA" GIT_TAG="${GIT_TAG:-}" bash -s << 'REMOTE'
set -euo pipefail
cd /opt/colectivo
: "${GIT_SHA:=dev}"
: "${GIT_TAG:=}"
echo "--- Building app image (commit $GIT_SHA)"
GIT_SHA="$GIT_SHA" docker compose --env-file .env -f infra/docker-compose.erosi.yml \
@@ -217,9 +241,13 @@ docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
-c "NOTIFY pgrst, 'reload schema';"
# Record the successful deploy in .deploys.log (read by rollback-erosi.sh).
# Format: <iso-ts>\t<sha>\t<backup-file>\t<tag-or-empty>
# The 4th column is Fase 17 — older rows have 3 columns; the rollback
# script's `cut -f4` returns empty for them, which is the right
# "no tag" sentinel.
backup_file=$(cat /tmp/.colectivo-last-backup 2>/dev/null || echo "")
deploy_ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
printf '%s\t%s\t%s\n' "$deploy_ts" "$GIT_SHA" "$backup_file" \
printf '%s\t%s\t%s\t%s\n' "$deploy_ts" "$GIT_SHA" "$backup_file" "$GIT_TAG" \
>> /opt/colectivo/.deploys.log
rm -f /tmp/.colectivo-last-backup
echo "--- Recorded deploy in /opt/colectivo/.deploys.log"