- Dockerfile/compose: Flask-App + selenium/standalone-chrome (noVNC), Healthcheck - app.py: /healthz + eingebettete noVNC-Live-Ansicht (NOVNC_URL, lokal:7900 / Cluster:/novnc/) - Helm-Chart infra/k8s/base/ibo: App + Selenium-Sidecar, 2 Ports, Ingress (/ + /novnc via stripPrefix), SSO-Middlewares aus dem CD-Repo - Gitea-CI: version -> test -> build-push -> helm-validate -> deploy-dev (Write-back) - .gitignore/.dockerignore (Dev-Samples raus) - infra/RUNBOOK-ibo.md: Zitadel/DNS/Deploy/Prod-Promote Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
128 lines
5.2 KiB
YAML
128 lines
5.2 KiB
YAML
# Momentrum CI (Contabo-Gitea) — build · test · push · deploy(dev)
|
|
# Zielt auf das Gitea auf momentrum-k3s-01 (org: momentrum).
|
|
#
|
|
# Umgebungs-Modell fuer ibo (bewusst NUR dev+prod, keine PR-Previews):
|
|
# - dev = deployt AUTOMATISCH bei jedem main-Push (dieser Deploy-Step bumpt
|
|
# apps/internal/ibo/dev.yaml im CD-Repo -> ArgoCD synct dev).
|
|
# - prod = wird MANUELL promotet (Tag aus dev.yaml -> app.yaml committen,
|
|
# siehe infra/RUNBOOK-ibo.md). Die CI fasst prod NICHT an.
|
|
#
|
|
# Image-Tag ist immutable pro Commit:
|
|
# - Pull Request: pr-<nummer>-<shortsha>
|
|
# - Push auf main: pr-<id>-<sha> (aus Merge-Message) bzw. main-<shortsha>
|
|
name: Momentrum CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
env:
|
|
# :3000 = direkt zu Gitea (HTTP). Host-Docker hat diese Registry in insecure-registries.
|
|
REGISTRY: momentrum-k3s-01.tailcc1bcf.ts.net:3000
|
|
IMAGE: momentrum/ibo-web
|
|
CHART_PATH: infra/k8s/base/ibo
|
|
|
|
jobs:
|
|
version:
|
|
name: Version (aus PR-ID / SHA)
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
tag: ${{ steps.v.outputs.tag }}
|
|
steps:
|
|
- id: v
|
|
env:
|
|
HEAD_MSG: ${{ github.event.head_commit.message }}
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
short=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7)
|
|
tag="pr-${{ github.event.number }}-${short}"
|
|
else
|
|
short=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
|
# Push auf main = PR-Merge: PR-ID aus der Merge-Commit-Message ziehen.
|
|
# `|| true`: kein #N in der Message darf unter set -e -o pipefail killen.
|
|
pr=$(printf '%s' "$HEAD_MSG" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || true)
|
|
if [ -n "$pr" ]; then tag="pr-${pr}-${short}"; else tag="main-${short}"; fi
|
|
fi
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
echo "Image-Tag: $tag"
|
|
|
|
test:
|
|
name: Test (compile + pytest)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
- run: pip install --no-cache-dir -r requirements.txt pytest
|
|
- name: Compile-Check (alle Module)
|
|
run: python -m compileall -q app.py core.py config.py immo_bot.py mailtm.py autofill.py autofill_kontakt.py cookies_setup.py
|
|
- name: Unit-Tests (falls vorhanden)
|
|
run: |
|
|
if ls test_*.py >/dev/null 2>&1; then pytest -q; else echo "keine Tests - skip"; fi
|
|
|
|
build-push:
|
|
name: Build & Push image
|
|
runs-on: ubuntu-latest
|
|
needs: [version, test]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || '' }}
|
|
# Plain docker build/push -> Host-Docker-Daemon (gemounteter Socket) inkl.
|
|
# dessen insecure-registries. buildx wuerde die daemon-Config ignorieren.
|
|
- name: Login to Gitea Registry
|
|
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login "${{ env.REGISTRY }}" -u "${{ secrets.REGISTRY_USER }}" --password-stdin
|
|
- name: Build & push
|
|
run: |
|
|
IMG="${{ env.REGISTRY }}/${{ env.IMAGE }}:${{ needs.version.outputs.tag }}"
|
|
ok=""
|
|
for attempt in 1 2 3; do
|
|
echo "== Build-Versuch $attempt =="
|
|
if DOCKER_BUILDKIT=1 docker build -t "$IMG" -f Dockerfile .; then ok=1; break; fi
|
|
echo "Build fehlgeschlagen (Versuch $attempt), neuer Versuch in 10s..."; sleep 10
|
|
done
|
|
[ "$ok" = "1" ] || { echo "Build nach 3 Versuchen fehlgeschlagen"; exit 1; }
|
|
docker push "$IMG"
|
|
|
|
helm-validate:
|
|
name: Helm lint + template
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: azure/setup-helm@v4
|
|
with:
|
|
version: v3.17.3
|
|
- run: |
|
|
helm lint "${{ env.CHART_PATH }}"
|
|
helm template ibo "${{ env.CHART_PATH }}" >/dev/null
|
|
|
|
# CD-Write-back: nur auf main. Bumpt den Image-Tag in apps/internal/ibo/dev.yaml
|
|
# im CD-Repo -> ArgoCD deployt DEV automatisch. Prod bleibt unberuehrt (Promote
|
|
# ist ein bewusster manueller Commit, siehe RUNBOOK). DEPLOY_TOKEN = Gitea-Token
|
|
# mit Write auf momentrum-deploy.
|
|
deploy-dev:
|
|
name: Deploy DEV (Image-Tag -> CD-Repo)
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
needs: [version, build-push, helm-validate]
|
|
steps:
|
|
- name: Write-back image.tag nach momentrum-deploy (dev.yaml)
|
|
run: |
|
|
TAG="${{ needs.version.outputs.tag }}"
|
|
git clone -q "http://ci:${{ secrets.DEPLOY_TOKEN }}@100.111.27.99:3000/momentrum/momentrum-deploy.git" /tmp/deploy
|
|
cd /tmp/deploy
|
|
APP_FILE="apps/internal/ibo/dev.yaml"
|
|
grep -qE '^ tag: ' "$APP_FILE" || { echo "FEHLER: 'tag:'-Zeile nicht in $APP_FILE gefunden"; exit 1; }
|
|
sed -i "s|^ tag: .*| tag: ${TAG}|" "$APP_FILE"
|
|
git config user.email "ci@momentrum.local"
|
|
git config user.name "Momentrum CI"
|
|
git commit -am "ibo: deploy dev ${TAG}" || { echo "kein Change - Tag identisch"; exit 0; }
|
|
git push origin HEAD:main
|
|
echo "Deployed dev tag ${TAG} -> momentrum-deploy"
|