ci: add missing admin-api and admin-web to full CI/CD pipeline

CI now covers all 6 services:
- api-build: Meezi.API dotnet build + test
- admin-api-build: Meezi.Admin.API dotnet build (was missing)
- dashboard-check: web/dashboard tsc
- admin-web-check: web/admin tsc (was missing)
- website-check: web/website tsc (was missing)
- finder-check: web/finder tsc

Deploy now builds and starts all 8 containers:
- Main: postgres, redis, api, web, website, finder
- Admin: admin-api, admin-web (via docker-compose.admin.yml overlay)
- Health checks for both meezi-api and meezi-admin-api

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-05-27 23:53:49 +03:30
parent 64b488ac89
commit 284920544b
+122 -44
View File
@@ -15,8 +15,10 @@ concurrency:
# CI — runs on every push AND every PR # CI — runs on every push AND every PR
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
jobs: jobs:
# ── Main API ────────────────────────────────────────────────────────────────
api-build: api-build:
name: "CI · API (dotnet build)" name: "CI · API (dotnet build + test)"
runs-on: self-hosted runs-on: self-hosted
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -26,16 +28,34 @@ jobs:
with: with:
dotnet-version: "10.0.x" dotnet-version: "10.0.x"
- name: Restore dependencies - name: Restore
run: dotnet restore run: dotnet restore src/Meezi.API/Meezi.API.csproj
- name: Build (Release) - name: Build
run: dotnet build --no-restore -c Release run: dotnet build src/Meezi.API/Meezi.API.csproj --no-restore -c Release
- name: Run tests - name: Test
run: dotnet test --no-build -c Release --logger "console;verbosity=minimal" run: dotnet test --no-build -c Release --logger "console;verbosity=minimal"
# ── Dashboard typecheck ──────────────────────────────────────────────────── # ── Admin API ───────────────────────────────────────────────────────────────
admin-api-build:
name: "CI · Admin API (dotnet build)"
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Setup .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"
- name: Restore
run: dotnet restore src/Meezi.Admin.API/Meezi.Admin.API.csproj
- name: Build
run: dotnet build src/Meezi.Admin.API/Meezi.Admin.API.csproj --no-restore -c Release
# ── Dashboard ───────────────────────────────────────────────────────────────
dashboard-check: dashboard-check:
name: "CI · Dashboard (tsc)" name: "CI · Dashboard (tsc)"
runs-on: self-hosted runs-on: self-hosted
@@ -44,20 +64,49 @@ jobs:
working-directory: web/dashboard working-directory: web/dashboard
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "20" node-version: "20"
- run: npm install --legacy-peer-deps --ignore-scripts
- name: Install dependencies - run: npx tsc --noEmit
run: npm install --legacy-peer-deps --ignore-scripts
- name: TypeScript check
run: npx tsc --noEmit
env: env:
NEXT_PUBLIC_API_URL: http://localhost:5080 NEXT_PUBLIC_API_URL: http://localhost:5080
# ── Finder typecheck ─────────────────────────────────────────────────────── # ── Admin Web ───────────────────────────────────────────────────────────────
admin-web-check:
name: "CI · Admin Web (tsc)"
runs-on: self-hosted
defaults:
run:
working-directory: web/admin
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm install --legacy-peer-deps --ignore-scripts
- run: npx tsc --noEmit
env:
NEXT_PUBLIC_ADMIN_API_URL: http://localhost:5081
# ── Website ─────────────────────────────────────────────────────────────────
website-check:
name: "CI · Website (tsc)"
runs-on: self-hosted
defaults:
run:
working-directory: web/website
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm install --legacy-peer-deps --ignore-scripts
- run: npx tsc --noEmit
env:
MEEZI_API_URL: http://localhost:5080
# ── Finder ──────────────────────────────────────────────────────────────────
finder-check: finder-check:
name: "CI · Finder (tsc)" name: "CI · Finder (tsc)"
runs-on: self-hosted runs-on: self-hosted
@@ -66,77 +115,106 @@ jobs:
working-directory: web/finder working-directory: web/finder
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "20" node-version: "20"
- run: npm install --legacy-peer-deps --ignore-scripts
- name: Install dependencies - run: npx tsc --noEmit
run: npm install --legacy-peer-deps --ignore-scripts
- name: TypeScript check
run: npx tsc --noEmit
env: env:
NEXT_PUBLIC_API_URL: http://localhost:5080 NEXT_PUBLIC_API_URL: http://localhost:5080
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
# DEPLOY — only on push to main, only if all CI jobs pass # DEPLOY — only on push to main, only if ALL CI jobs pass
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
deploy: deploy:
name: "Deploy · docker compose" name: "Deploy · all services"
runs-on: self-hosted runs-on: self-hosted
needs: [api-build, dashboard-check, finder-check] needs:
# Skip deploy on PRs — only run when pushing directly to main - api-build
- admin-api-build
- dashboard-check
- admin-web-check
- website-check
- finder-check
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
timeout-minutes: 30 timeout-minutes: 40
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# Write .env from a single Gitea secret called ENV_FILE # Write .env from Gitea secret
# How to set it: Gitea repo → Settings → Secrets → Add secret # Set it at: Gitea repo → Settings → Secrets → Actions → Add Secret
# Name: ENV_FILE # Name: ENV_FILE
# Value: paste your entire .env file content # Value: your full .env file content
- name: Write .env - name: Write .env
run: printf '%s' "$ENV_FILE" > .env run: printf '%s' "$ENV_FILE" > .env
env: env:
ENV_FILE: ${{ secrets.ENV_FILE }} ENV_FILE: ${{ secrets.ENV_FILE }}
# Build all service images in parallel using BuildKit # ── Build main services ─────────────────────────────────────────────────
- name: Build Docker images - name: Build main images (api, web, website, finder)
run: | run: |
docker compose build --parallel api web website finder docker compose build --parallel api web website finder
env: env:
DOCKER_BUILDKIT: 1 DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1 COMPOSE_DOCKER_CLI_BUILD: 1
# Rolling restart — postgres/redis stay untouched if already healthy # ── Build admin services (separate compose file) ────────────────────────
- name: Start / restart services - name: Build admin images (admin-api, admin-web)
run: |
docker compose \
-f docker-compose.yml \
-f docker-compose.admin.yml \
build --parallel admin-api admin-web
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
# ── Start / restart main services ───────────────────────────────────────
- name: Start main services
run: | run: |
docker compose up -d \ docker compose up -d \
--remove-orphans \ --remove-orphans \
--no-deps \ --no-deps \
postgres redis api web website finder postgres redis api web website finder
# Poll until API container reports healthy (max 2 min) # ── Start / restart admin services ──────────────────────────────────────
- name: Wait for API to become healthy - name: Start admin services
run: | run: |
echo "Waiting for meezi-api to become healthy..." docker compose \
-f docker-compose.yml \
-f docker-compose.admin.yml \
up -d \
--no-deps \
admin-api admin-web
# ── Health checks ────────────────────────────────────────────────────────
- name: Wait for main API healthy
run: |
echo "Waiting for meezi-api..."
for i in $(seq 1 24); do for i in $(seq 1 24); do
STATUS=$(docker inspect --format='{{.State.Health.Status}}' meezi-api 2>/dev/null || echo "missing") STATUS=$(docker inspect --format='{{.State.Health.Status}}' meezi-api 2>/dev/null || echo "missing")
echo " [$i/24] $STATUS" echo " [$i/24] $STATUS"
[ "$STATUS" = "healthy" ] && echo "✅ Healthy" && exit 0 [ "$STATUS" = "healthy" ] && echo "✅ meezi-api healthy" && break
[ "$i" = "24" ] && echo "❌ meezi-api timeout" && docker compose logs --tail=40 api && exit 1
sleep 5 sleep 5
done done
echo "❌ API did not become healthy — last 50 log lines:"
docker compose logs --tail=50 api
exit 1
- name: Show running containers - name: Wait for admin API healthy
run: |
echo "Waiting for meezi-admin-api..."
for i in $(seq 1 24); do
STATUS=$(docker inspect --format='{{.State.Health.Status}}' meezi-admin-api 2>/dev/null || echo "missing")
echo " [$i/24] $STATUS"
[ "$STATUS" = "healthy" ] && echo "✅ meezi-admin-api healthy" && break
[ "$i" = "24" ] && echo "❌ meezi-admin-api timeout" && docker compose -f docker-compose.yml -f docker-compose.admin.yml logs --tail=40 admin-api && exit 1
sleep 5
done
- name: Show all running containers
if: always() if: always()
run: docker compose ps run: docker compose -f docker-compose.yml -f docker-compose.admin.yml ps
# Remove dangling images to keep disk clean
- name: Prune old images - name: Prune old images
if: success() if: success()
run: docker image prune -f run: docker image prune -f