name: CI on: push: branches: [main] pull_request: branches: [main] workflow_dispatch: env: REGISTRY: forgejo.riotpiao.com IMAGE: forgejo.riotpiao.com/rock/api-gateway DOCKER_HOST: tcp://localhost:2375 jobs: ci: name: CI runs-on: golang steps: - name: Install dependencies run: | apt-get update apt-get install -y docker.io curl nodejs - name: Checkout code uses: actions/checkout@v4 - name: Go vet run: go vet ./... - name: Go test run: go test -short ./... - name: Get short SHA id: sha run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Registry login if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" \ --username "${REGISTRY_USER}" --password-stdin env: REGISTRY_USER: ${{ secrets.FORGEJO_REGISTRY_USER }} REGISTRY_TOKEN: ${{ secrets.FORGEJO_REGISTRY_TOKEN }} - name: Build Docker image if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | docker build --no-cache \ -t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \ -f Dockerfile . - name: Push image (SHA tag) if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}" # ── Deploy canary pod + integration test ──────────────── # Canary pod runs in-cluster with real secrets and real upstreams # (Temporal, Gotify). Tests run against its pod IP directly. # Zero downtime: production pods untouched until tests pass. - name: Setup kubeconfig if: false # SKIP: only needed for canary deploy, RBAC not ready run: | mkdir -p ~/.kube echo "${KUBECONFIG_B64}" | base64 -d > ~/.kube/config kubectl get namespaces --no-headers | head -1 echo '✓ kubeconfig works' env: KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} - name: Deploy canary pod if: false # SKIP: SA lacks pod create RBAC. Re-enable when fixed. id: canary run: | SHA="${{ steps.sha.outputs.short_sha }}" POD_NAME="api-gateway-canary-${SHA}" # Remove any stale canary kubectl delete pod "${POD_NAME}" -n api --ignore-not-found # Create canary pod with real secrets + config kubectl run "${POD_NAME}" \ --image="${IMAGE}:${SHA}" \ --restart=Never \ --namespace=api \ --labels="app=api-gateway-canary,sha=${SHA}" \ --overrides="$(cat <> $GITHUB_OUTPUT echo "pod_ip=${POD_IP}" >> $GITHUB_OUTPUT echo "✓ Canary ready at ${POD_IP}:8080" - name: Run integration tests against canary if: false # SKIP: depends on canary pod id: tests run: | POD_IP="${{ steps.canary.outputs.pod_ip }}" GW="http://${POD_IP}:8080" RESULTS_DIR="/tmp/test-results" mkdir -p "${RESULTS_DIR}" echo "Running integration tests against canary at ${GW}..." sh k8s/tekton/scripts/integration-test.sh RESULT=$(cat "${RESULTS_DIR}/result" 2>/dev/null || echo "fail") SUMMARY=$(cat "${RESULTS_DIR}/summary" 2>/dev/null || echo "unknown") echo "Result: ${RESULT}" echo "Summary: ${SUMMARY}" echo "result=${RESULT}" >> $GITHUB_OUTPUT - name: Cleanup canary pod if: false # SKIP: depends on canary pod run: | POD_NAME="${{ steps.canary.outputs.pod_name }}" if [ -n "${POD_NAME}" ]; then kubectl delete pod "${POD_NAME}" -n api --ignore-not-found || true echo "✓ Canary pod removed" else echo "⚠ No canary pod to clean up (name was empty)" fi - name: Gate on test result if: false # SKIP: depends on canary pod run: | echo "✗ Integration tests FAILED — production deployment unchanged" exit 1 # ── Zero-downtime promotion ────────────────────────────── # kubectl set image triggers a rolling update: new pods come up # before old pods are terminated. Production traffic uninterrupted. # TODO: Re-enable rolling update when kubeconfig/RBAC is ready # - name: Promote — rolling update # if: github.event_name == 'push' && github.ref == 'refs/heads/main' # run: | # kubectl set image deployment/api-gateway api-gateway="${IMAGE}:${SHA}" -n api # kubectl rollout status deployment/api-gateway -n api --timeout=120s - name: Tag :latest (informational) if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | docker tag "${IMAGE}:${{ steps.sha.outputs.short_sha }}" "${IMAGE}:latest" docker push "${IMAGE}:latest" echo "✓ Tagged :latest" - name: Cleanup docker images if: always() run: docker image prune -af 2>&1 | tail -3 || true