From 1723d22931b8b1c001914529066c2cd57ddea424 Mon Sep 17 00:00:00 2001 From: lizerk Date: Mon, 7 Sep 2026 20:10:53 +0300 Subject: [PATCH] Add non-blocking Telegram deploy reports --- .gitea/workflows/deploy-production.yml | 94 ++++++++++++++++++++++++++ ops/deploy/README.md | 11 ++- 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-production.yml b/.gitea/workflows/deploy-production.yml index 4f6b81ff..c412dc25 100644 --- a/.gitea/workflows/deploy-production.yml +++ b/.gitea/workflows/deploy-production.yml @@ -20,8 +20,11 @@ jobs: env: CORP_DEPLOY_SSH_KEY: ${{ secrets.CORP_DEPLOY_SSH_KEY }} TARGET_SHA: ${{ gitea.sha }} + GITEA_RUN_ID: ${{ gitea.run_id }} run: | set -eu + status_file="${RUNNER_TEMP:-/tmp}/eusrr-production-deploy-${GITEA_RUN_ID}.status" + printf '%s\n' failure > "${status_file}" work_dir="$(mktemp -d)" trap 'rm -rf "${work_dir}"' EXIT HUP INT TERM umask 077 @@ -35,3 +38,94 @@ jobs: -o UserKnownHostsFile="${work_dir}/known_hosts" \ deploy@172.11.0.11 \ "deploy ${TARGET_SHA}" + printf '%s\n' success > "${status_file}" + + - name: Send deployment report to Telegram + if: always() + continue-on-error: true + shell: sh + env: + TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} + TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} + DEPLOY_SHA: ${{ gitea.sha }} + DEPLOY_REF: ${{ gitea.ref_name }} + DEPLOY_REPOSITORY: ${{ gitea.repository }} + DEPLOY_ACTOR: ${{ gitea.actor }} + GITEA_SERVER_URL: ${{ gitea.server_url }} + GITEA_RUN_ID: ${{ gitea.run_id }} + run: | + # Reporting must never change the deployment result. + set +e + + status_file="${RUNNER_TEMP:-/tmp}/eusrr-production-deploy-${GITEA_RUN_ID}.status" + if [ -r "${status_file}" ]; then + DEPLOY_OUTCOME="$(cat "${status_file}" 2>/dev/null)" + else + DEPLOY_OUTCOME=unknown + fi + + if [ -z "${TELEGRAM_BOT_TOKEN:-}" ] || [ -z "${TELEGRAM_CHAT_ID:-}" ]; then + echo "Telegram deployment report skipped: TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID is not configured." + exit 0 + fi + if ! command -v curl >/dev/null 2>&1; then + echo "Telegram deployment report skipped: curl is unavailable on the runner." + exit 0 + fi + + case "${DEPLOY_OUTCOME:-unknown}" in + success) + heading="✅ Деплой production успешно завершён" + production_state="Ревизия ${DEPLOY_SHA} активна в production." + ;; + failure) + heading="❌ Деплой production завершился ошибкой" + production_state="Новая ревизия не запущена; процедура отката сохраняет предыдущий релиз активным." + ;; + cancelled) + heading="⚠️ Деплой production был отменён" + production_state="Запрошенная ревизия не подтверждена как активная." + ;; + *) + heading="⚠️ Деплой production завершён со статусом ${DEPLOY_OUTCOME:-unknown}" + production_state="Запрошенная ревизия не подтверждена как активная." + ;; + esac + + run_url="${GITEA_SERVER_URL}/${DEPLOY_REPOSITORY}/actions/runs/${GITEA_RUN_ID}" + message="$(printf '%s\n\nРепозиторий: %s\nВетка: %s\nРевизия: %s\nИнициатор: %s\nТекущее состояние: %s\nЗапуск: %s' \ + "${heading}" \ + "${DEPLOY_REPOSITORY}" \ + "${DEPLOY_REF}" \ + "${DEPLOY_SHA}" \ + "${DEPLOY_ACTOR}" \ + "${production_state}" \ + "${run_url}")" + + response_file="$(mktemp)" + http_code="$(curl \ + --silent \ + --output "${response_file}" \ + --write-out '%{http_code}' \ + --connect-timeout 5 \ + --max-time 15 \ + --retry 2 \ + --retry-delay 2 \ + --retry-all-errors \ + --request POST \ + "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ + --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \ + --data-urlencode "text=${message}" \ + --data-urlencode "disable_web_page_preview=true" 2>/dev/null)" + curl_status=$? + rm -f "${response_file}" + + if [ "${curl_status}" -ne 0 ]; then + echo "Telegram deployment report failed: curl exited with status ${curl_status}." + elif [ "${http_code}" -lt 200 ] 2>/dev/null || [ "${http_code}" -ge 300 ] 2>/dev/null; then + echo "Telegram deployment report failed: Telegram returned HTTP ${http_code:-unknown}." + else + echo "Telegram deployment report sent." + fi + + exit 0 diff --git a/ops/deploy/README.md b/ops/deploy/README.md index bb63f6ea..19a44c17 100644 --- a/ops/deploy/README.md +++ b/ops/deploy/README.md @@ -35,10 +35,19 @@ automatically while the old release is accepting writes. 3. Store the private key as repository Actions secret `CORP_DEPLOY_SSH_KEY` in Gitea. -4. Run **Deploy production** manually from `master` and verify the first blue +4. To receive deployment reports in Telegram, add repository Actions secrets + `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID`. The chat ID may identify a user, + group, or channel that the bot is allowed to message. +5. Run **Deploy production** manually from `master` and verify the first blue deployment before enabling automatic master deployments. The SSH key is forced through `/usr/local/sbin/eusrr-deploy-ssh`. The deploy command rejects every revision except the current Gitea `origin/master` SHA. Logs are appended to `/var/log/eusrr-deploy.log`; the active slot and successful SHA are recorded under `/var/lib/eusrr-deploy`. + +The final workflow step reports successful, failed, cancelled, and unknown +deployment outcomes with the repository, branch, revision, actor, current +production state, and Gitea run link. Reporting is skipped when either Telegram +secret is absent. Missing tools, network failures, Telegram API errors, and +reporting timeouts are logged but never change the deployment result.