perf(build): faster Maven + UI + CI pipelines
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m43s
CI / docker (push) Successful in 4m13s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 41s

- Maven: enable useIncrementalCompilation; Surefire forkCount=1C +
  reuseForks=true so unit-test JVMs are reused per CPU core instead of
  spawning per class (205 tests pass under the new strategy).
- Testcontainers: opt-in reuse via .withReuse(true) on Postgres +
  ClickHouse base; per-developer enable via ~/.testcontainers.properties.
- UI: drop redundant `tsc --noEmit` from `npm run build` (Vite already
  type-checks); split into a dedicated `npm run typecheck` script.
- CI: cache ~/.npm and ui/node_modules/.vite alongside Maven; npm ci with
  --prefer-offline --no-audit --fund=false; paths-ignore for docs-only,
  .planning/ and .claude/ changes so doc-only pushes skip the pipeline.
- Docs: CLAUDE.md + .claude/rules/cicd.md updated with the new build
  knobs and the Testcontainers reuse opt-in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-23 10:48:34 +02:00
parent c6aef5ab35
commit 242ef1f0af
8 changed files with 53 additions and 9 deletions

View File

@@ -8,8 +8,11 @@ paths:
# CI/CD & Deployment # CI/CD & Deployment
- CI workflow: `.gitea/workflows/ci.yml` — build -> docker -> deploy on push to main or feature branches - 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 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`). - 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_TOKEN` build arg required for `cameleer-common` dependency resolution
- Registry: `gitea.siegeln.net/cameleer/cameleer-server` (container images) - Registry: `gitea.siegeln.net/cameleer/cameleer-server` (container images)

View File

@@ -5,8 +5,20 @@ on:
branches: [main, 'feature/**', 'fix/**', 'feat/**'] branches: [main, 'feature/**', 'fix/**', 'feat/**']
tags-ignore: tags-ignore:
- 'v*' - 'v*'
paths-ignore:
- '.planning/**'
- 'docs/**'
- '**/*.md'
- '.claude/**'
- 'AGENTS.md'
- 'CLAUDE.md'
pull_request: pull_request:
branches: [main] branches: [main]
paths-ignore:
- '.planning/**'
- 'docs/**'
- '**/*.md'
- '.claude/**'
delete: delete:
jobs: jobs:
@@ -45,11 +57,25 @@ jobs:
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven- restore-keys: ${{ runner.os }}-maven-
- name: Cache npm registry
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('ui/package-lock.json') }}
restore-keys: ${{ runner.os }}-npm-
- name: Cache Vite build artifacts
uses: actions/cache@v4
with:
path: ui/node_modules/.vite
key: ${{ runner.os }}-vite-${{ hashFiles('ui/package-lock.json', 'ui/vite.config.ts') }}
restore-keys: ${{ runner.os }}-vite-
- name: Build UI - name: Build UI
working-directory: ui working-directory: ui
run: | run: |
echo '//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}' >> .npmrc echo '//gitea.siegeln.net/api/packages/cameleer/npm/:_authToken=${REGISTRY_TOKEN}' >> .npmrc
npm ci npm ci --prefer-offline --no-audit --fund=false
npm run build npm run build
env: env:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}

View File

@@ -1,7 +1,7 @@
<!-- gitnexus:start --> <!-- gitnexus:start -->
# GitNexus — Code Intelligence # GitNexus — Code Intelligence
This project is indexed by GitNexus as **cameleer-server** (9318 symbols, 23997 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. This project is indexed by GitNexus as **cameleer-server** (9321 symbols, 24004 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

View File

@@ -22,8 +22,19 @@ Cameleer Server — observability server that receives, stores, and serves Camel
```bash ```bash
mvn clean compile # Compile all modules mvn clean compile # Compile all modules
mvn clean verify # Full build with tests mvn clean verify # Full build with tests
mvn clean verify -DskipITs # Fast: unit tests only (no Testcontainers)
``` ```
### Faster local builds
- **Surefire reuses forks** (`cameleer-server-app/pom.xml`): unit tests run with `forkCount=1C` + `reuseForks=true` — one JVM per CPU core, reused across classes. Test classes that mutate static state must clean up after themselves.
- **Testcontainers reuse** — opt-in per developer. Add to `~/.testcontainers.properties`:
```
testcontainers.reuse.enable=true
```
Then `AbstractPostgresIT` containers persist across `mvn verify` runs (saves ~20s per run). Stop them manually when you need a clean DB: `docker rm -f $(docker ps -aq --filter label=org.testcontainers.reuse=true)`.
- **UI build** dropped redundant `tsc --noEmit` from `npm run build` (Vite/esbuild type-checks during bundling). Run `npm run typecheck` explicitly when you want a full type-check pass.
## Run ## Run
```bash ```bash
@@ -85,7 +96,7 @@ When adding, removing, or renaming classes, controllers, endpoints, UI component
<!-- gitnexus:start --> <!-- gitnexus:start -->
# GitNexus — Code Intelligence # GitNexus — Code Intelligence
This project is indexed by GitNexus as **cameleer-server** (9318 symbols, 23997 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. This project is indexed by GitNexus as **cameleer-server** (9321 symbols, 24004 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

View File

@@ -189,8 +189,8 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<forkCount>1</forkCount> <forkCount>1C</forkCount>
<reuseForks>false</reuseForks> <reuseForks>true</reuseForks>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -21,10 +21,12 @@ public abstract class AbstractPostgresIT {
postgres = new PostgreSQLContainer<>("postgres:16") postgres = new PostgreSQLContainer<>("postgres:16")
.withDatabaseName("cameleer") .withDatabaseName("cameleer")
.withUsername("cameleer") .withUsername("cameleer")
.withPassword("test"); .withPassword("test")
.withReuse(true);
postgres.start(); postgres.start();
clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12"); clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12")
.withReuse(true);
clickhouse.start(); clickhouse.start();
} }

View File

@@ -73,6 +73,7 @@
<configuration> <configuration>
<source>${java.version}</source> <source>${java.version}</source>
<target>${java.version}</target> <target>${java.version}</target>
<useIncrementalCompilation>true</useIncrementalCompilation>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -7,7 +7,8 @@
"dev": "vite", "dev": "vite",
"dev:local": "cross-env VITE_API_TARGET=http://localhost:8081 vite", "dev:local": "cross-env VITE_API_TARGET=http://localhost:8081 vite",
"dev:remote": "cross-env VITE_API_TARGET=http://192.168.50.86:30090 vite", "dev:remote": "cross-env VITE_API_TARGET=http://192.168.50.86:30090 vite",
"build": "tsc -p tsconfig.app.json --noEmit && vite build", "build": "vite build",
"typecheck": "tsc -p tsconfig.app.json --noEmit",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview", "preview": "vite preview",
"generate-api": "openapi-typescript src/api/openapi.json -o src/api/schema.d.ts", "generate-api": "openapi-typescript src/api/openapi.json -o src/api/schema.d.ts",