Files
cameleer-server/.claude/rules/cicd.md
hsiegeln 724054296e
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 3m24s
CI / docker (push) Successful in 2m28s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 48s
ci(loader): build & push cameleer-runtime-loader image only when its sources change
The init-container image referenced by DockerRuntimeOrchestrator
(`gitea.siegeln.net/cameleer/cameleer-runtime-loader:latest`) had no CI
producer; it had to be built and pushed by hand. Replicates the
cameleer-saas pattern (single docker job with multiple buildx push
steps), but gates the loader build on a path-diff so unrelated commits
don't rebuild and re-tag a sidecar that didn't change.

- build job: fetch-depth=0 + Detect runtime-loader changes step that
  diffs `${{ github.event.before }}..${{ github.sha }}` for paths under
  cameleer-runtime-loader/. Falls back to `changed=true` when no prior
  commit is reachable (first push to a branch).
- docker job: new `Build and push runtime-loader` step gated on
  `needs.build.outputs.loader_changed == 'true'`. Tags with sha and
  latest/branch-<slug>, --provenance=false for Gitea, no buildcache
  (image is alpine + script).
- Cleanup loops in docker and cleanup-branch jobs include the new
  package.
- Rules and loader README updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:13:25 +02:00

3.4 KiB

paths
paths
.gitea/**
deploy/**
Dockerfile
docker-entrypoint.sh

CI/CD & Deployment

  • CI workflow: .gitea/workflows/ci.yml — build -> docker -> deploy on push to main or feature branches. paths-ignore skips the whole pipeline for docs-only / .planning/ / .claude/ / *.md changes (push and PR triggers).
  • Build step skips integration tests (-DskipITs) — Testcontainers needs Docker daemon
  • Build caches (parallel actions/cache@v4 steps in the build job): ~/.m2/repository (key on all pom.xml), ~/.npm (key on ui/package-lock.json), ui/node_modules/.vite (key on ui/package-lock.json + ui/vite.config.ts). UI install uses npm ci --prefer-offline --no-audit --fund=false so the npm cache is the primary source.
  • Maven build performance (set in pom.xml and cameleer-server-app/pom.xml): useIncrementalCompilation=true on the compiler plugin; Surefire uses forkCount=1C + reuseForks=true (one JVM per CPU core, reused across test classes); Failsafe keeps forkCount=1 + reuseForks=true. Unit tests must not rely on per-class JVM isolation.
  • UI build script (ui/package.json): build is vite build only — the type-check pass was split out into npm run typecheck (run separately when you want a full tsc --noEmit sweep).
  • Docker: multi-stage build (Dockerfile), $BUILDPLATFORM for native Maven on ARM64 runner, amd64 runtime. docker-entrypoint.sh imports /certs/ca.pem into JVM truststore before starting the app (supports custom CAs for OIDC discovery without CAMELEER_SERVER_SECURITY_OIDCTLSSKIPVERIFY).
  • REGISTRY_TOKEN build arg required for cameleer-common dependency resolution
  • Registry: gitea.siegeln.net/cameleer/cameleer-server (container images)
  • cameleer-runtime-loader image (init container that fetches the deployable JAR before the runtime container starts) is built and pushed by the same docker job, but only when files under cameleer-runtime-loader/ actually changed in the push. Detection runs in the build job (Detect runtime-loader changes step, diffs ${{ github.event.before }}..${{ github.sha }}) and is exposed as the loader_changed job output. The loader build step uses if: needs.build.outputs.loader_changed == 'true'. Build job's checkout uses fetch-depth: 0 so the diff has access to the prior commit.
  • K8s manifests in deploy/ — Kustomize base + overlays (main/feature), shared infra (PostgreSQL, ClickHouse, Logto) as top-level manifests
  • Deployment target: k3s at 192.168.50.86, namespace cameleer (main), cam-<slug> (feature branches)
  • Feature branches: isolated namespace, PG schema; Traefik Ingress at <slug>-api.cameleer.siegeln.net
  • Secrets managed in CI deploy step (idempotent --dry-run=client | kubectl apply): cameleer-auth, cameleer-postgres-credentials, cameleer-clickhouse-credentials
  • K8s probes: server uses /api/v1/health, PostgreSQL uses pg_isready -U "$POSTGRES_USER" (env var, not hardcoded)
  • K8s security: server and database pods run with securityContext.runAsNonRoot. UI (nginx) runs without securityContext (needs root for entrypoint setup).
  • Docker: server Dockerfile has no default credentials — all DB config comes from env vars at runtime
  • Docker build uses buildx registry cache + --provenance=false for Gitea compatibility
  • CI: branch slug sanitization extracted to .gitea/sanitize-branch.sh, sourced by docker and deploy-feature jobs