Files
meezi/.gitea/workflows/ci-cd.yml
T
soroush.asadi 8ca2cae988 Pull Docker images from Nexus connector port 8087
The Docker daemon reaches the Nexus Docker group over the dedicated
connector port 8087 (its registry mirror), not the main 8081 HTTP port,
which caused HTTPS-to-HTTP pull failures in CI. Repoint all image refs to
171.22.25.73:8087 at the connector root; npm and NuGet stay on 8081.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 05:17:21 +03:30

357 lines
13 KiB
YAML

name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: meezi-cicd-${{ github.ref }}
cancel-in-progress: true
# ─────────────────────────────────────────────────────────────────────────────
# HOW THIS WORKS
# ─────────────────────────────────────────────────────────────────────────────
# Runner labels (in gitea docker-compose):
# ubuntu-latest:docker://node:20-alpine ← CI jobs run in real Docker containers
# self-hosted:host ← deploy runs directly on the server
#
# All images/packages served from local Nexus at 171.22.25.73:
# Docker images → 171.22.25.73:8087 (docker-group connector: Docker Hub + MCR)
# NuGet → http://171.22.25.73:8081/repository/nuget-group/
# npm → http://171.22.25.73:8081/repository/npm-group/
#
# The runner host is 171.22.25.73, so Nexus is always reachable directly.
# Daemon must have: "insecure-registries": ["171.22.25.73:8087"]
# ─────────────────────────────────────────────────────────────────────────────
jobs:
api-build:
name: "CI · API (dotnet build + test)"
runs-on: ubuntu-latest
container:
image: 171.22.25.73:8087/dotnet/sdk:10.0
options: >-
--add-host=gitea:host-gateway
services:
postgres:
image: 171.22.25.73:8087/postgres:16-alpine
env:
POSTGRES_DB: meezi_test
POSTGRES_USER: meezi
POSTGRES_PASSWORD: meezi_test_pass
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: 171.22.25.73:8087/redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 10
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
REF: ${{ github.ref }}
run: |
git init
git remote add origin "${{ github.server_url }}/${{ github.repository }}.git"
git config http.extraheader "Authorization: Bearer ${TOKEN}"
git fetch --depth=1 origin "${REF}"
git checkout FETCH_HEAD
- name: Write NuGet config
run: |
cat > /tmp/nuget.ci.config << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nexus"
value="http://171.22.25.73:8081/repository/nuget-group/index.json"
protocolVersion="3"
allowInsecureConnections="true" />
</packageSources>
</configuration>
EOF
- name: Restore
run: dotnet restore src/Meezi.API/Meezi.API.csproj --configfile /tmp/nuget.ci.config
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
- name: Build
run: dotnet build src/Meezi.API/Meezi.API.csproj --no-restore -c Release
- name: Test
run: dotnet test --no-build -c Release --logger "console;verbosity=minimal"
env:
ConnectionStrings__DefaultConnection: "Host=postgres;Port=5432;Database=meezi_test;Username=meezi;Password=meezi_test_pass"
ConnectionStrings__Redis: "redis:6379"
admin-api-build:
name: "CI · Admin API (dotnet build)"
runs-on: ubuntu-latest
container:
image: 171.22.25.73:8087/dotnet/sdk:10.0
options: >-
--add-host=gitea:host-gateway
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
REF: ${{ github.ref }}
run: |
git init
git remote add origin "${{ github.server_url }}/${{ github.repository }}.git"
git config http.extraheader "Authorization: Bearer ${TOKEN}"
git fetch --depth=1 origin "${REF}"
git checkout FETCH_HEAD
- name: Write NuGet config
run: |
cat > /tmp/nuget.ci.config << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nexus"
value="http://171.22.25.73:8081/repository/nuget-group/index.json"
protocolVersion="3"
allowInsecureConnections="true" />
</packageSources>
</configuration>
EOF
- name: Restore
run: dotnet restore src/Meezi.Admin.API/Meezi.Admin.API.csproj --configfile /tmp/nuget.ci.config
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
- name: Build
run: dotnet build src/Meezi.Admin.API/Meezi.Admin.API.csproj --no-restore -c Release
dashboard-check:
name: "CI · Dashboard (tsc)"
runs-on: ubuntu-latest
container:
image: 171.22.25.73:8087/node:20-alpine
options: >-
--add-host=gitea:host-gateway
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
SHA: ${{ github.sha }}
run: |
wget -q \
--header "Authorization: Bearer ${TOKEN}" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/archive/${SHA}.tar.gz" \
-O /tmp/repo.tar.gz
tar -xzf /tmp/repo.tar.gz --strip-components=1
rm -f /tmp/repo.tar.gz
- name: Install dependencies
working-directory: web/dashboard
run: npm install --legacy-peer-deps --ignore-scripts --registry http://171.22.25.73:8081/repository/npm-group/
- name: TypeScript check
working-directory: web/dashboard
run: npx tsc --noEmit
env:
NEXT_PUBLIC_API_URL: http://localhost:5080
admin-web-check:
name: "CI · Admin Web (tsc)"
runs-on: ubuntu-latest
container:
image: 171.22.25.73:8087/node:20-alpine
options: >-
--add-host=gitea:host-gateway
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
SHA: ${{ github.sha }}
run: |
wget -q \
--header "Authorization: Bearer ${TOKEN}" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/archive/${SHA}.tar.gz" \
-O /tmp/repo.tar.gz
tar -xzf /tmp/repo.tar.gz --strip-components=1
rm -f /tmp/repo.tar.gz
- name: Install dependencies
working-directory: web/admin
run: npm install --legacy-peer-deps --ignore-scripts --registry http://171.22.25.73:8081/repository/npm-group/
- name: TypeScript check
working-directory: web/admin
run: npx tsc --noEmit
env:
NEXT_PUBLIC_ADMIN_API_URL: http://localhost:5081
website-check:
name: "CI · Website (tsc)"
runs-on: ubuntu-latest
container:
image: 171.22.25.73:8087/node:20-alpine
options: >-
--add-host=gitea:host-gateway
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
SHA: ${{ github.sha }}
run: |
wget -q \
--header "Authorization: Bearer ${TOKEN}" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/archive/${SHA}.tar.gz" \
-O /tmp/repo.tar.gz
tar -xzf /tmp/repo.tar.gz --strip-components=1
rm -f /tmp/repo.tar.gz
- name: Install dependencies
working-directory: web/website
run: npm install --legacy-peer-deps --ignore-scripts --registry http://171.22.25.73:8081/repository/npm-group/
- name: TypeScript check
working-directory: web/website
run: npx tsc --noEmit
env:
MEEZI_API_URL: http://localhost:5080
koja-check:
name: "CI · Koja (tsc)"
runs-on: ubuntu-latest
container:
image: 171.22.25.73:8087/node:20-alpine
options: >-
--add-host=gitea:host-gateway
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
SHA: ${{ github.sha }}
run: |
wget -q \
--header "Authorization: Bearer ${TOKEN}" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/archive/${SHA}.tar.gz" \
-O /tmp/repo.tar.gz
tar -xzf /tmp/repo.tar.gz --strip-components=1
rm -f /tmp/repo.tar.gz
- name: Install dependencies
working-directory: web/koja
run: npm install --legacy-peer-deps --ignore-scripts --registry http://171.22.25.73:8081/repository/npm-group/
- name: TypeScript check
working-directory: web/koja
run: npx tsc --noEmit
env:
NEXT_PUBLIC_API_URL: http://localhost:5080
# ─────────────────────────────────────────────────────────────────────────────
# DEPLOY — only on push to main, only if ALL CI jobs pass.
# self-hosted:host — runs directly on your server where Docker is installed.
# ─────────────────────────────────────────────────────────────────────────────
deploy:
name: "Deploy · all services"
runs-on: self-hosted
env:
# act runner (host mode) starts with a minimal PATH — extend it so
# docker (/usr/bin or /usr/local/bin) and snap packages are found.
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
needs:
- api-build
- admin-api-build
- dashboard-check
- admin-web-check
- website-check
- koja-check
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
timeout-minutes: 40
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
REF: ${{ github.ref }}
run: |
git init
git remote add origin "${{ github.server_url }}/${{ github.repository }}.git"
git config http.extraheader "Authorization: Bearer ${TOKEN}"
git fetch --depth=1 origin "${REF}"
git checkout FETCH_HEAD
- name: Write .env
run: printf '%s' "$ENV_FILE" > .env
env:
ENV_FILE: ${{ secrets.ENV_FILE }}
- name: Build main images (api, web, website, koja)
run: docker compose build --parallel api web website koja
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
- 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
- name: Start main services
run: |
docker compose up -d \
--remove-orphans \
--no-deps \
postgres redis api web website koja
- name: Start admin services
run: |
docker compose \
-f docker-compose.yml \
-f docker-compose.admin.yml \
up -d \
--no-deps \
admin-api admin-web
- name: Wait for main API healthy
run: |
for i in $(seq 1 24); do
STATUS=$(docker inspect --format='{{.State.Health.Status}}' meezi-api 2>/dev/null || echo "missing")
echo " [$i/24] $STATUS"
[ "$STATUS" = "healthy" ] && echo "✅ meezi-api healthy" && break
[ "$i" = "24" ] && echo "❌ meezi-api timeout" && docker compose logs --tail=40 api && exit 1
sleep 5
done
- name: Wait for admin API healthy
run: |
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()
run: docker compose -f docker-compose.yml -f docker-compose.admin.yml ps
- name: Prune old images
if: success()
run: docker image prune -f