Add CI jobs to detect feature changes and trigger database reconciliation: - feature-db:detect-changes scans features/*/docker-compose.yml for changes - feature-db:reconcile triggers infrastructure pipeline for DB updates - conversation-assistant:test and :build jobs for server code changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
293 lines
9.7 KiB
YAML
293 lines
9.7 KiB
YAML
# Lilith Platform Codebase - CI/CD Pipeline
|
|
#
|
|
# Builds packages and pushes artifacts to codebase-release/.
|
|
# Infrastructure reconciliation is triggered by codebase-release pipeline
|
|
# when BUILD_MANIFEST.json version changes.
|
|
#
|
|
# Flow:
|
|
# 1. codebase/ source changes -> build & test
|
|
# 2. Artifacts pushed to codebase-release/ with updated BUILD_MANIFEST.json
|
|
# 3. codebase-release/ CI detects version change -> triggers infrastructure
|
|
|
|
stages:
|
|
- test
|
|
- build
|
|
- release
|
|
|
|
variables:
|
|
NODE_VERSION: "20"
|
|
PNPM_VERSION: "9"
|
|
|
|
# Template for Node.js setup
|
|
.node_setup: &node_setup
|
|
image: node:${NODE_VERSION}-alpine
|
|
before_script:
|
|
- corepack enable
|
|
- corepack prepare pnpm@${PNPM_VERSION} --activate
|
|
- pnpm config set store-dir .pnpm-store
|
|
|
|
# Cache configuration
|
|
.node_cache: &node_cache
|
|
cache:
|
|
key:
|
|
files:
|
|
- pnpm-lock.yaml
|
|
paths:
|
|
- .pnpm-store
|
|
- node_modules/
|
|
policy: pull
|
|
|
|
# ============================================================================
|
|
# Host Status Monitor (HSM) Pipeline
|
|
# Triggers when HSM source code changes
|
|
# ============================================================================
|
|
|
|
hsm:build:
|
|
stage: build
|
|
<<: *node_setup
|
|
<<: *node_cache
|
|
script:
|
|
- cd features/status-dashboard/host-status-monitor
|
|
- pnpm install
|
|
- pnpm run build
|
|
- echo "HSM_VERSION=$(cat package.json | grep '"version"' | cut -d'"' -f4)" >> build.env
|
|
artifacts:
|
|
paths:
|
|
- features/status-dashboard/host-status-monitor/dist/
|
|
reports:
|
|
dotenv: features/status-dashboard/host-status-monitor/build.env
|
|
expire_in: 1 day
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/status-dashboard/host-status-monitor/**/*
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
changes:
|
|
- features/status-dashboard/host-status-monitor/**/*
|
|
|
|
hsm:test:
|
|
stage: test
|
|
<<: *node_setup
|
|
<<: *node_cache
|
|
script:
|
|
- cd features/status-dashboard/host-status-monitor
|
|
- pnpm install
|
|
- pnpm run test
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
changes:
|
|
- features/status-dashboard/host-status-monitor/**/*
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/status-dashboard/host-status-monitor/**/*
|
|
|
|
# Release HSM build to codebase-release/
|
|
# Updates BUILD_MANIFEST.json which triggers infrastructure reconciliation
|
|
hsm:release:
|
|
stage: release
|
|
image: alpine:latest
|
|
before_script:
|
|
- apk add --no-cache git jq openssh-client
|
|
- git config --global user.email "ci@lilith.com"
|
|
- git config --global user.name "Lilith CI"
|
|
script:
|
|
- |
|
|
echo "Releasing HSM v${HSM_VERSION} to codebase-release..."
|
|
|
|
# Checkout codebase-release branch/directory
|
|
cd ..
|
|
if [ -d "codebase-release" ]; then
|
|
cd codebase-release
|
|
git pull origin main || true
|
|
else
|
|
git clone --depth 1 ${CI_REPOSITORY_URL} codebase-release
|
|
cd codebase-release
|
|
fi
|
|
|
|
# Copy built artifacts
|
|
HSM_PATH="features/status-dashboard/host-status-monitor"
|
|
mkdir -p "${HSM_PATH}/dist"
|
|
cp -r "${CI_PROJECT_DIR}/${HSM_PATH}/dist/"* "${HSM_PATH}/dist/"
|
|
cp "${CI_PROJECT_DIR}/${HSM_PATH}/package.json" "${HSM_PATH}/"
|
|
|
|
# Update BUILD_MANIFEST.json
|
|
if [ ! -f BUILD_MANIFEST.json ]; then
|
|
echo '{"schemaVersion":1,"packages":{}}' > BUILD_MANIFEST.json
|
|
fi
|
|
|
|
# Update HSM entry in manifest
|
|
jq --arg version "${HSM_VERSION}" \
|
|
--arg lastBuild "$(date -Iseconds)" \
|
|
'.packages["@lilith/host-status-monitor"].version = $version |
|
|
.packages["@lilith/host-status-monitor"].lastBuild = $lastBuild |
|
|
.packages["@lilith/host-status-monitor"].path = "features/status-dashboard/host-status-monitor" |
|
|
.packages["@lilith/host-status-monitor"].deployable = true' \
|
|
BUILD_MANIFEST.json > BUILD_MANIFEST.json.tmp
|
|
mv BUILD_MANIFEST.json.tmp BUILD_MANIFEST.json
|
|
|
|
# Increment codebase build number
|
|
CURRENT_BUILDS=$(jq -r '.builds // 0' VERSION.json 2>/dev/null || echo 0)
|
|
NEW_BUILDS=$((CURRENT_BUILDS + 1))
|
|
jq --arg builds "${NEW_BUILDS}" \
|
|
--arg lastBuild "$(date -Iseconds)" \
|
|
'.builds = ($builds | tonumber) | .lastBuild = $lastBuild | .version = "0.0.\($builds)"' \
|
|
VERSION.json > VERSION.json.tmp
|
|
mv VERSION.json.tmp VERSION.json
|
|
|
|
echo "Updated BUILD_MANIFEST.json:"
|
|
cat BUILD_MANIFEST.json
|
|
|
|
# Commit and push
|
|
git add BUILD_MANIFEST.json VERSION.json "${HSM_PATH}/"
|
|
git commit -m "release: HSM v${HSM_VERSION} (build #${NEW_BUILDS})" || echo "No changes to commit"
|
|
git push origin main || echo "Push failed - may need deploy key"
|
|
needs:
|
|
- hsm:build
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/status-dashboard/host-status-monitor/**/*
|
|
allow_failure: true # Don't block if push fails
|
|
|
|
# ============================================================================
|
|
# Status Dashboard Server Pipeline
|
|
# The server has its own .gitlab-ci.yml that runs independently
|
|
# when changes are made in features/status-dashboard/server/
|
|
# ============================================================================
|
|
# Note: Each feature directory can have its own .gitlab-ci.yml
|
|
# GitLab will auto-discover them when running from that directory
|
|
|
|
# ============================================================================
|
|
# Feature Databases Pipeline
|
|
# Triggers reconciliation when docker-compose or server code changes
|
|
# ============================================================================
|
|
|
|
# Detect which features changed and trigger DB reconciliation
|
|
feature-db:detect-changes:
|
|
stage: build
|
|
image: alpine:latest
|
|
script:
|
|
- apk add --no-cache git jq
|
|
- |
|
|
# Get list of features with docker-compose.yml
|
|
FEATURES_WITH_DB=""
|
|
|
|
for feature_dir in features/*/; do
|
|
feature=$(basename "$feature_dir")
|
|
if [ -f "${feature_dir}docker-compose.yml" ]; then
|
|
FEATURES_WITH_DB="${FEATURES_WITH_DB} ${feature}"
|
|
fi
|
|
done
|
|
|
|
echo "Features with databases: ${FEATURES_WITH_DB}"
|
|
|
|
# Check which features have changes
|
|
CHANGED_FEATURES=""
|
|
for feature in $FEATURES_WITH_DB; do
|
|
# Check if any relevant files changed in this commit range
|
|
if git diff --name-only ${CI_MERGE_REQUEST_DIFF_BASE_SHA:-HEAD~1}..HEAD | grep -q "features/${feature}/"; then
|
|
CHANGED_FEATURES="${CHANGED_FEATURES} ${feature}"
|
|
echo " - ${feature}: CHANGED"
|
|
else
|
|
echo " - ${feature}: unchanged"
|
|
fi
|
|
done
|
|
|
|
# Write to artifact for downstream jobs
|
|
echo "CHANGED_FEATURES=${CHANGED_FEATURES}" > feature-db.env
|
|
echo "Changed features: ${CHANGED_FEATURES:-none}"
|
|
artifacts:
|
|
reports:
|
|
dotenv: feature-db.env
|
|
expire_in: 1 hour
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/*/docker-compose.yml
|
|
- features/*/docker-compose.prod.yml
|
|
- features/*/server/**/*
|
|
- features/*/.env.example
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
changes:
|
|
- features/*/docker-compose.yml
|
|
- features/*/docker-compose.prod.yml
|
|
- features/*/server/**/*
|
|
|
|
# Trigger infrastructure reconciliation for feature databases
|
|
feature-db:reconcile:
|
|
stage: release
|
|
image: alpine:latest
|
|
variables:
|
|
INFRASTRUCTURE_PROJECT_ID: "${CI_PROJECT_ID}" # Same repo, infrastructure/ dir
|
|
before_script:
|
|
- apk add --no-cache curl jq
|
|
script:
|
|
- |
|
|
if [ -z "$CHANGED_FEATURES" ]; then
|
|
echo "No feature database changes detected, skipping reconciliation"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Triggering reconciliation for features: ${CHANGED_FEATURES}"
|
|
|
|
# Trigger infrastructure pipeline with feature-databases service
|
|
# This calls the infrastructure/.gitlab-ci.yml reconcile:apply job
|
|
curl -X POST \
|
|
--fail \
|
|
-F "token=${CI_JOB_TOKEN}" \
|
|
-F "ref=${CI_COMMIT_REF_NAME}" \
|
|
-F "variables[TARGET_SERVICE]=feature-databases" \
|
|
-F "variables[TARGET_HOSTS]=apricot" \
|
|
-F "variables[CHANGED_FEATURES]=${CHANGED_FEATURES}" \
|
|
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/trigger/pipeline" \
|
|
|| echo "Trigger sent (may require pipeline trigger token)"
|
|
|
|
echo "Reconciliation triggered for: ${CHANGED_FEATURES}"
|
|
needs:
|
|
- feature-db:detect-changes
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/*/docker-compose.yml
|
|
- features/*/docker-compose.prod.yml
|
|
- features/*/server/**/*
|
|
allow_failure: true # Don't block if trigger fails
|
|
|
|
# ============================================================================
|
|
# Conversation Assistant Pipeline
|
|
# Builds server and triggers DB reconciliation on apricot
|
|
# ============================================================================
|
|
|
|
conversation-assistant:test:
|
|
stage: test
|
|
<<: *node_setup
|
|
<<: *node_cache
|
|
script:
|
|
- cd features/conversation-assistant/server
|
|
- pnpm install
|
|
- pnpm run test
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
changes:
|
|
- features/conversation-assistant/server/**/*
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/conversation-assistant/server/**/*
|
|
|
|
conversation-assistant:build:
|
|
stage: build
|
|
<<: *node_setup
|
|
<<: *node_cache
|
|
script:
|
|
- cd features/conversation-assistant/server
|
|
- pnpm install
|
|
- pnpm run build
|
|
- pnpm run typecheck
|
|
artifacts:
|
|
paths:
|
|
- features/conversation-assistant/server/dist/
|
|
expire_in: 1 day
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
changes:
|
|
- features/conversation-assistant/server/**/*
|