diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 2ed84fa..0ffc967 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -19,7 +19,8 @@ "Bash(curl:*)", "Bash(docker-compose up:*)", "Bash(dotnet build:*)", - "Bash(chmod:*)" + "Bash(chmod:*)", + "Bash(mv:*)" ] }, "enableAllProjectMcpServers": false diff --git a/.gitea/workflows/deploy-bcards.yml b/.gitea/workflows/deploy-bcards.yml new file mode 100644 index 0000000..fc2f60c --- /dev/null +++ b/.gitea/workflows/deploy-bcards.yml @@ -0,0 +1,359 @@ +name: BCards Deployment Pipeline + +on: + push: + branches: + - main + - 'Release/*' + pull_request: + branches: [ main ] + +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" + + build-and-push: + name: Build and Push Image + runs-on: ubuntu-latest + needs: [test] + if: always() && (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/amd64,linux/arm64 + + - name: Determine build settings + id: settings + run: | + BRANCH_NAME="${{ github.ref_name }}" + + if [ "$BRANCH_NAME" = "main" ]; then + # Main = Produção (ARM64) + 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 = Staging (x86) + 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/amd64" >> $GITHUB_OUTPUT + echo "environment=Staging" >> $GITHUB_OUTPUT + echo "dockerfile=Dockerfile.release" >> $GITHUB_OUTPUT + echo "deploy_target=staging" >> $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: $(echo '${{ steps.settings.outputs.tag }}')" + echo "🏗️ Platform: $(echo '${{ steps.settings.outputs.platform }}')" + echo "🌍 Environment: $(echo '${{ steps.settings.outputs.environment }}')" + echo "🎯 Target: $(echo '${{ steps.settings.outputs.deploy_target }}')" + + - name: Build and push image + run: | + echo "🏗️ Building image for ${{ steps.settings.outputs.deploy_target }}..." + + # Build para a plataforma correta + docker buildx build \ + --platform ${{ steps.settings.outputs.platform }} \ + --file ${{ steps.settings.outputs.dockerfile }} \ + --tag $REGISTRY/$IMAGE_NAME:${{ steps.settings.outputs.tag }} \ + --push \ + --build-arg VERSION=${{ steps.settings.outputs.version || 'latest' }} \ + --build-arg COMMIT=${{ steps.settings.outputs.commit }} \ + --progress=plain \ + . + + 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: Deploy to Production Servers + run: | + echo "🚀 Deploying to production servers (ARM64)..." + + # Configura SSH + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + + # Deploy no Servidor 1 (ARM - OCI) + ssh -o StrictHostKeyChecking=no ubuntu@141.148.162.114 << 'EOF' + echo "🔄 Atualizando Servidor 1..." + + # 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 \ + -p 5002:8080 \ + -e ASPNETCORE_ENVIRONMENT=Production \ + -e ASPNETCORE_URLS=http://+:8080 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + # Recarrega NGINX + sudo nginx -t && sudo systemctl reload nginx + + echo "✅ Servidor 1 atualizado" + EOF + + # Deploy no Servidor 2 (ARM - OCI) + ssh -o StrictHostKeyChecking=no ubuntu@129.146.116.218 << 'EOF' + echo "🔄 Atualizando Servidor 2..." + + # 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 \ + -p 5002:8080 \ + -e ASPNETCORE_ENVIRONMENT=Production \ + -e ASPNETCORE_URLS=http://+:8080 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + 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:5002/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:5002/health || echo "⚠️ Servidor 2 pode não estar respondendo"' + + deploy-staging: + name: Deploy to Staging (x86 - Local) + runs-on: ubuntu-latest + 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: Deploy to Staging Server + run: | + echo "🚀 Deploying to staging server (x86)..." + + # Configura SSH + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + + # Deploy no Servidor Local x86 + ssh -o StrictHostKeyChecking=no ubuntu@192.168.0.100 << EOF + echo "🔄 Atualizando Servidor Staging..." + + # 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-staging || true + docker rm bcards-staging || true + + # Remove imagem antiga + docker rmi ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }} || true + + # Puxa nova imagem + docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }} + + # Executa novo container BCards + docker run -d \ + --name bcards-staging \ + --restart unless-stopped \ + -p 5002:8080 \ + -e ASPNETCORE_ENVIRONMENT=Staging \ + -e ASPNETCORE_URLS=http://+:8080 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }} + + echo "✅ Servidor Staging atualizado" + EOF + + - name: Health Check Staging + run: | + echo "🏥 Verificando saúde do servidor de staging..." + sleep 30 + + echo "Verificando Servidor Staging (x86)..." + ssh -o StrictHostKeyChecking=no ubuntu@192.168.0.100 'curl -f http://localhost:5002/health || echo "⚠️ Servidor staging pode não estar respondendo"' + + cleanup: + name: Cleanup Old Resources + runs-on: ubuntu-latest + needs: [deploy-production, deploy-staging] + if: always() && (needs.deploy-production.result == 'success' || needs.deploy-staging.result == 'success') + + steps: + - name: Cleanup containers and images + run: | + echo "🧹 Limpando recursos antigos..." + + # Configura SSH + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + + # Lista de servidores baseada na branch + if [ "${{ github.ref_name }}" = "main" ]; then + SERVERS=("141.148.162.114" "129.146.116.218") + else + SERVERS=("192.168.0.100") + fi + + # Limpeza em cada servidor + for server in "${SERVERS[@]}"; do + echo "🧹 Limpando servidor $server..." + ssh -o StrictHostKeyChecking=no ubuntu@$server << 'EOF' + # Remove containers parados + docker container prune -f + + # Remove imagens não utilizadas + docker image prune -f + + # Remove redes não utilizadas + docker network prune -f + EOF + done + + echo "✅ Limpeza concluída!" + + deployment-summary: + name: Deployment Summary + runs-on: ubuntu-latest + needs: [deploy-production, deploy-staging] + 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 (ARM64)" + echo "🖥️ Servers: 141.148.162.114, 129.146.116.218" + echo "📦 Tag: latest" + echo "🔗 Status: ${{ needs.deploy-production.result }}" + else + echo "🌍 Environment: Staging (x86)" + echo "🖥️ Server: 192.168.0.100" + echo "📦 Tag: ${{ github.ref_name }}" + echo "🔗 Status: ${{ needs.deploy-staging.result }}" + fi + + echo "====================" + echo "✅ Pipeline completed!" \ No newline at end of file diff --git a/.gitea/workflows/pr-validation.yml b/.gitea/workflows/pr-validation.yml.backup similarity index 100% rename from .gitea/workflows/pr-validation.yml rename to .gitea/workflows/pr-validation.yml.backup diff --git a/.gitea/workflows/release-deploy.yml b/.gitea/workflows/release-deploy.yml.backup similarity index 100% rename from .gitea/workflows/release-deploy.yml rename to .gitea/workflows/release-deploy.yml.backup diff --git a/.github/workflows/deploy-bcards.yml b/.github/workflows/deploy-bcards.yml deleted file mode 100644 index c7699a5..0000000 --- a/.github/workflows/deploy-bcards.yml +++ /dev/null @@ -1,254 +0,0 @@ -name: Deploy BCards -on: - push: - branches: [ main, 'release/*' ] - pull_request: - branches: [ main ] - -env: - REGISTRY: registry.redecarneir.us - IMAGE_NAME: bcards - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.x - - - name: Cache dependencies - uses: actions/cache@v3 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} - restore-keys: | - ${{ runner.os }}-nuget- - - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build --no-restore --configuration Release - - - name: Test - run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" - - - name: Upload coverage - uses: codecov/codecov-action@v3 - with: - files: coverage.cobertura.xml - - build-and-push: - needs: test - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Determine build settings - run: | - if [ "${{ github.ref }}" = "refs/heads/main" ]; then - echo "TAG=latest" >> $GITHUB_ENV - echo "PLATFORM=linux/arm64" >> $GITHUB_ENV - echo "ENVIRONMENT=Production" >> $GITHUB_ENV - elif [[ "${{ github.ref }}" == refs/heads/release/* ]]; then - # Extrai versão da branch (release/v1.0.0 -> v1.0.0) - VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/heads\/release\///') - echo "TAG=${VERSION}" >> $GITHUB_ENV - echo "PLATFORM=linux/amd64" >> $GITHUB_ENV - echo "ENVIRONMENT=Staging" >> $GITHUB_ENV - fi - - echo "IMAGE_TAG=$TAG" >> $GITHUB_ENV - - - name: Build and push to registry - run: | - # Build da imagem para a plataforma correta - docker buildx build \ - --platform ${{ env.PLATFORM }} \ - --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} \ - --push \ - . - - deploy-production: - needs: build-and-push - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' - environment: production - - steps: - - name: Deploy to Production Servers (ARM - OCI) - run: | - # Configura SSH - mkdir -p ~/.ssh - echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # Deploy no Servidor 1 (ARM - OCI) - ssh -o StrictHostKeyChecking=no ubuntu@141.148.162.114 << 'EOF' - # Remove containers bcards-infrastructure se existirem - docker stop bcards-infrastructure || true - docker rm bcards-infrastructure || true - docker stop bcards-test-app || true - docker rm 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 \ - -p 5002:8080 \ - -e ASPNETCORE_ENVIRONMENT=Production \ - -e ASPNETCORE_URLS=http://+:8080 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - - # Recarrega NGINX - sudo nginx -t && sudo systemctl reload nginx - EOF - - # Deploy no Servidor 2 (ARM - OCI) - ssh -o StrictHostKeyChecking=no ubuntu@129.146.116.218 << 'EOF' - # Remove containers bcards-infrastructure se existirem - docker stop bcards-infrastructure || true - docker rm bcards-infrastructure || true - docker stop bcards-test-app || true - docker rm 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 \ - -p 5002:8080 \ - -e ASPNETCORE_ENVIRONMENT=Production \ - -e ASPNETCORE_URLS=http://+:8080 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - EOF - - - name: Health Check Production - run: | - # Aguarda containers subirem - sleep 30 - - # Verifica se os serviços estão respondendo - echo "Verificando Servidor 1 (ARM)..." - ssh -o StrictHostKeyChecking=no ubuntu@141.148.162.114 'curl -f http://localhost:5002/health || echo "Servidor 1 pode não estar respondendo"' - - echo "Verificando Servidor 2 (ARM)..." - ssh -o StrictHostKeyChecking=no ubuntu@129.146.116.218 'curl -f http://localhost:5002/health || echo "Servidor 2 pode não estar respondendo"' - - deploy-staging: - needs: build-and-push - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/heads/release/') - - steps: - - name: Deploy to Staging Server (x86 - Local) - run: | - # Configura SSH - mkdir -p ~/.ssh - echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # Extrai versão da branch - VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/heads\/release\///') - - # Deploy no Servidor Local x86 - ssh -o StrictHostKeyChecking=no ubuntu@192.168.0.100 << EOF - # Remove containers bcards-infrastructure se existirem - docker stop bcards-infrastructure || true - docker rm bcards-infrastructure || true - docker stop bcards-test-app || true - docker rm bcards-test-app || true - - # Para o container BCards atual se existir - docker stop bcards-staging || true - docker rm bcards-staging || true - - # Remove imagem antiga - docker rmi ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION} || true - - # Puxa nova imagem - docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION} - - # Executa novo container BCards - docker run -d \ - --name bcards-staging \ - --restart unless-stopped \ - -p 5002:8080 \ - -e ASPNETCORE_ENVIRONMENT=Staging \ - -e ASPNETCORE_URLS=http://+:8080 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION} - EOF - - - name: Health Check Staging - run: | - # Aguarda container subir - sleep 30 - - # Verifica se o serviço está respondendo - echo "Verificando Servidor Staging (x86)..." - ssh -o StrictHostKeyChecking=no ubuntu@192.168.0.100 'curl -f http://localhost:5002/health || echo "Servidor staging pode não estar respondendo"' - - cleanup: - needs: [deploy-production, deploy-staging] - runs-on: ubuntu-latest - if: always() && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) - - steps: - - name: Cleanup old containers and images - run: | - # Configura SSH - mkdir -p ~/.ssh - echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # Lista de servidores baseada na branch - if [ "${{ github.ref }}" = "refs/heads/main" ]; then - SERVERS=("141.148.162.114" "129.146.116.218") - else - SERVERS=("192.168.0.100") - fi - - # Limpeza em cada servidor - for server in "${SERVERS[@]}"; do - echo "Limpando servidor $server..." - ssh -o StrictHostKeyChecking=no ubuntu@$server << 'EOF' - # Remove containers parados - docker container prune -f - - # Remove imagens não utilizadas (mantém as mais recentes) - docker image prune -f - - # Remove redes não utilizadas - docker network prune -f - EOF - done \ No newline at end of file