From 72caa51dd809b455a6c4cbaafc52202a4dd061d5 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sat, 13 Jun 2026 17:17:38 +0000 Subject: [PATCH] ci: remove inert build-fallback pipelines (clean cut on fallbacks) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were event:deployment (never auto-fired) leftovers of the old in-cluster buildkit build. Removed under the no-local-builds policy; api+frontend build on GHA. github lineage was already clean — this drops them from the forgejo lineage too. Co-Authored-By: Claude Fable 5 --- .woodpecker/build-fallback-api.yml | 184 ---------------------- .woodpecker/build-fallback-frontend.yml | 196 ------------------------ 2 files changed, 380 deletions(-) delete mode 100644 .woodpecker/build-fallback-api.yml delete mode 100644 .woodpecker/build-fallback-frontend.yml diff --git a/.woodpecker/build-fallback-api.yml b/.woodpecker/build-fallback-api.yml deleted file mode 100644 index e447c92..0000000 --- a/.woodpecker/build-fallback-api.yml +++ /dev/null @@ -1,184 +0,0 @@ -# Fallback pipeline — only fires on manual `deployment` event after GHA -# (.github/workflows/build-api.yml) became the primary builder on -# 2026-05-18. Kept around in case GHA is down and a build needs to ship -# from inside the cluster. `event: deployment` means it never auto-fires -# on push. -when: - - event: deployment - -clone: - git: - image: woodpeckerci/plugin-git - settings: - attempts: 5 - backoff: 10s - -steps: - - name: install-api-deps - image: python:3.13-slim - backend_options: - kubernetes: - resources: - requests: - memory: 512Mi - limits: - memory: 1Gi - commands: - - apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 - - python -m venv .venv - - .venv/bin/pip install --quiet --upgrade pip - - >- - .venv/bin/pip install --quiet - pytest pytest-asyncio pytest-cov httpx fakeredis aioresponses - fastapi uvicorn sqlmodel sqlalchemy alembic pyjwt cryptography - celery redis click aiohttp aiohttp-socks pillow numpy pytesseract - opentelemetry-api opentelemetry-sdk opentelemetry-exporter-prometheus - opentelemetry-instrumentation-fastapi opentelemetry-instrumentation-sqlalchemy - python-dotenv webauthn apprise tenacity prometheus-client - email-validator opencv-python-headless tqdm pandas cachetools watchdog - - - name: test-unit - image: python:3.13-slim - depends_on: - - install-api-deps - commands: - - apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 - - .venv/bin/pytest tests/unit/ -v --tb=short - - - name: test-integration - image: python:3.13-slim - depends_on: - - install-api-deps - commands: - - apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 - - .venv/bin/pytest tests/integration/ tests/regression/ tests/e2e/ tests/test_listing_geojson.py -v --tb=short - - - name: build-and-push-api - image: woodpeckerci/plugin-docker-buildx - depends_on: - - test-unit - - test-integration - settings: - username: viktorbarzin - password: - from_secret: dockerhub-token - repo: viktorbarzin/realestatecrawler - dockerfile: Dockerfile - context: . - target: production - platforms: - - linux/amd64 - tag: ["${CI_PIPELINE_NUMBER}", "latest"] - cache_from: "viktorbarzin/realestatecrawler:latest" - cache_to: "type=inline" - - - name: update-deployment - image: alpine - depends_on: - - build-and-push-api - commands: - - apk add --no-cache curl jq - - | - TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) - IMAGE="viktorbarzin/realestatecrawler:${CI_PIPELINE_NUMBER}" - RESTART_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) - API="https://kubernetes:6443/apis/apps/v1/namespaces/realestate-crawler/deployments" - - for DEPLOY in realestate-crawler-api realestate-crawler-celery realestate-crawler-celery-beat; do - STATUS=$(curl -sfk "$API/$DEPLOY" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/json") - CONTAINER=$(echo "$STATUS" | jq -r '.spec.template.spec.containers[0].name') - PAUSED=$(echo "$STATUS" | jq -r '.spec.paused // false') - echo "Patching $DEPLOY (container=$CONTAINER, paused=$PAUSED) to image $IMAGE..." - - curl -sf -X PATCH "$API/$DEPLOY" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/strategic-merge-patch+json" \ - -k -d "{\"spec\":{\"paused\":null,\"template\":{\"metadata\":{\"annotations\":{\"kubectl.kubernetes.io/restartedAt\":\"$RESTART_AT\"}},\"spec\":{\"containers\":[{\"name\":\"$CONTAINER\",\"image\":\"$IMAGE\"}]}}}}" \ - | jq '{name: .metadata.name, generation: .metadata.generation, image: .spec.template.spec.containers[0].image, paused: .spec.paused, restartedAt: .spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"]}' - done - - - name: verify-deploy - image: alpine - depends_on: - - update-deployment - commands: - - apk add --no-cache curl jq - - | - TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) - EXPECTED_IMAGE="viktorbarzin/realestatecrawler:${CI_PIPELINE_NUMBER}" - BASE_API="https://kubernetes:6443/api/v1/namespaces/realestate-crawler/pods" - DEPLOY_API="https://kubernetes:6443/apis/apps/v1/namespaces/realestate-crawler/deployments" - - for DEPLOY in realestate-crawler-api realestate-crawler-celery realestate-crawler-celery-beat; do - echo "Verifying $DEPLOY..." - PODS_API="$BASE_API?labelSelector=app%3D$DEPLOY" - RS_API="https://kubernetes:6443/apis/apps/v1/namespaces/realestate-crawler/replicasets?labelSelector=app%3D$DEPLOY" - - DEPLOY_STATUS=$(curl -sfk "$DEPLOY_API/$DEPLOY" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/json") - echo " Deployment spec image: $(echo "$DEPLOY_STATUS" | jq -r '.spec.template.spec.containers[0].image')" - echo " Deployment paused: $(echo "$DEPLOY_STATUS" | jq -r '.spec.paused // false')" - echo " Deployment status: replicas=$(echo "$DEPLOY_STATUS" | jq -r '.status.replicas // 0') updated=$(echo "$DEPLOY_STATUS" | jq -r '.status.updatedReplicas // 0') ready=$(echo "$DEPLOY_STATUS" | jq -r '.status.readyReplicas // 0') unavailable=$(echo "$DEPLOY_STATUS" | jq -r '.status.unavailableReplicas // 0')" - echo " Conditions:" - echo "$DEPLOY_STATUS" | jq -r '.status.conditions[]? | " \(.type): \(.status) (\(.reason // "unknown"))"' 2>/dev/null || echo " (none)" - - echo " ReplicaSets:" - curl -sfk "$RS_API" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/json" | \ - jq -r '.items[] | " \(.metadata.name) desired=\(.spec.replicas) ready=\(.status.readyReplicas // 0) image=\(.spec.template.spec.containers[0].image)"' 2>/dev/null || echo " (none)" - - FOUND=0 - for i in $(seq 1 60); do - RAW=$(curl -sfk "$PODS_API" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/json") - - if [ "$i" -eq 1 ] || [ "$i" -eq 10 ] || [ "$i" -eq 30 ]; then - echo " DEBUG (attempt $i): All pods for $DEPLOY:" - echo "$RAW" | jq -r '[.items[] | { - name: .metadata.name, - image: .spec.containers[0].image, - ready: ([.status.containerStatuses[]? | .ready] | first // "unknown"), - phase: .status.phase, - restarts: ([.status.containerStatuses[]? | .restartCount] | first // 0), - reason: ([.status.containerStatuses[]? | .state | to_entries[] | .value.reason // empty] | first // "running") - }] | .[] | " \(.name) image=\(.image) ready=\(.ready) phase=\(.phase) restarts=\(.restarts) reason=\(.reason)"' 2>/dev/null || echo " (no pods or parse error)" - fi - - RESULT=$(echo "$RAW" | \ - jq --arg img "$EXPECTED_IMAGE" '[.items[] | select( - (.status.containerStatuses[]? | .ready == true) and - (.spec.containers[]? | .image | endswith($img)) - ) | {name: .metadata.name, image: .spec.containers[0].image, started: .status.startTime}]') - - COUNT=$(echo "$RESULT" | jq 'length' 2>/dev/null || echo 0) - echo " Attempt $i/60: $COUNT pod(s) ready with image matching $EXPECTED_IMAGE" - - if [ "$COUNT" -gt 0 ] 2>/dev/null; then - echo "$RESULT" | jq -r '.[] | " \(.name) image=\(.image) started=\(.started)"' - echo "$DEPLOY is live!" - FOUND=1 - break - fi - - sleep 5 - done - - if [ "$FOUND" -ne 1 ]; then - echo " FINAL DEBUG: All pods for $DEPLOY:" - echo "$RAW" | jq -r '[.items[] | { - name: .metadata.name, - image: .spec.containers[0].image, - ready: ([.status.containerStatuses[]? | .ready] | first // "unknown"), - phase: .status.phase, - restarts: ([.status.containerStatuses[]? | .restartCount] | first // 0), - reason: ([.status.containerStatuses[]? | .state | to_entries[] | .value.reason // empty] | first // "running") - }] | .[] | " \(.name) image=\(.image) ready=\(.ready) phase=\(.phase) restarts=\(.restarts) reason=\(.reason)"' 2>/dev/null || echo " (no pods or parse error)" - echo "ERROR: No new ready pod for $DEPLOY with image $EXPECTED_IMAGE appeared within 5 minutes" - exit 1 - fi - done diff --git a/.woodpecker/build-fallback-frontend.yml b/.woodpecker/build-fallback-frontend.yml deleted file mode 100644 index ca166da..0000000 --- a/.woodpecker/build-fallback-frontend.yml +++ /dev/null @@ -1,196 +0,0 @@ -# Fallback pipeline — only fires on manual `deployment` event after GHA -# (.github/workflows/build-frontend.yml) became the primary builder on -# 2026-05-18. Kept around in case GHA is down and a build needs to ship -# from inside the cluster. `event: deployment` means it never auto-fires -# on push. -when: - - event: deployment - -clone: - git: - image: woodpeckerci/plugin-git - settings: - attempts: 5 - backoff: 10s - -steps: - - name: install-frontend-deps - image: node:24-alpine - backend_options: - kubernetes: - resources: - requests: - memory: 1Gi - limits: - memory: 2Gi - environment: - NODE_OPTIONS: "--max-old-space-size=1536" - commands: - - cd frontend && npm ci - - - name: test-shard-1 - image: node:24-alpine - depends_on: - - install-frontend-deps - backend_options: - kubernetes: - resources: - requests: - memory: 1Gi - limits: - memory: 2Gi - environment: - NODE_OPTIONS: "--max-old-space-size=1536" - commands: - - cd frontend && npx vitest run --reporter=verbose --shard=1/4 - - - name: test-shard-2 - image: node:24-alpine - depends_on: - - install-frontend-deps - backend_options: - kubernetes: - resources: - requests: - memory: 1Gi - limits: - memory: 2Gi - environment: - NODE_OPTIONS: "--max-old-space-size=1536" - commands: - - cd frontend && npx vitest run --reporter=verbose --shard=2/4 - - - name: test-shard-3 - image: node:24-alpine - depends_on: - - install-frontend-deps - backend_options: - kubernetes: - resources: - requests: - memory: 1Gi - limits: - memory: 2Gi - environment: - NODE_OPTIONS: "--max-old-space-size=1536" - commands: - - cd frontend && npx vitest run --reporter=verbose --shard=3/4 - - - name: test-shard-4 - image: node:24-alpine - depends_on: - - install-frontend-deps - backend_options: - kubernetes: - resources: - requests: - memory: 1Gi - limits: - memory: 2Gi - environment: - NODE_OPTIONS: "--max-old-space-size=1536" - commands: - - cd frontend && npx vitest run --reporter=verbose --shard=4/4 - - # Writes frontend/.env.production from the Woodpecker secret. Vite auto-loads - # this file during `npx vite build` (the plugin step below picks it up via - # the build context). Cleaner than --build-arg because docker-buildx's - # build_args list-parser mangled the KEY=VALUE form when the value contained - # `=` separators (see pipeline 2207 — bundle came out without the token). - - name: prepare-frontend-env - image: alpine - depends_on: - - test-shard-1 - - test-shard-2 - - test-shard-3 - - test-shard-4 - environment: - MAPBOX_TOKEN: - from_secret: wrongmove-mapbox-token - commands: - - 'printf "VITE_MAPBOX_TOKEN=%s\n" "$MAPBOX_TOKEN" > frontend/.env.production' - - 'wc -c frontend/.env.production' - - - name: build-and-push-frontend - image: woodpeckerci/plugin-docker-buildx - depends_on: - - prepare-frontend-env - settings: - username: viktorbarzin - password: - from_secret: dockerhub-token - repo: viktorbarzin/immoweb - dockerfile: frontend/Dockerfile - context: frontend - target: production - platforms: - - linux/amd64 - tag: ["${CI_PIPELINE_NUMBER}", "latest"] - cache_from: "viktorbarzin/immoweb:latest" - cache_to: "type=inline" - - - name: update-deployment - image: alpine - depends_on: - - build-and-push-frontend - commands: - - apk add --no-cache curl jq - - | - TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) - IMAGE="viktorbarzin/immoweb:${CI_PIPELINE_NUMBER}" - RESTART_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) - API="https://kubernetes:6443/apis/apps/v1/namespaces/realestate-crawler/deployments" - DEPLOY="realestate-crawler-ui" - - CONTAINER=$(curl -sfk "$API/$DEPLOY" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/json" | jq -r '.spec.template.spec.containers[0].name') - echo "Patching $DEPLOY (container=$CONTAINER) to image $IMAGE with restartedAt=$RESTART_AT..." - - curl -sf -X PATCH "$API/$DEPLOY" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/strategic-merge-patch+json" \ - -k -d "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"kubectl.kubernetes.io/restartedAt\":\"$RESTART_AT\"}},\"spec\":{\"containers\":[{\"name\":\"$CONTAINER\",\"image\":\"$IMAGE\"}]}}}}" \ - | jq '{name: .metadata.name, generation: .metadata.generation, image: .spec.template.spec.containers[0].image}' - - - name: verify-deploy - image: alpine - depends_on: - - update-deployment - commands: - - apk add --no-cache curl jq - - | - TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) - EXPECTED_IMAGE="viktorbarzin/immoweb:${CI_PIPELINE_NUMBER}" - PODS_API="https://kubernetes:6443/api/v1/namespaces/realestate-crawler/pods?labelSelector=app%3Drealestate-crawler-ui" - - for i in $(seq 1 60); do - RAW=$(curl -sfk "$PODS_API" \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: application/json") - - if [ "$i" -eq 1 ]; then - echo "DEBUG: All pods for realestate-crawler-ui:" - echo "$RAW" | jq -r '[.items[] | {name: .metadata.name, image: .spec.containers[0].image, ready: (.status.containerStatuses[]? | .ready), phase: .status.phase}] | .[] | " \(.name) image=\(.image) ready=\(.ready) phase=\(.phase)"' 2>/dev/null || echo " (no pods found)" - fi - - RESULT=$(echo "$RAW" | \ - jq --arg img "$EXPECTED_IMAGE" '[.items[] | select( - (.status.containerStatuses[]? | .ready == true) and - (.spec.containers[]? | .image | endswith($img)) - ) | {name: .metadata.name, image: .spec.containers[0].image, started: .status.startTime}]') - - COUNT=$(echo "$RESULT" | jq 'length') - echo "Attempt $i/60: $COUNT pod(s) ready with image matching $EXPECTED_IMAGE" - - if [ "$COUNT" -gt 0 ]; then - echo "$RESULT" | jq -r '.[] | " \(.name) image=\(.image) started=\(.started)"' - echo "New pod is live!" - exit 0 - fi - - sleep 5 - done - - echo "ERROR: No new ready pod with image $EXPECTED_IMAGE appeared within 5 minutes" - exit 1