diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index 4ad7a9e..e8e88b5 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -1,4 +1,4 @@ -name: Test and Deploy to k3s +name: CI/CD Pipeline on: push: @@ -12,32 +12,22 @@ env: DOMAIN: "academia.ingeniumcodex.com" jobs: + # Job 1: Build y Test (obligatorio) test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: "10.0.x" + - name: Restore & Build + run: dotnet build --configuration Release --verbosity minimal - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build --no-restore - - - name: Run Unit Tests - run: dotnet test tests/Domain.Tests --no-build --verbosity normal - - - name: Run Application Tests - run: dotnet test tests/Application.Tests --no-build --verbosity normal - - - name: Run Integration Tests - run: dotnet test tests/Integration.Tests --no-build --verbosity normal + - name: Run Tests + run: | + dotnet test tests/Domain.Tests --no-build -c Release --verbosity minimal + dotnet test tests/Application.Tests --no-build -c Release --verbosity minimal + # Job 2: Deploy (siempre después de tests) deploy: runs-on: ubuntu-latest needs: test @@ -52,23 +42,17 @@ jobs: chmod 600 ~/.ssh/id_rsa ssh-keyscan -H ${{ env.K3S_HOST }} >> ~/.ssh/known_hosts 2>/dev/null - - name: Sync code to k3s - run: | - rsync -az --delete \ - --exclude '.git' \ - --exclude 'node_modules' \ - --exclude 'dist' \ - --exclude 'bin' \ - --exclude 'obj' \ - --exclude '.angular' \ - ./ ${{ env.K3S_USER }}@${{ env.K3S_HOST }}:~/academia/ - - - name: Build images (parallel) + - name: Deploy to K3s run: | ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} << 'ENDSSH' + set -e cd ~/academia - export DOCKER_BUILDKIT=1 + # Pull latest changes + git fetch origin main + git reset --hard origin/main + + # Build images echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S docker build \ -f deploy/docker/Dockerfile.api -t student-api:latest . & PID_API=$! @@ -79,55 +63,80 @@ jobs: wait $PID_API || exit 1 wait $PID_FE || exit 1 - ENDSSH - - name: Import to k3s - run: | - ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} << 'ENDSSH' + # Import to k3s echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S sh -c \ 'docker save student-api:latest | k3s ctr images import -' echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S sh -c \ 'docker save student-frontend:latest | k3s ctr images import -' - ENDSSH - - name: Setup namespace if needed - run: | - ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} << 'ENDSSH' - cd ~/academia/deploy/k3s - if ! echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl get ns academia &>/dev/null; then - echo "Creating namespace and resources..." - echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl apply -k . - fi - ENDSSH - - - name: Deploy - run: | - ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} << 'ENDSSH' - cd ~/academia/deploy/k3s - echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl apply -k . + # Deploy + echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl apply -k deploy/k3s/ echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl rollout restart \ deployment/student-api deployment/student-frontend -n academia - ENDSSH - - name: Wait rollout - run: | - ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} << 'ENDSSH' + # Wait for rollout echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl rollout status \ - deployment/student-api -n academia --timeout=120s + deployment/student-api -n academia --timeout=180s echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl rollout status \ deployment/student-frontend -n academia --timeout=60s ENDSSH - - name: Health check - run: | - sleep 10 - curl -sf https://${{ env.DOMAIN }}/health || exit 1 - curl -sf https://${{ env.DOMAIN }}/ || exit 1 + # Job 3: Smoke Tests en Producción + smoke-tests: + runs-on: ubuntu-latest + needs: deploy + steps: + - name: Wait for services + run: sleep 15 - - name: Rollback on failure - if: failure() + - name: Health Check API + run: | + response=$(curl -sf https://${{ env.DOMAIN }}/health) + echo "Health response: $response" + echo "$response" | grep -q '"status":"Healthy"' || exit 1 + + - name: Health Check Frontend + run: | + curl -sf https://${{ env.DOMAIN }}/ | grep -q 'Sistema de Estudiantes' || exit 1 + + - name: GraphQL Endpoint Check + run: | + response=$(curl -sf -X POST https://${{ env.DOMAIN }}/graphql \ + -H "Content-Type: application/json" \ + -d '{"query":"{ __typename }"}') + echo "GraphQL response: $response" + echo "$response" | grep -q '"data"' || exit 1 + + - name: Database Connectivity Check + run: | + response=$(curl -sf https://${{ env.DOMAIN }}/health) + echo "$response" | grep -q '"name":"database","status":"Healthy"' || exit 1 + + - name: Subjects Query Test + run: | + response=$(curl -sf -X POST https://${{ env.DOMAIN }}/graphql \ + -H "Content-Type: application/json" \ + -d '{"query":"{ subjects { id name credits } }"}') + echo "Subjects response: $response" + echo "$response" | grep -q '"subjects"' || exit 1 + + # Job 4: Rollback automático si smoke tests fallan + rollback: + runs-on: ubuntu-latest + needs: smoke-tests + if: failure() + steps: + - name: Setup SSH + run: | + mkdir -p ~/.ssh + echo "${{ secrets.K3S_SSH_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan -H ${{ env.K3S_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: Rollback Deployments run: | ssh ${{ env.K3S_USER }}@${{ env.K3S_HOST }} << 'ENDSSH' echo "${{ secrets.K3S_SUDO_PASS }}" | sudo -S kubectl rollout undo \ - deployment/student-api deployment/student-frontend -n academia 2>/dev/null || true + deployment/student-api deployment/student-frontend -n academia ENDSSH