BCards/.gitea/workflows/deploy-bcards.yml
Ricardo Carneiro ee4db7a910
Some checks failed
BCards Deployment Pipeline / Run Tests (push) Successful in 4s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 6m48s
BCards Deployment Pipeline / Deploy to Release Swarm (ARM) (push) Failing after 0s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 0s
fix: deploy de release
2025-09-22 08:05:53 -03:00

653 lines
25 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: BCards Deployment Pipeline
on:
push:
branches:
- main
- 'Release/*'
# PRs apenas validam, não fazem deploy
pull_request:
branches: [ main ]
types: [opened, synchronize, reopened]
env:
REGISTRY: registry.redecarneir.us
IMAGE_NAME: bcards
MONGODB_HOST: 192.168.0.100:27017
jobs:
test:
name: Run Tests
runs-on: ubuntu-latest
steps:
- name: Test info
run: |
echo "🧪 Executando testes para ${{ github.ref_name }}"
echo "🎯 Trigger: ${{ github.event_name }}"
# Verificar se deve pular testes
SKIP_TESTS="${{ github.event.inputs.skip_tests || vars.SKIP_TESTS }}"
if [ "$SKIP_TESTS" == "true" ]; then
echo "⚠️ Testes PULADOS"
echo "TESTS_SKIPPED=true" >> $GITHUB_ENV
else
echo "✅ Executando testes"
echo "TESTS_SKIPPED=false" >> $GITHUB_ENV
fi
- name: Checkout code
if: env.TESTS_SKIPPED == 'false'
uses: actions/checkout@v4
- name: Setup .NET 8
if: env.TESTS_SKIPPED == 'false'
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Cache dependencies
if: env.TESTS_SKIPPED == 'false'
uses: actions/cache@v3
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
if: env.TESTS_SKIPPED == 'false'
run: dotnet restore
- name: Build solution
if: env.TESTS_SKIPPED == 'false'
run: dotnet build --no-restore --configuration Release
- name: Run unit tests
if: env.TESTS_SKIPPED == 'false'
run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage"
# Job específico para validação de PRs (sem deploy)
pr-validation:
name: PR Validation
runs-on: ubuntu-latest
needs: [test]
if: github.event_name == 'pull_request'
steps:
- name: PR Validation Summary
run: |
echo "✅ Pull Request Validation Summary"
echo "🎯 Target Branch: ${{ github.base_ref }}"
echo "📂 Source Branch: ${{ github.head_ref }}"
echo "🧪 Tests: ${{ needs.test.result }}"
echo "👤 Author: ${{ github.event.pull_request.user.login }}"
echo "📝 Title: ${{ github.event.pull_request.title }}"
echo ""
echo "✨ PR está pronto para merge!"
build-and-push:
name: Build and Push Image
runs-on: [self-hosted, arm64, bcards]
needs: [test]
# Só faz build/push em push (não em PR)
if: github.event_name == 'push' && (needs.test.result == 'success' || needs.test.result == 'skipped')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/arm64
- name: Determine build settings
id: settings
run: |
BRANCH_NAME="${{ github.ref_name }}"
if [ "$BRANCH_NAME" = "main" ]; then
# Main = Produção (ARM64) - usando Dockerfile simples
echo "tag=latest" >> $GITHUB_OUTPUT
echo "platform=linux/arm64" >> $GITHUB_OUTPUT
echo "environment=Production" >> $GITHUB_OUTPUT
echo "dockerfile=Dockerfile" >> $GITHUB_OUTPUT
echo "deploy_target=production" >> $GITHUB_OUTPUT
elif [[ "$BRANCH_NAME" == Release/* ]]; then
# Release = Swarm tests (Orange Pi arm64) - usando Dockerfile simples também
VERSION_RAW=${BRANCH_NAME#Release/}
VERSION=$(echo "$VERSION_RAW" | sed 's/^[Vv]//')
[ -z "$VERSION" ] && VERSION="0.0.1"
echo "tag=$VERSION" >> $GITHUB_OUTPUT
echo "platform=linux/arm64" >> $GITHUB_OUTPUT
echo "environment=Testing" >> $GITHUB_OUTPUT
echo "dockerfile=Dockerfile" >> $GITHUB_OUTPUT
echo "deploy_target=testing" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
fi
COMMIT_SHA=${{ github.sha }}
SHORT_COMMIT=${COMMIT_SHA:0:7}
echo "commit=$SHORT_COMMIT" >> $GITHUB_OUTPUT
echo "📦 Tag: ${{ steps.settings.outputs.tag }}"
echo "🏗️ Platform: ${{ steps.settings.outputs.platform }}"
echo "🌍 Environment: ${{ steps.settings.outputs.environment }}"
echo "🎯 Target: ${{ steps.settings.outputs.deploy_target }}"
- name: Build and push image
run: |
echo "🏗️ Building image for ${{ steps.settings.outputs.deploy_target }}..."
# Debug das variáveis
echo "Platform: ${{ steps.settings.outputs.platform }}"
echo "Dockerfile: ${{ steps.settings.outputs.dockerfile }}"
echo "Tag: ${{ steps.settings.outputs.tag }}"
# Verificar se o Dockerfile existe
if [ ! -f "${{ steps.settings.outputs.dockerfile }}" ]; then
echo "❌ Dockerfile não encontrado: ${{ steps.settings.outputs.dockerfile }}"
echo "📂 Arquivos na raiz:"
ls -la
echo "📂 Arquivos em src/BCards.Web/:"
ls -la src/BCards.Web/ || echo "Diretório não existe"
exit 1
else
echo "✅ Dockerfile encontrado: ${{ steps.settings.outputs.dockerfile }}"
fi
# Build para a plataforma correta
if [ "${{ steps.settings.outputs.deploy_target }}" = "production" ]; then
# Build para produção (main branch)
docker buildx build \
--platform ${{ steps.settings.outputs.platform }} \
--file ${{ steps.settings.outputs.dockerfile }} \
--tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.settings.outputs.tag }} \
--push \
--progress=plain \
.
else
# Build para staging (Release branches)
docker buildx build \
--platform ${{ steps.settings.outputs.platform }} \
--file ${{ steps.settings.outputs.dockerfile }} \
--tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.settings.outputs.tag }} \
--push \
--build-arg VERSION=${{ steps.settings.outputs.version || 'latest' }} \
--build-arg COMMIT=${{ steps.settings.outputs.commit }} \
--progress=plain \
.
fi
deploy-production:
name: Deploy to Production (ARM - OCI)
runs-on: ubuntu-latest
needs: [build-and-push]
if: github.ref_name == 'main'
environment: production
steps:
- name: Create Production Configuration
run: |
echo "🔧 Creating appsettings.Production.json with environment variables..."
# Cria o arquivo de configuração para produção
cat > appsettings.Production.json << 'CONFIG_EOF'
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"BCards": "Information",
"BCards.Web.Services.GridFSImageStorage": "Debug"
},
"Console": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Information"
}
},
"File": {
"Path": "/app/logs/bcards-{Date}.log",
"LogLevel": {
"Default": "Information"
}
}
},
"AllowedHosts": "*",
"Stripe": {
"PublishableKey": "${{ vars.STRIPE_PUBLISHABLE_KEY }}",
"SecretKey": "${{ secrets.STRIPE_SECRET_KEY }}",
"WebhookSecret": "${{ secrets.STRIPE_WEBHOOK_SECRET }}",
"Environment": "${{ vars.STRIPE_ENVIRONMENT || 'test' }}"
},
"Authentication": {
"Google": {
"ClientId": "${{ vars.GOOGLE_CLIENT_ID }}",
"ClientSecret": "${{ secrets.GOOGLE_CLIENT_SECRET }}"
},
"Microsoft": {
"ClientId": "${{ vars.MICROSOFT_CLIENT_ID }}",
"ClientSecret": "${{ secrets.MICROSOFT_CLIENT_SECRET }}"
}
},
"SendGrid": {
"ApiKey": "${{ secrets.SENDGRID_API_KEY }}",
"FromEmail": "${{ vars.SENDGRID_FROM_EMAIL || 'ricardo.carneiro@jobmaker.com.br' }}",
"FromName": "${{ vars.SENDGRID_FROM_NAME || 'Ricardo Carneiro' }}"
},
"Plans": {
"Basic": {
"Name": "Básico",
"PriceId": "price_1RycPaBMIadsOxJVKioZZofK",
"Price": 5.90,
"MaxPages": 3,
"MaxLinks": 8,
"AllowPremiumThemes": false,
"AllowProductLinks": false,
"AllowAnalytics": true,
"Features": [ "URL Personalizada", "20 temas básicos", "Analytics simples" ],
"Interval": "month"
},
"Professional": {
"Name": "Profissional",
"PriceId": "price_1RycQmBMIadsOxJVGqjVMaOj",
"Price": 12.90,
"MaxPages": 5,
"MaxLinks": 20,
"AllowPremiumThemes": false,
"AllowProductLinks": false,
"AllowAnalytics": true,
"Features": [ "URL Personalizada", "20 temas básicos", "Analytics avançado" ],
"Interval": "month"
},
"Premium": {
"Name": "Premium",
"PriceId": "price_1RycRUBMIadsOxJVkxGOh3uu",
"Price": 19.90,
"MaxPages": 15,
"MaxLinks": -1,
"AllowPremiumThemes": true,
"AllowProductLinks": false,
"AllowAnalytics": true,
"SpecialModeration": false,
"Features": [ "URL Personalizada", "40 temas (básicos + premium)", "Suporte prioritário", "Links ilimitados" ],
"Interval": "month"
},
"PremiumAffiliate": {
"Name": "Premium+Afiliados",
"PriceId": "price_1RycTaBMIadsOxJVeDLseXQq",
"Price": 29.90,
"MaxPages": 15,
"MaxLinks": -1,
"AllowPremiumThemes": true,
"AllowProductLinks": true,
"AllowAnalytics": true,
"SpecialModeration": true,
"Features": [ "Tudo do Premium", "Links de produto", "Moderação especial", "Até 10 links afiliados" ],
"Interval": "month"
},
"BasicYearly": {
"Name": "Básico Anual",
"PriceId": "price_1RycWgBMIadsOxJVGdtEeoMS",
"Price": 59.00,
"MaxPages": 3,
"MaxLinks": 8,
"AllowPremiumThemes": false,
"AllowProductLinks": false,
"AllowAnalytics": true,
"Features": [ "URL Personalizada", "20 temas básicos", "Analytics simples", "Economize R$ 11,80 (2 meses grátis)" ],
"Interval": "year"
},
"ProfessionalYearly": {
"Name": "Profissional Anual",
"PriceId": "price_1RycXdBMIadsOxJV5cNX7dHm",
"Price": 129.00,
"MaxPages": 5,
"MaxLinks": 20,
"AllowPremiumThemes": false,
"AllowProductLinks": false,
"AllowAnalytics": true,
"Features": [ "URL Personalizada", "20 temas básicos", "Analytics avançado", "Economize R$ 25,80 (2 meses grátis)" ],
"Interval": "year"
},
"PremiumYearly": {
"Name": "Premium Anual",
"PriceId": "price_1RycYnBMIadsOxJVPdKmzy4m",
"Price": 199.00,
"MaxPages": 15,
"MaxLinks": -1,
"AllowPremiumThemes": true,
"AllowProductLinks": false,
"AllowAnalytics": true,
"SpecialModeration": false,
"Features": [ "URL Personalizada", "40 temas (básicos + premium)", "Suporte prioritário", "Links ilimitados", "Economize R$ 39,80 (2 meses grátis)" ],
"Interval": "year"
},
"PremiumAffiliateYearly": {
"Name": "Premium+Afiliados Anual",
"PriceId": "price_1RycaEBMIadsOxJVEhsdB2Y1",
"Price": 299.00,
"MaxPages": 15,
"MaxLinks": -1,
"AllowPremiumThemes": true,
"AllowProductLinks": true,
"AllowAnalytics": true,
"SpecialModeration": true,
"Features": [ "Tudo do Premium", "Links de produto", "Moderação especial", "Até 10 links afiliados", "Economize R$ 59,80 (2 meses grátis)" ],
"Interval": "year"
}
},
"Moderation": {
"PriorityTimeframes": {
"Trial": "7.00:00:00",
"Basic": "7.00:00:00",
"Professional": "3.00:00:00",
"Premium": "1.00:00:00"
},
"MaxAttempts": 3,
"ModeratorEmail": "${{ vars.MODERATOR_EMAIL || 'ricardo.carneiro@jobmaker.com.br' }}",
"ModeratorEmails": [
"${{ vars.MODERATOR_EMAIL_1 || 'rrcgoncalves@gmail.com' }}",
"${{ vars.MODERATOR_EMAIL_2 || 'rirocarneiro@gmail.com' }}"
]
},
"MongoDb": {
"ConnectionString": "mongodb://admin:c4rn31r0@129.146.116.218:27017,141.148.162.114:27017/BCardsDB?replicaSet=rs0&authSource=admin",
"DatabaseName": "BCardsDB",
"MaxConnectionPoolSize": 100,
"ConnectTimeout": "30s",
"ServerSelectionTimeout": "30s",
"SocketTimeout": "30s"
},
"BaseUrl": "https://bcards.site",
"Environment": {
"Name": "Production",
"IsStagingEnvironment": false,
"AllowTestData": false,
"EnableDetailedErrors": false
},
"Performance": {
"EnableCaching": true,
"CacheExpirationMinutes": 30,
"EnableCompression": true,
"EnableResponseCaching": true
},
"Security": {
"EnableHttpsRedirection": true,
"EnableHsts": true,
"RequireHttpsMetadata": true
},
"HealthChecks": {
"Enabled": true,
"Endpoints": {
"Health": "/health",
"Ready": "/ready",
"Live": "/live"
},
"MongoDb": {
"Enabled": true,
"Timeout": "10s"
}
},
"Features": {
"EnablePreviewMode": true,
"EnableModerationWorkflow": true,
"EnableAnalytics": true,
"EnableFileUploads": true,
"MaxFileUploadSize": "5MB"
},
"Serilog": {
"OpenSearchUrl": "${{ vars.OPENSEARCH_URL || 'http://localhost:9201' }}"
}
}
CONFIG_EOF
echo "✅ Configuration file created!"
echo "🔍 File content (sensitive data masked):"
cat appsettings.Production.json | sed 's/"[^"]*_[0-9A-Za-z_]*"/"***MASKED***"/g'
- name: Deploy to Production Servers
run: |
echo "🚀 Deploying to production servers (ARM64)..."
# Configura SSH (igual ao QRRapido)
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# Adiciona hosts conhecidos
ssh-keyscan -H 141.148.162.114 >> ~/.ssh/known_hosts
ssh-keyscan -H 129.146.116.218 >> ~/.ssh/known_hosts
# Testa a chave SSH
ssh-add ~/.ssh/id_rsa 2>/dev/null || echo "SSH key loaded"
# Upload configuration file to Server 1
echo "📤 Uploading configuration to Server 1..."
scp -o StrictHostKeyChecking=no appsettings.Production.json ubuntu@141.148.162.114:/tmp/
# Deploy no Servidor 1 (ARM - OCI)
ssh -o StrictHostKeyChecking=no ubuntu@141.148.162.114 << 'EOF'
echo "🔄 Atualizando Servidor 1..."
# Create app config directory
mkdir -p /home/ubuntu/bcards-config
mv /tmp/appsettings.Production.json /home/ubuntu/bcards-config/
# Remove containers bcards-infrastructure se existirem
docker stop bcards-infrastructure bcards-test-app || true
docker rm bcards-infrastructure bcards-test-app || true
# Para o container BCards atual se existir
docker stop bcards-prod || true
docker rm bcards-prod || true
# Remove imagem antiga
docker rmi ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest || true
# Puxa nova imagem
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Executa novo container BCards
docker run -d \
--name bcards-prod \
--restart unless-stopped \
--network host \
-e ASPNETCORE_ENVIRONMENT=Production \
-e ASPNETCORE_URLS=http://+:8080 \
-e MongoDb__ConnectionString="mongodb://admin:c4rn31r0@129.146.116.218:27017,141.148.162.114:27017/BCardsDB?replicaSet=rs0&authSource=admin" \
-e MongoDb__DatabaseName="BCardsDB" \
-e Logging__LogLevel__Default=Debug \
-e Serilog__OpenSearchUrl="http://localhost:9201" \
-v /home/ubuntu/bcards-config/appsettings.Production.json:/app/appsettings.Production.json:ro \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Debug: verificar configuração aplicada
echo "🔍 Verificando configuração MongoDB no container..."
docker logs bcards-prod | head -20 || echo "Container ainda iniciando..."
# Recarrega NGINX
sudo nginx -t && sudo systemctl reload nginx
echo "✅ Servidor 1 atualizado"
EOF
# Upload configuration file to Server 2
echo "📤 Uploading configuration to Server 2..."
scp -o StrictHostKeyChecking=no appsettings.Production.json ubuntu@129.146.116.218:/tmp/
# Deploy no Servidor 2 (ARM - OCI)
ssh -o StrictHostKeyChecking=no ubuntu@129.146.116.218 << 'EOF'
echo "🔄 Atualizando Servidor 2..."
# Create app config directory
mkdir -p /home/ubuntu/bcards-config
mv /tmp/appsettings.Production.json /home/ubuntu/bcards-config/
# Remove containers bcards-infrastructure se existirem
docker stop bcards-infrastructure bcards-test-app || true
docker rm bcards-infrastructure bcards-test-app || true
# Para o container BCards atual se existir
docker stop bcards-prod || true
docker rm bcards-prod || true
# Remove imagem antiga
docker rmi ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest || true
# Puxa nova imagem
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Executa novo container BCards
docker run -d \
--name bcards-prod \
--restart unless-stopped \
--network host \
-e ASPNETCORE_ENVIRONMENT=Production \
-e ASPNETCORE_URLS=http://+:8080 \
-e MongoDb__ConnectionString="mongodb://admin:c4rn31r0@129.146.116.218:27017,141.148.162.114:27017/BCardsDB?replicaSet=rs0&authSource=admin" \
-e MongoDb__DatabaseName="BCardsDB" \
-e Logging__LogLevel__Default=Debug \
-e Serilog__OpenSearchUrl="http://localhost:9202" \
-v /home/ubuntu/bcards-config/appsettings.Production.json:/app/appsettings.Production.json:ro \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Debug: verificar configuração aplicada
echo "🔍 Verificando configuração MongoDB no container..."
docker logs bcards-prod | head -20 || echo "Container ainda iniciando..."
echo "✅ Servidor 2 atualizado"
EOF
- name: Health Check Production
run: |
echo "🏥 Verificando saúde dos servidores de produção..."
sleep 30
# Verifica Servidor 1
echo "Verificando Servidor 1 (ARM)..."
ssh -o StrictHostKeyChecking=no ubuntu@141.148.162.114 'curl -f http://localhost:8080/health || echo "⚠️ Servidor 1 pode não estar respondendo"'
# Verifica Servidor 2
echo "Verificando Servidor 2 (ARM)..."
ssh -o StrictHostKeyChecking=no ubuntu@129.146.116.218 'curl -f http://localhost:8080/health || echo "⚠️ Servidor 2 pode não estar respondendo"'
deploy-test:
name: Deploy to Release Swarm (ARM)
runs-on: [self-hosted, arm64, bcards]
needs: [build-and-push]
if: startsWith(github.ref_name, 'Release/')
steps:
- name: Extract version
id: version
run: |
BRANCH_NAME="${{ github.ref_name }}"
VERSION_RAW=${BRANCH_NAME#Release/}
VERSION=$(echo "$VERSION_RAW" | sed 's/^[Vv]//')
[ -z "$VERSION" ] && VERSION="0.0.1"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "📦 Deploying version: $VERSION"
- name: Prepare release stack manifest
run: |
mkdir -p artifacts
export BCARDS_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}
envsubst '$BCARDS_IMAGE' < deploy/docker-stack.release.yml > artifacts/docker-stack.release.yml
- name: Deploy to release swarm
run: |
echo "🚀 Deploying release stack to Orange Pi swarm..."
docker stack deploy -c artifacts/docker-stack.release.yml bcards-release
- name: Await release service readiness
run: |
echo "⏳ Aguardando serviço bcards-release estabilizar..."
ATTEMPTS=30
while [ $ATTEMPTS -gt 0 ]; do
REPLICAS=$(docker service ls --filter name=bcards-release_bcards-release --format '{{.Replicas}}')
if [ "$REPLICAS" = "2/2" ]; then
echo "✅ Serviço com $REPLICAS réplicas"
break
fi
echo "Atual: ${REPLICAS:-N/A}; aguardando..."
sleep 5
ATTEMPTS=$((ATTEMPTS-1))
done
if [ "$REPLICAS" != "2/2" ]; then
echo "❌ Serviço não atingiu 2/2 réplicas"
docker service ps bcards-release_bcards-release
exit 1
fi
docker service ps bcards-release_bcards-release
cleanup:
name: Cleanup Old Resources
runs-on: ubuntu-latest
needs: [deploy-production, deploy-test]
if: always() && (needs.deploy-production.result == 'success' || needs.deploy-test.result == 'success')
steps:
- name: Cleanup containers and images
run: |
echo "🧹 Limpando recursos antigos..."
if [ "${{ github.ref_name }}" = "main" ]; then
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H 141.148.162.114 >> ~/.ssh/known_hosts
ssh-keyscan -H 129.146.116.218 >> ~/.ssh/known_hosts
ssh-add ~/.ssh/id_rsa 2>/dev/null || echo "SSH key loaded"
for server in 141.148.162.114 129.146.116.218; do
echo "🧹 Limpando servidor $server..."
ssh -o StrictHostKeyChecking=no ubuntu@$server << 'EOF'
docker container prune -f
docker image prune -f
docker network prune -f
EOF
done
else
echo " Release branch: limpeza remota ignorada (Swarm gerencia recursos)."
fi
echo "✅ Limpeza concluída!"
deployment-summary:
name: Deployment Summary
runs-on: ubuntu-latest
needs: [deploy-production, deploy-test]
if: always()
steps:
- name: Summary
run: |
echo "📋 DEPLOYMENT SUMMARY"
echo "===================="
echo "🎯 Branch: ${{ github.ref_name }}"
echo "🔑 Commit: ${{ github.sha }}"
echo "🏗️ Registry: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
if [ "${{ github.ref_name }}" = "main" ]; then
echo "🌍 Environment: Production (Swarm ARM)"
echo "🖥️ Servers: 141.148.162.114, 129.146.116.218"
echo "📦 Tag: latest"
echo "🔗 Status: ${{ needs.deploy-production.result }}"
else
echo "🌍 Environment: Release (Swarm ARM)"
echo "🖥️ Servers: 141.148.162.114, 129.146.116.218"
echo "📦 Branch Tag: ${{ github.ref_name }}"
echo "🔗 Status: ${{ needs.deploy-test.result }}"
fi
echo "===================="
echo "✅ Pipeline completed!"