ci: add teamcity build and deployment entry points

This commit is contained in:
Bastian Wagner
2026-08-17 13:53:01 +02:00
parent ccea4e48ec
commit 2994e46274
7 changed files with 102 additions and 0 deletions

View File

@@ -34,6 +34,20 @@ pnpm test:compose
pnpm build pnpm build
``` ```
## TeamCity deployment scripts
TeamCity invokes repository-owned scripts rather than duplicating deployment logic in step configuration:
```text
scripts/teamcity/validate.sh # install, lint, test, compose-invariant check, build
scripts/teamcity/build-images.sh # build + push immutable IMAGE_TAG images
scripts/teamcity/deploy.sh # pull, migrate, compose up -d, smoke test
scripts/teamcity/smoke.sh # health/root checks against APP_BASE_URL
scripts/teamcity/rollback.sh # redeploy the previous IMAGE_TAG
```
`deploy.sh` never runs `docker compose down` as part of a routine deployment; `rollback.sh` never attempts an automatic database downgrade.
## Production topology ## Production topology
Production Docker Compose (`compose.yml`) publishes **exactly one** host port, on the `edge` (Nginx) service, which serves the built Angular app and reverse-proxies `/api/*` and `/health/*` to the internal `api` service. `api`, `worker`, `postgres`, and `redis` are reachable only over the internal Docker network. See `docs/architecture/deployment.md` for the full contract and `scripts/teamcity/` for the TeamCity-invoked build/deploy/rollback scripts. Production Docker Compose (`compose.yml`) publishes **exactly one** host port, on the `edge` (Nginx) service, which serves the built Angular app and reverse-proxies `/api/*` and `/health/*` to the internal `api` service. `api`, `worker`, `postgres`, and `redis` are reachable only over the internal Docker network. See `docs/architecture/deployment.md` for the full contract and `scripts/teamcity/` for the TeamCity-invoked build/deploy/rollback scripts.

View File

@@ -0,0 +1,8 @@
export function runMigrations(): Promise<void> {
console.log('No migrations configured in Phase 01');
return Promise.resolve();
}
if (require.main === module) {
void runMigrations();
}

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail
: "${REGISTRY:?REGISTRY is required}"
: "${BUILD_NUMBER:?BUILD_NUMBER is required}"
: "${BUILD_VCS_NUMBER:?BUILD_VCS_NUMBER is required}"
IMAGE_TAG="${BUILD_NUMBER}-${BUILD_VCS_NUMBER}"
export IMAGE_TAG
if [[ "$IMAGE_TAG" == "latest" ]]; then
echo "Refusing floating deployment tag" >&2
exit 1
fi
docker build --pull -f docker/edge.Dockerfile -t "${REGISTRY}/travel-edge:${IMAGE_TAG}" .
docker build --pull -f docker/api.Dockerfile -t "${REGISTRY}/travel-api:${IMAGE_TAG}" .
docker build --pull -f docker/worker.Dockerfile -t "${REGISTRY}/travel-worker:${IMAGE_TAG}" .
docker push "${REGISTRY}/travel-edge:${IMAGE_TAG}"
docker push "${REGISTRY}/travel-api:${IMAGE_TAG}"
docker push "${REGISTRY}/travel-worker:${IMAGE_TAG}"
printf '%s\n' "$IMAGE_TAG"

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
: "${IMAGE_TAG:?IMAGE_TAG is required}"
: "${REGISTRY:?REGISTRY is required}"
: "${APP_BASE_URL:?APP_BASE_URL is required}"
exec 9>/var/lock/travel-planner-deploy.lock
flock -n 9 || { echo "Another deployment is already running" >&2; exit 1; }
if [[ -f .deployed-image-tag ]]; then
cp .deployed-image-tag .previous-image-tag
fi
export IMAGE_TAG REGISTRY
docker compose pull edge api worker postgres redis
docker compose up -d postgres redis --wait --wait-timeout 120
docker compose run --rm --no-deps api node backend/dist/apps/api/src/migration.js
docker compose up -d --remove-orphans --wait --wait-timeout 120
scripts/teamcity/smoke.sh
printf '%s\n' "$IMAGE_TAG" > .deployed-image-tag

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
: "${REGISTRY:?REGISTRY is required}"
: "${APP_BASE_URL:?APP_BASE_URL is required}"
if [[ ! -s .previous-image-tag ]]; then
echo "No previous image tag is available for rollback" >&2
exit 1
fi
IMAGE_TAG="$(cat .previous-image-tag)"
export IMAGE_TAG REGISTRY
docker compose pull edge api worker
docker compose up -d --remove-orphans --wait --wait-timeout 120
scripts/teamcity/smoke.sh
printf '%s\n' "$IMAGE_TAG" > .deployed-image-tag

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
: "${APP_BASE_URL:?APP_BASE_URL is required}"
curl --fail --silent --show-error "${APP_BASE_URL}/health/live"
curl --fail --silent --show-error "${APP_BASE_URL}/health/ready"
curl --fail --silent --show-error "${APP_BASE_URL}/" >/dev/null

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
corepack enable || true
pnpm install --frozen-lockfile
pnpm lint
pnpm test
pnpm test:compose
pnpm build