Skip to content

CI/CD

This document covers the GitHub Actions and TeamCity pipelines for quant-app.

For how Gradle tasks and JKube manifests are produced, see build-system.md. For Terraform edge and deployment environments, see infrastructure.md.

GitHub Actions

The default workflow lives in .github/workflows/build.yml and runs on pushes and pull requests targeting main.

Resource Caps

The build job sets NODE_OPTIONS=--max-old-space-size=1536 at job scope and writes the following into ~/.gradle/gradle.properties so all Gradle invocations share the same limits:

org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC -Dfile.encoding=UTF-8
kotlin.daemon.jvmargs=-Xmx1536m -XX:+UseParallelGC
org.gradle.workers.max=2

Pipeline Steps

  1. Generate and validate the TeamCity DSL before running Gradle verification tasks.
  2. ./gradlew test allTests — unit tests and KMP allTests.
  3. ./gradlew :backend-recorder:dbIntegrationTest :backend-sync:dbIntegrationTest — database-backed integration tests.
  4. ./gradlew :backend-web-app:serverIntegrationTest
  5. ./gradlew :backend-database:k8sIntegrationTest :backend-sync:k8sIntegrationTest :backend-web-app:k8sIntegrationTest — real-cluster bootstrap tests. Uses CONTAINER_REGISTRY=ghcr.io/timemanx.
  6. Build and push deploy artifacts for backend-app, backend-server, backend-sync, and backend-web-app. Generates Kubernetes resources with CONTAINER_REGISTRY=ghcr.io/timemanx.

On failure, both HTML reports and raw JUnit results are uploaded from **/build/reports/tests/ and **/build/test-results/.

The GitHub-hosted Ubuntu runner already provides Docker for Docker-dependent steps.

TeamCity

DSL lives in .teamcity/. Each TeamCity-managed module has its own subproject and a three-stage pipeline.

Pipeline Stages Per Module

  1. Build Artifacts — runs tests and builds the deployable artifact. JVM application modules publish their fat JARs with an explicit destination path (e.g. +:{module}/build/libs/{module}-all.jar => {module}/build/libs) so TeamCity preserves the directory structure instead of flattening the artifact root. backend-web-app publishes its staged Caddy web root under build/caddy/dist/.
  2. Push Imagesk8sBuild + k8sPush, requires CONTAINER_REGISTRY env var on the agent. Consumes artifacts from stage 1 using their preserved directory structures.
  3. Deploy Staging / Deploy Productionk8sResource + k8sApply, runs on environment-matched agents (env.AGENT_ENV=stg or env.AGENT_ENV=prod).

Project Structure

  • The "All Modules" and "Selective" pipelines remain in the root project.
  • Each module pipeline lives in its own TeamCity subproject declared from .teamcity/settings.kts, with IDs like <ModuleId>_Project and generated config directories like target/generated-configs/RootProjectId_<ModuleId>_Project/.
  • Module project metadata is written to target/generated-configs/RootProjectId_<ModuleId>_Project/project-config.xml.
  • Module build type XML files live under target/generated-configs/RootProjectId_<ModuleId>_Project/buildTypes/.
  • Even inside those subproject directories, build type IDs and XML filenames still use the rooted RootProjectId_* prefix — e.g. RootProjectId_Build_BackendApp.xml, not RootProjectId_BackendApp_Project_Build_BackendApp.xml.

Validation

Run .teamcity/validate-generated-configs.sh after regenerating TeamCity configs to verify key invariants in target/generated-configs, including:

  • agent requirements and deployment environment requirements
  • selective/relay parameter propagation
  • preserved deploy-artifact rule mappings
  • module subproject placement and parent/root wiring in generated project-config.xml
  • the expected rooted build type XML names inside each module subproject directory