name: CI/CD Pipeline with Ephemeral PiP on: push: branches: [main] pull_request: branches: [main] env: REGISTRY: ${{ secrets.REGISTRY_HOST }} APP_NAME: ${{ secrets.APP_NAME }} IMAGE_TAG: ${{ github.sha }} jobs: test-backend: runs-on: [self-hosted, ci] steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup ephemeral PiP container run: | chmod +x ./secure_pip_setup.sh ./secure_pip_setup.sh - name: Wait for PiP readiness run: | chmod +x ./pip_ready.sh ./pip_ready.sh - name: Setup SSH for production deployment run: | mkdir -p ~/.ssh echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H ${{ secrets.PRODUCTION_IP }} >> ~/.ssh/known_hosts - name: Login to Forgejo Container Registry run: | podman exec ci-pip podman login ${{ secrets.REGISTRY_HOST }} \ -u ${{ secrets.REGISTRY_USERNAME }} \ -p ${{ secrets.REGISTRY_TOKEN }} - name: Start PostgreSQL for integration tests run: | podman exec ci-pip podman run -d \ --name test-postgres \ -e POSTGRES_PASSWORD=testpassword \ -e POSTGRES_USER=testuser \ -e POSTGRES_DB=testdb \ -p 5432:5432 \ postgres:15-alpine - name: Wait for PostgreSQL to be ready run: | podman exec ci-pip timeout 60 bash -c 'until podman exec test-postgres pg_isready -h localhost -p 5432 -U testuser; do sleep 1; done' - name: Run backend unit tests run: | podman exec ci-pip podman run --rm \ -v $(pwd):/workspace \ -w /workspace \ rust:latest \ sh -c "cargo test --lib -- --test-threads=1" - name: Run backend integration tests env: DATABASE_URL: postgres://testuser:testpassword@localhost:5432/testdb run: | podman exec ci-pip podman run --rm \ -v $(pwd):/workspace \ -w /workspace \ -e DATABASE_URL="$DATABASE_URL" \ rust:latest \ sh -c "cargo test --test '*' -- --test-threads=1" - name: Cleanup test database if: always() run: | podman exec ci-pip podman stop test-postgres 2>/dev/null || true podman exec ci-pip podman rm test-postgres 2>/dev/null || true test-frontend: runs-on: [self-hosted, ci] needs: test-backend steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup ephemeral PiP container run: | chmod +x ./secure_pip_setup.sh ./secure_pip_setup.sh - name: Wait for PiP readiness run: | chmod +x ./pip_ready.sh ./pip_ready.sh - name: Run frontend tests in PiP run: | podman exec ci-pip podman run --rm \ -v $(pwd):/workspace \ -w /workspace \ node:20 \ sh -c "npm ci && npm run test" build-backend: runs-on: [self-hosted, ci] needs: test-frontend steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup ephemeral PiP container run: | chmod +x ./secure_pip_setup.sh ./secure_pip_setup.sh - name: Wait for PiP readiness run: | chmod +x ./pip_ready.sh ./pip_ready.sh - name: Login to Forgejo Container Registry run: | podman exec ci-pip podman login ${{ secrets.REGISTRY_HOST }} \ -u ${{ secrets.REGISTRY_USERNAME }} \ -p ${{ secrets.REGISTRY_TOKEN }} - name: Build backend image run: | podman exec ci-pip podman build \ -t ${{ secrets.REGISTRY_HOST }}/${{ secrets.APP_NAME }}/backend:${{ github.sha }} \ -f Dockerfile.backend . - name: Push backend image run: | podman exec ci-pip podman push \ ${{ secrets.REGISTRY_HOST }}/${{ secrets.APP_NAME }}/backend:${{ github.sha }} build-frontend: runs-on: [self-hosted, ci] needs: test-frontend steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup ephemeral PiP container run: | chmod +x ./secure_pip_setup.sh ./secure_pip_setup.sh - name: Wait for PiP readiness run: | chmod +x ./pip_ready.sh ./pip_ready.sh - name: Login to Forgejo Container Registry run: | podman exec ci-pip podman login ${{ secrets.REGISTRY_HOST }} \ -u ${{ secrets.REGISTRY_USERNAME }} \ -p ${{ secrets.REGISTRY_TOKEN }} - name: Build frontend image run: | podman exec ci-pip podman build \ -t ${{ secrets.REGISTRY_HOST }}/${{ secrets.APP_NAME }}/frontend:${{ github.sha }} \ -f Dockerfile.frontend . - name: Push frontend image run: | podman exec ci-pip podman push \ ${{ secrets.REGISTRY_HOST }}/${{ secrets.APP_NAME }}/frontend:${{ github.sha }} cleanup: runs-on: [self-hosted, ci] needs: [build-backend, build-frontend] if: always() steps: - name: Cleanup PiP container run: | podman rm -f ci-pip 2>/dev/null || true rm -f /tmp/podman.sock 2>/dev/null || true