From edac3fb010080c76dd434c46e82a2f2d8c59ccf9 Mon Sep 17 00:00:00 2001 From: pkirillw Date: Sat, 25 Jul 2026 00:33:29 +0300 Subject: [PATCH] =?UTF-8?q?CI:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=BD=D0=B0=20=D0=B5=D0=B4=D0=B8=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=B9=D0=BF=D0=BB=D0=B0=D0=B9=D0=BD=20ci-templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01ULKZHadoqyVmGKF8ukwmaW --- .gitea/workflows/deploy.yml | 115 +++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 48 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 7ce9e14..cc02a16 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,73 +1,92 @@ -name: Deploy Max Bot Test +name: Deploy on: push: - branches: - - main + branches: [main] workflow_dispatch: +# !!! Сгенерировано из ci-templates/deploy.template.yml скриптом sync-workflows.sh. +# !!! Правь ШАБЛОН и прогоняй sync, а не этот файл вручную. +# +# Раннер Gitea не умеет тянуть внешние uses:-actions (mkdir /.cache: permission +# denied), поэтому весь деплой — inline через SSH, без actions/checkout и т.п. jobs: deploy: runs-on: ubuntu-latest + env: + SERVICE: max-bot-test + HEALTHCHECK: "" + BUILD: "true" + SERVER_HOST: ${{ vars.SERVER_HOST }} + SERVER_PORT: ${{ vars.SERVER_PORT }} + SERVER_USER: ${{ vars.SERVER_USER }} + SERVER_BASE: ${{ vars.SERVER_BASE }} + NTFY_URL: ${{ vars.NTFY_URL }} steps: - name: Setup SSH env: - SSH_KEY: ${{ vars.SSH_PRIVATE_KEY }} + SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }} run: | mkdir -p ~/.ssh - echo "$SSH_KEY" | sed 's/^[[:space:]]*//' > ~/.ssh/id_rsa + printf '%s\n' "$SSH_KEY" | sed 's/^[[:space:]]*//' > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa - ssh-keyscan -p ${{ vars.SERVER_PORT }} ${{ vars.SERVER_HOST }} >> ~/.ssh/known_hosts + ssh-keyscan -p "$SERVER_PORT" "$SERVER_HOST" >> ~/.ssh/known_hosts 2>/dev/null - - name: Clone or pull on server + - name: Clone or reset repo on server run: | - ssh -i ~/.ssh/id_rsa -p ${{ vars.SERVER_PORT }} ${{ vars.SERVER_USER }}@${{ vars.SERVER_HOST }} " - if [ -d /home/pkirillw/dockered-services/max-bot-test/.git ]; then - cd /home/pkirillw/dockered-services/max-bot-test && git pull origin main + ssh -i ~/.ssh/id_rsa -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" " + set -e + URL=https://git.pkirillw-server.ru/pkirillw/$SERVICE.git + if [ -d '$SERVER_BASE/$SERVICE/.git' ]; then + cd '$SERVER_BASE/$SERVICE' + git rev-parse HEAD > /tmp/deploy_prev_$SERVICE + git fetch origin main && git reset --hard origin/main + elif [ -d '$SERVER_BASE/$SERVICE' ]; then + # папка есть, но не git (развёрнуто вручную) — инициализируем на месте + cd '$SERVER_BASE/$SERVICE' + git init -q + git remote add origin \$URL 2>/dev/null || git remote set-url origin \$URL + git fetch -q origin main && git reset --hard origin/main + : > /tmp/deploy_prev_$SERVICE else - cd /home/pkirillw/dockered-services && git clone https://git.pkirillw-server.ru/pkirillw/max-bot-test.git + mkdir -p '$SERVER_BASE' + cd '$SERVER_BASE' && git clone \$URL '$SERVICE' + : > /tmp/deploy_prev_$SERVICE fi" - - name: Create .env file - env: - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - MAX_BOT_API_SECRET: ${{ secrets.MAX_BOT_API_SECRET }} - WEBHOOK_URL: ${{ vars.WEBHOOK_URL }} - WEB_APP_URL: ${{ vars.WEB_APP_URL }} - DEBUG_CHAT_ID: ${{ vars.DEBUG_CHAT_ID }} - SELFTEST_CHAT_ID: ${{ vars.SELFTEST_CHAT_ID }} - run: | - ssh -i ~/.ssh/id_rsa -p ${{ vars.SERVER_PORT }} ${{ vars.SERVER_USER }}@${{ vars.SERVER_HOST }} "cat > /home/pkirillw/dockered-services/max-bot-test/.env << 'ENVEOF' - BOT_TOKEN=$BOT_TOKEN - MAX_BOT_API_SECRET=$MAX_BOT_API_SECRET - WEBHOOK_URL=$WEBHOOK_URL - WEB_APP_URL=$WEB_APP_URL - DEBUG_CHAT_ID=$DEBUG_CHAT_ID - SELFTEST_CHAT_ID=$SELFTEST_CHAT_ID - APP_ENV=prod - APP_DEBUG=false - ENVEOF" - - name: Build and restart + - name: Deploy run: | - ssh -i ~/.ssh/id_rsa -p ${{ vars.SERVER_PORT }} ${{ vars.SERVER_USER }}@${{ vars.SERVER_HOST }} " - cd /home/pkirillw/dockered-services/max-bot-test && \ - docker compose up -d --build && \ + if [ "$BUILD" = "true" ]; then CMD="docker compose up -d --build"; else CMD="docker compose pull && docker compose up -d"; fi + ssh -i ~/.ssh/id_rsa -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" " + set -e + cd '$SERVER_BASE/$SERVICE' + $CMD docker image prune -f" - - name: Subscribe webhook in MAX - env: - WEBHOOK_URL: ${{ vars.WEBHOOK_URL }} - run: | - if [ -z "$WEBHOOK_URL" ] || echo "$WEBHOOK_URL" | grep -q 'your-tunnel-host'; then - echo "WEBHOOK_URL not set, skipping subscription" - exit 0 - fi - ssh -i ~/.ssh/id_rsa -p ${{ vars.SERVER_PORT }} ${{ vars.SERVER_USER }}@${{ vars.SERVER_HOST }} " - cd /home/pkirillw/dockered-services/max-bot-test && \ - docker compose exec -T app bin/console webhook:subscribe --prune" - - name: Health check + if: ${{ env.HEALTHCHECK != '' }} run: | - ssh -i ~/.ssh/id_rsa -p ${{ vars.SERVER_PORT }} ${{ vars.SERVER_USER }}@${{ vars.SERVER_HOST }} " - sleep 5 && cd /home/pkirillw/dockered-services/max-bot-test && docker compose ps" + ok="" + for i in $(seq 1 5); do + if ssh -i ~/.ssh/id_rsa -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "curl -fsS -m 5 '$HEALTHCHECK' >/dev/null 2>&1"; then ok=1; break; fi + sleep 5 + done + [ -n "$ok" ] || { echo "::error::health-check не прошёл: $HEALTHCHECK"; exit 1; } + + - name: Rollback on failure + if: failure() + run: | + ssh -i ~/.ssh/id_rsa -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" " + PREV=\$(cat /tmp/deploy_prev_$SERVICE 2>/dev/null || true) + if [ -n \"\$PREV\" ]; then + echo 'Откат на '\$PREV + cd '$SERVER_BASE/$SERVICE' && git reset --hard \$PREV && docker compose up -d || true + fi" + + - name: Notify ntfy + if: always() + run: | + [ -n "$NTFY_URL" ] || exit 0 + if [ "${{ job.status }}" = "success" ]; then T="✅ $SERVICE задеплоен"; P=default; G=white_check_mark; else T="❌ $SERVICE: деплой упал"; P=high; G=rotating_light; fi + curl -fsS -H "Title: $T" -H "Priority: $P" -H "Tags: $G" -d "commit ${{ github.sha }}" "$NTFY_URL" || true