name: Gitea Actions - Terraform CI/CD run-name: ${{ gitea.actor }} is running Terraform CI/CD 🚀 on: pull_request: types: [opened, synchronize, reopened] branches: - main # Проверка PRs В main - dev # Проверка PRs В dev push: branches: - dev # При push в dev создаем PR в main - main # При push в main применяем изменения permissions: contents: write pull-requests: write jobs: terraform-ci: runs-on: code-runner00 env: GITEA_URL: "http://code.hlc.lab" # ⚠️ ЗАМЕНИТЕ на ваш URL GITEA_TOKEN: ${{ secrets.GITEATOKEN }} # Terraform переменные TF_IN_AUTOMATION: "true" TF_VAR_PVE_CLUSTER_API_ID: ${{ secrets.TF_VAR_PVE_CLUSTER_API_ID }} TF_VAR_PVE_CLUSTER_API_TOKEN: ${{ secrets.TF_VAR_PVE_CLUSTER_API_TOKEN }} TF_VAR_PVE_CLUSTER_URL: ${{ secrets.TF_VAR_PVE_CLUSTER_URL }} TF_VAR_POWERDNS_API_URL: ${{ secrets.TF_VAR_POWERDNS_API_URL }} TF_VAR_POWERDNS_API_TOKEN: ${{ secrets.TF_VAR_POWERDNS_API_TOKEN }} # AWS переменные (если используете) AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 # Для корректной работы с ветками - name: Create PR from dev to main if: github.event_name == 'push' && github.ref == 'refs/heads/dev' id: create-pr run: | echo "🔄 Создание Pull Request из dev в main..." # Проверяем, существует ли уже открытый PR EXISTING_PR=$(curl -s -H "Authorization: token $GITEA_TOKEN" \ "$GITEA_URL/api/v1/repos/${{ github.repository }}/pulls?state=open&base=main&head=dev" | jq length) if [ "$EXISTING_PR" -eq "0" ]; then # Создаем новый PR RESPONSE=$(curl -s -X POST \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"title\": \"[Auto] Merge dev → main - $(date +'%Y-%m-%d %H:%M')\", \"body\": \"Автоматически созданный PR из ветки dev.\\n\\n**Изменения:**\\n${{ github.event.head_commit.message }}\", \"head\": \"dev\", \"base\": \"main\", \"draft\": false }" \ "$GITEA_URL/api/v1/repos/${{ github.repository }}/pulls") PR_NUMBER=$(echo "$RESPONSE" | jq -r '.number // empty') if [ -n "$PR_NUMBER" ]; then echo "✅ PR создан: #$PR_NUMBER" echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT else echo "❌ Ошибка создания PR" echo "$RESPONSE" | jq . fi else echo "📝 PR уже существует, обновляем..." echo "pr_number=existing" >> $GITHUB_OUTPUT fi - name: Setup Terraform run: | # Проверяем установку Terraform terraform version echo "Terraform готов к работе" # 📋 Terraform проверки (выполняются всегда) - name: Terraform Format Check id: fmt run: | if terraform fmt -check -recursive; then echo "✅ Форматирование корректно" echo "fmt_status=passed" >> $GITHUB_OUTPUT else echo "⚠️ Найдены проблемы с форматированием" echo "fmt_status=failed" >> $GITHUB_OUTPUT fi continue-on-error: true - name: Terraform Init id: init run: terraform init - name: Terraform Validate id: validate run: terraform validate -no-color # 🗺️ Terraform Plan (для PR и push в dev) - name: Terraform Plan id: plan if: | github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/dev') run: | echo "📋 Генерация Terraform плана..." # Генерируем план terraform plan -no-color -out=tfplan 2>&1 | tee plan_output.txt # Проверяем наличие опасных изменений if grep -q "destroy and then create replacement" plan_output.txt; then echo "has_replace=true" >> $GITHUB_OUTPUT echo "replace_count=$(grep -c 'destroy and then create replacement' plan_output.txt)" >> $GITHUB_OUTPUT # Извлекаем имена ресурсов для замены grep -B1 "destroy and then create replacement" plan_output.txt | grep "# " | sed 's/^[[:space:]]*#[[:space:]]*//' > replace_resources.txt echo "replace_resources<> $GITHUB_OUTPUT cat replace_resources.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi if grep -q "^[[:space:]]*\- destroy" plan_output.txt; then echo "has_destroy=true" >> $GITHUB_OUTPUT echo "destroy_count=$(grep -c '^[[:space:]]*\- destroy' plan_output.txt)" >> $GITHUB_OUTPUT # Извлекаем имена ресурсов для удаления grep "^[[:space:]]*\- destroy" plan_output.txt -B1 | grep "# " | sed 's/^[[:space:]]*#[[:space:]]*//' > destroy_resources.txt echo "destroy_resources<> $GITHUB_OUTPUT cat destroy_resources.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi # Сохраняем полный вывод плана PLAN_CONTENT=$(cat plan_output.txt | jq -Rs .) echo "plan_content=$PLAN_CONTENT" >> $GITHUB_OUTPUT echo "✅ План сгенерирован" - name: Create Gitea PR Comment if: github.event_name == 'pull_request' env: PR_NUMBER: ${{ github.event.pull_request.number }} REPO_OWNER: ${{ github.repository_owner }} REPO_NAME: ${{ github.event.repository.name }} run: | echo "💬 Добавление комментария в PR #$PR_NUMBER..." # Проверяем, сгенерирован ли план if [ ! -f "plan_output.txt" ]; then echo "⚠️ Файл плана не найден, пропускаем комментарий" exit 0 fi # Создаем Markdown комментарий cat > comment.md << 'EOF' ## 🔧 Terraform Plan Report ### 📊 Проверки: EOF # Добавляем статусы echo "- **Format Check:** ${{ steps.fmt.outputs.fmt_status == 'passed' && '✅ passed' || '⚠️ failed' }}" >> comment.md echo "- **Validation:** ${{ steps.validate.outcome == 'success' && '✅ passed' || '❌ failed' }}" >> comment.md echo "- **Plan:** ${{ steps.plan.outcome == 'success' && '✅ generated' || '⚠️ issues' }}" >> comment.md # Предупреждения о деструктивных изменениях if [ "${{ steps.plan.outputs.has_replace }}" = "true" ]; then echo "" >> comment.md echo "### ⚠️ REPLACE OPERATIONS DETECTED!" >> comment.md echo "**${{ steps.plan.outputs.replace_count }}** ресурсов будут пересозданы:" >> comment.md echo '```' >> comment.md echo "${{ steps.plan.outputs.replace_resources }}" >> comment.md echo '```' >> comment.md fi if [ "${{ steps.plan.outputs.has_destroy }}" = "true" ]; then echo "" >> comment.md echo "### 🗑️ DESTROY OPERATIONS DETECTED!" >> comment.md echo "**${{ steps.plan.outputs.destroy_count }}** ресурсов будут удалены:" >> comment.md echo '```' >> comment.md echo "${{ steps.plan.outputs.destroy_resources }}" >> comment.md echo '```' >> comment.md fi # Полный план echo "" >> comment.md echo "
" >> comment.md echo "📄 Full Terraform Plan Output" >> comment.md echo "" >> comment.md echo '```terraform' >> comment.md cat plan_output.txt >> comment.md echo '```' >> comment.md echo "
" >> comment.md # Отправляем через Gitea API COMMENT_BODY=$(jq -n --arg body "$(cat comment.md)" '{"body": $body}') curl -X POST \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ -d "$COMMENT_BODY" \ "$GITEA_URL/api/v1/repos/${{ github.repository }}/issues/$PR_NUMBER/comments" echo "✅ Комментарий добавлен" - name: Block on Destructive Changes if: | github.event_name == 'pull_request' && (steps.plan.outputs.has_replace == 'true' || steps.plan.outputs.has_destroy == 'true') run: | echo "🚨 ОБНАРУЖЕНЫ ОПАСНЫЕ ИЗМЕНЕНИЯ!" echo "Этот PR содержит destroy/replace операции." echo "Требуется ручной review перед мержем." exit 1 - name: Terraform Apply if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | echo "🚀 Применение изменений в main..." if [ -f "tfplan" ]; then terraform apply -auto-approve tfplan else terraform apply -auto-approve fi echo "✅ Изменения применены"