name: Dynamic Branch Deploy on: [push] env: REGISTRY: git.zb-server.de # WICHTIG: Deine echte Haupt-Domain BASE_DOMAIN: escape-from-school.de jobs: build-and-deploy: runs-on: ubuntu-latest steps: # 1. Code auschecken (fetch-depth: 2 für git diff gegen den vorherigen Commit) - name: Checkout Code uses: actions/checkout@v3 with: fetch-depth: 2 # 2. Variablen vorbereiten (MIT HAUPT-DOMAIN LOGIK) - name: Prepare Environment Variables id: prep run: | # 1. Repo und Branch Namen säubern # Voller Pfad für Docker Image (z.B. "user/escape-teacher") FULL_IMAGE_PATH=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]') # Nur der Projektname für K8s (z.B. "escape-teacher") REPO_LOWER=$(echo "$FULL_IMAGE_PATH" | cut -d'/' -f2) # Branch Name säubern (Sonderzeichen zu Bindestrichen) BRANCH_LOWER=$(echo "${{ gitea.ref_name }}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g') # 2. Logik: Ist es der Haupt-Branch? if [ "$BRANCH_LOWER" = "main" ] || [ "$BRANCH_LOWER" = "master" ]; then APP_URL="${{ env.BASE_DOMAIN }}" TARGET_NS="${REPO_LOWER}" echo "Mode: PRODUCTION (Root Domain)" else APP_URL="${REPO_LOWER}-${BRANCH_LOWER}.${{ env.BASE_DOMAIN }}" TARGET_NS="${REPO_LOWER}-${BRANCH_LOWER}" echo "Mode: DEVELOPMENT (Subdomain)" fi # Image Tag (Commit Hash) und stabiler Branch-Tag IMAGE_TAG="${{ gitea.sha }}" BRANCH_TAG="${TARGET_NS}-latest" # Debug Ausgabe echo "DEBUG: Branch: $BRANCH_LOWER" echo "DEBUG: Namespace: $TARGET_NS" echo "DEBUG: URL: $APP_URL" echo "DEBUG: Branch-Tag: $BRANCH_TAG" # In Gitea Actions Environment schreiben echo "FULL_IMAGE_PATH=$FULL_IMAGE_PATH" >> $GITHUB_ENV echo "REPO_NAME=$REPO_LOWER" >> $GITHUB_ENV echo "TARGET_NS=$TARGET_NS" >> $GITHUB_ENV echo "APP_URL=$APP_URL" >> $GITHUB_ENV echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV echo "BRANCH_TAG=$BRANCH_TAG" >> $GITHUB_ENV # 3. Prüfen ob ein Image-Rebuild nötig ist - name: Detect Source Changes run: | # Beim allerersten Commit gibt es kein HEAD~1 → immer bauen if ! git rev-parse HEAD~1 >/dev/null 2>&1; then echo "NEEDS_BUILD=true" >> $GITHUB_ENV echo "→ Erster Commit, Image wird gebaut" exit 0 fi CHANGED=$(git diff --name-only HEAD~1 HEAD) echo "Geänderte Dateien:" echo "$CHANGED" # Rebuild wenn Source-Code, Dockerfile oder Assets geändert wurden if echo "$CHANGED" | grep -qE '(^Dockerfile$|^go\.(mod|sum)$|^(cmd|pkg|assets_raw)/)'; then echo "NEEDS_BUILD=true" >> $GITHUB_ENV echo "→ Quelldateien geändert – Image wird neu gebaut" else echo "NEEDS_BUILD=false" >> $GITHUB_ENV echo "→ Keine Quelländerungen – Image-Build wird übersprungen" fi # 4. Image bauen und pushen (NUR wenn NEEDS_BUILD=true) - name: Build and Push with Kaniko if: env.NEEDS_BUILD == 'true' uses: aevea/action-kaniko@v0.12.0 with: registry: ${{ env.REGISTRY }} username: ${{ gitea.actor }} password: ${{ secrets.PACKAGE_TOKEN }} image: ${{ env.FULL_IMAGE_PATH }} tag: ${{ env.IMAGE_TAG }} cache: true extra_args: --skip-tls-verify-pull --insecure # 5. Stabilen Branch-Tag aktualisieren (NUR nach erfolgreichem Build) # Damit weiß der nächste Nicht-Build-Push welches Image er verwenden soll. - name: Tag as branch-latest if: env.NEEDS_BUILD == 'true' run: | AUTH=$(echo -n "${{ gitea.actor }}:${{ secrets.PACKAGE_TOKEN }}" | base64 -w0) REGISTRY_API="https://${{ env.REGISTRY }}/v2/${{ env.FULL_IMAGE_PATH }}" # Fetch the manifest (try OCI index first, then v2, then v1) for MEDIA_TYPE in \ "application/vnd.oci.image.index.v1+json" \ "application/vnd.docker.distribution.manifest.list.v2+json" \ "application/vnd.docker.distribution.manifest.v2+json" \ "application/vnd.oci.image.manifest.v1+json"; do MANIFEST=$(curl -sk \ -H "Authorization: Basic $AUTH" \ -H "Accept: $MEDIA_TYPE" \ "${REGISTRY_API}/manifests/${{ env.IMAGE_TAG }}") if echo "$MANIFEST" | grep -q '"mediaType"\|"schemaVersion"\|"manifests"\|"layers"'; then break fi done echo "Manifest fetched, pushing as ${{ env.BRANCH_TAG }}..." curl -sk -X PUT \ -H "Authorization: Basic $AUTH" \ -H "Content-Type: $MEDIA_TYPE" \ -d "$MANIFEST" \ "${REGISTRY_API}/manifests/${{ env.BRANCH_TAG }}" \ -o /dev/null -w "HTTP %{http_code}\n" # 6. Deploy-Image festlegen # - Build passiert: SHA-Tag verwenden (exakt dieser Stand) # - Build übersprungen: Branch-Latest-Tag verwenden (letztes gebautes Image) - name: Set Deploy Image run: | if [ "$NEEDS_BUILD" = "true" ]; then DEPLOY_IMAGE="${{ env.REGISTRY }}/${{ env.FULL_IMAGE_PATH }}:${{ env.IMAGE_TAG }}" echo "→ Deploy mit neuem Image: $DEPLOY_IMAGE" else DEPLOY_IMAGE="${{ env.REGISTRY }}/${{ env.FULL_IMAGE_PATH }}:${{ env.BRANCH_TAG }}" echo "→ Deploy mit bestehendem Image: $DEPLOY_IMAGE" fi echo "DEPLOY_IMAGE=$DEPLOY_IMAGE" >> $GITHUB_ENV # 7. Setup Kubectl - name: Setup Kubectl run: | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x kubectl mv kubectl /usr/local/bin/ mkdir -p $HOME/.kube echo "${{ secrets.KUBE_CONFIG }}" > $HOME/.kube/config chmod 600 $HOME/.kube/config # Internal DNS Trick (für Kommunikation innerhalb des Clusters) sed -i 's|server: https://.*:6443|server: https://kubernetes.default.svc:443|g' $HOME/.kube/config # 8. Deploy to Kubernetes - name: Deploy to Kubernetes run: | # Namespace erstellen (falls nicht existiert) kubectl create namespace ${{ env.TARGET_NS }} --dry-run=client -o yaml | kubectl apply -f - # Ingress und App-Manifest anpassen sed -i "s|\${APP_URL}|${{ env.APP_URL }}|g" k8s/ingress.yaml sed -i "s|\${TARGET_NS}|${{ env.TARGET_NS }}|g" k8s/ingress.yaml sed -i "s|\${IMAGE_NAME}|${{ env.DEPLOY_IMAGE }}|g" k8s/app.yaml # Anwenden echo "Deploying to Namespace: ${{ env.TARGET_NS }} (Image: ${{ env.DEPLOY_IMAGE }})" kubectl apply -f k8s/compress-middleware.yaml -n ${{ env.TARGET_NS }} kubectl apply -f k8s/pvc.yaml -n ${{ env.TARGET_NS }} kubectl apply -f k8s/nats.yaml -n ${{ env.TARGET_NS }} kubectl apply -f k8s/redis.yaml -n ${{ env.TARGET_NS }} kubectl apply -f k8s/app.yaml -n ${{ env.TARGET_NS }} kubectl apply -f k8s/cilium-netpol.yaml -n ${{ env.TARGET_NS }} kubectl apply -f k8s/ingress.yaml -n ${{ env.TARGET_NS }} # HPA nur für Main/Master Branch if [ "${{ env.TARGET_NS }}" == "${{ env.REPO_NAME }}" ]; then echo "Main Branch: Applying HPA..." kubectl apply -f k8s/hpa.yaml -n ${{ env.TARGET_NS }} else echo "Feature Branch: Skipping HPA." kubectl delete hpa escape-game-hpa -n ${{ env.TARGET_NS }} --ignore-not-found fi # Pod nur neu starten wenn ein neues Image gebaut wurde # Bei reinen k8s-Änderungen reicht kubectl apply, kein Restart nötig if [ "$NEEDS_BUILD" = "true" ]; then kubectl rollout restart deployment/escape-game -n ${{ env.TARGET_NS }} fi # 9. Summary - name: Summary run: | if [ "$NEEDS_BUILD" = "true" ]; then echo "🔨 Image neu gebaut und deployed: ${{ env.DEPLOY_IMAGE }}" else echo "⚡ Image-Build übersprungen (keine Quelländerungen)" echo "📦 Bestehendes Image verwendet: ${{ env.DEPLOY_IMAGE }}" fi echo "🚀 Deployed to https://${{ env.APP_URL }}"