Appearance
Overview
Contributions are currently only possible by curasystems GmbH and all code inside the aeppic monorepo is fully owned by curasystems GmbH. Any contributions when accepted will thus be fully owned by curasystems GmbH.
Build process
The build process is handled via @microsoft/rush
:
Once all dependencies are linked and the environment matches the following command does the build:
node common/scripts/install-run-rush.js build
During development the following command is more helpful:
node common/scripts/install-run-rush.js build:incremental
and if npm i -g @microsoft/rush
was installed before you can shorten that to:
rush build:incremental
Dependencies
The .gitlab-ci.yml
file shows all the other steps that need to be done initially too.
yaml
# Optimized GitLab CI for Rush + PNPM monorepo (Single Runner)
# Key optimizations:
# 1. Single stage to eliminate transition overhead
# 2. Optimized pnpm store caching
# 3. Rush incremental builds
# 4. Efficient cache key strategy
# 5. Early failure detection
default:
image:
name: registry.dev.curasystems.com/aeppic/aeppic-full/ci:1.3.1
entrypoint: [""]
variables:
GIT_DEPTH: "100"
DOCKER_HOST: unix:///var/run/docker.sock
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
CI_REGISTRY: registry.dev.curasystems.com
CI_REGISTRY_IMAGE: $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
SERVER_REGISTRY_IMAGE: $CI_REGISTRY_IMAGE/server
SERVER_CONTAINER_TAG_BRANCH: $SERVER_REGISTRY_IMAGE:$CI_COMMIT_BRANCH
SERVER_CONTAINER_TAG_LATEST: $SERVER_REGISTRY_IMAGE:latest
SERVER_CONTAINER_TAG: $SERVER_CONTAINER_TAG_BRANCH
DOCS_REGISTRY_IMAGE: $CI_REGISTRY_IMAGE/docs
DOCS_CONTAINER_TAG_BRANCH: $DOCS_REGISTRY_IMAGE:$CI_COMMIT_BRANCH
DOCS_CONTAINER_TAG_LATEST: $DOCS_REGISTRY_IMAGE:latest
DOCS_CONTAINER_TAG: $DOCS_CONTAINER_TAG_BRANCH
# Enable Rush build cache for faster incremental builds
RUSH_BUILD_CACHE_ENABLED: "1"
NODE_ENV: development
# Optimized cache strategy - fewer, more targeted caches
cache:
key:
files:
- "rush.json"
- "common/config/rush/pnpm-lock.yaml"
prefix: "rush-optimized-v5"
paths:
# PNPM store (most important for speed)
- "common/temp/pnpm-store/"
# Rush install cache
- "common/temp/install-run/"
# Rush build cache (incremental builds)
- "common/temp/build-cache/"
# Built outputs (avoid rebuilding unchanged packages)
- "*/*/dist/"
- "*/*/types/"
policy: pull-push
when: always
before_script:
- git config --global user.email "dev-ci@curasystems.de"
- git config --global user.name "Curasystems Dev-CI"
- if [ "$CI_COMMIT_BRANCH" == "master" ] || [ "$CI_COMMIT_BRANCH" == "main" ]; then git remote set-url origin "https://continuous-deployment:${CI_GIT_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" && echo "Allow push using token to ${CI_COMMIT_BRANCH}"; fi
- '[ ! -z "$PUBLISH_NPMRC" ] && cp "$PUBLISH_NPMRC" ~/.npmrc'
.exceptions: &default_except
refs:
- tags
variables:
- $CI_COMMIT_MESSAGE =~ /.*\[skip ci\].*/
.tags: &default_tags
- docker
stages:
- build-and-deploy
# Single comprehensive stage for maximum efficiency
build-and-deploy:
stage: build-and-deploy
tags: *default_tags
services:
- docker:dind
except: *default_except
script:
# Early validation (fail fast)
- echo "=== Change Check (Early Fail) ==="
- node common/scripts/install-run-rush.js change -b origin/master -v || (echo "Changes not documented or error finding merge-base" && false)
# Install with optimized caching
- echo "=== Rush Install (Cached) ==="
- echo "Cache status - PNPM store:" && ls -la common/temp/pnpm-store/ 2>/dev/null | wc -l || echo "Empty"
- time node common/scripts/install-run-rush.js install --bypass-policy
# Incremental build (only builds what changed)
- echo "=== Rush Incremental Build ==="
- time node common/scripts/install-run-rush.js build --verbose
# License check
- echo "=== License Check ==="
- node common/scripts/install-run-rush.js check-licenses 2>&1 > licenses.txt
# Tests
- echo "=== Tests ==="
- DEBUG=pw:api node common/scripts/install-run-rush.js test:ci --verbose
# Docker preparation and builds (only if tests pass)
- echo "=== Docker Build Preparation ==="
- echo "Playwright installed at $PLAYWRIGHT_BROWSERS_PATH"
- echo "Installed browsers are:" && ls $PLAYWRIGHT_BROWSERS_PATH 2>/dev/null || echo "None"
- bash build/prepare.sh
- source build/set-version.sh
- if [ "$CI_COMMIT_BRANCH" == "master" ] || [ "$CI_COMMIT_BRANCH" == "main" ]; then echo "Version $VERSION"; fi
# Docker registry login and build
- echo "=== Docker Build and Push ==="
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- if [ "$CI_COMMIT_BRANCH" == "master" ] || [ "$CI_COMMIT_BRANCH" == "main" ]; then export SERVER_CONTAINER_TAG="$SERVER_CONTAINER_TAG_LATEST"; fi
- if [ "$CI_COMMIT_BRANCH" == "master" ] || [ "$CI_COMMIT_BRANCH" == "main" ]; then export DOCS_CONTAINER_TAG="$DOCS_CONTAINER_TAG_LATEST"; fi
- if ! docker buildx ls | grep -q multiplatform_builder; then docker buildx create --name multiplatform_builder --driver docker-container || true; fi
- echo "Building server:" $SERVER_CONTAINER_TAG
- cd server/server && npm run image:build --docker-tag=$SERVER_CONTAINER_TAG && cd ../..
- echo "Building documentation:" $DOCS_CONTAINER_TAG
- cd docs && npm run image:build --docker-tag=$DOCS_CONTAINER_TAG && cd ..
- build/push-versioned-images.sh $VERSION
# Rust build
- echo "=== Rust Build ==="
- cargo build --release
# Release and deployment (master/main only)
- echo "=== Release and Deploy ==="
- bash build/release-packages.sh
- git add docs/src
- git commit -m "Add content in /docs/src [skip ci]" || true
- if [ "$CI_COMMIT_BRANCH" == "master" ] || [ "$CI_COMMIT_BRANCH" == "main" ]; then git push -o ci.skip --tags https://continuous-deployment:${CI_GIT_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git HEAD:$CI_COMMIT_BRANCH; fi
- build/upload-server.sh
- build/upload-tools.sh
- echo "=== Build Complete ==="
- echo "Total packages in pnpm store:" && find common/temp/pnpm-store/ -name "*.tgz" 2>/dev/null | wc -l || echo "0"
after_script:
- mkdir -p npm-logs
- cp -r /root/.npm/_logs npm-logs || true
artifacts:
when: always
expire_in: 1 year
paths:
- licenses.txt
- "*/*/dist/"
- "*/*/release/"
- "*/*/coverage/"
- "*/*/test-results/"
- "target/release/"
- npm-logs
reports:
junit: "*/*/test-results/**/*.xml"
# Security scanning (runs in build-and-deploy stage)
include:
- template: Security/Secret-Detection.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
# Override security job stages to use our single stage
secret_detection:
stage: build-and-deploy
dependency_scanning:
stage: build-and-deploy
Environment
In order to have repeatable builds in the CI environment we use a docker image which is declared in
/ci/Dockerfile
and built with build.sh
next to it. The build.sh
requires a correct version number inside it and the .gitlab-ci.yml
file also needs to reference it. It can only be referenced if it has also been pushed to the build server before of course.
GitLab CI
The .gitlab-ci.yml
file is the main entry point for the CI pipeline. It is used to define the stages and jobs that are run in the CI pipeline. The pipeline is triggered on every push to the repository and on every merge request. Each successful build will also create an image in the Gitlab repository based on the branch name.
When it is triggered on the main/master branch it will also create a new release. All releases have a docker image pushed to the gitlab registry and a fully built downloadable tgz for use with @aeppic/install-server
.
The default location for releases from the CI pipeline is https://get.aeppic.com where they get automatically tagged as latest
. Releases from that location are used by the aeppic ansible infrastructure to deploy it to the customer servers.