Files
draletaha/.gitea/workflows/ci-cd.yml
T
soroush.asadi e4ad440c15
CI/CD / CI · dotnet build (push) Successful in 24s
CI/CD / Deploy · drsousan (push) Successful in 12s
fix(ci): stop & remove old container before deploying new one
docker compose up --force-recreate only works when Compose owns the
container. If the container was started outside Compose (e.g. manually
via docker restart), Compose can't recreate it and errors with
"container name already in use". Explicitly stopping and removing it
first handles both cases cleanly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-02 01:59:16 +03:30

124 lines
4.4 KiB
YAML

name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: drsousan-cicd-${{ github.ref }}
cancel-in-progress: true
# ─────────────────────────────────────────────────────────────────────────────
# HOW THIS WORKS
# ─────────────────────────────────────────────────────────────────────────────
# Runner labels:
# ubuntu-latest → container runner ← CI dotnet build runs here
# self-hosted → host runner ← docker build/push/deploy runs here
#
# Local Nexus:
# Docker registry → mirror.soroushasadi.com (group: pull | host: push)
# NuGet → 171.22.25.73:8081/repository/nuget-group/
#
# Required Gitea secrets:
# ENV_FILE → contents of .env
# ─────────────────────────────────────────────────────────────────────────────
jobs:
# ── CI: compile-check (runs on every push / PR) ──────────────────────────────
ci:
name: "CI · dotnet build"
runs-on: ubuntu-latest
container:
image: mirror.soroushasadi.com/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: Restore
working-directory: DrSousan.Api
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
run: dotnet restore DrSousan.Api.csproj
- name: Build
working-directory: DrSousan.Api
run: dotnet build DrSousan.Api.csproj --no-restore -c Release
# ── CD: build image → deploy locally (push to main only) ───────────────────
deploy:
name: "Deploy · drsousan"
runs-on: self-hosted
env:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
REGISTRY: mirror.soroushasadi.com
IMAGE: mirror.soroushasadi.com/drsousan/api
needs: [ci]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
timeout-minutes: 20
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 image
run: docker compose build api
env:
DOCKER_BUILDKIT: 1
- name: Deploy
run: |
docker stop drsousan_api 2>/dev/null || true
docker rm drsousan_api 2>/dev/null || true
docker compose up -d --no-deps api
- name: Wait for healthy
run: |
for i in $(seq 1 24); do
STATUS=$(docker inspect --format='{{.State.Health.Status}}' drsousan_api 2>/dev/null || echo "missing")
echo " [$i/24] $STATUS"
[ "$STATUS" = "healthy" ] && echo "✅ drsousan_api healthy" && exit 0
sleep 5
done
echo "❌ timed out"
docker compose logs --tail=60 api
exit 1
- name: Show containers
if: always()
run: docker compose ps
- name: Prune old drsousan images
if: success()
# Only remove untagged (dangling) drsousan images — never touches other projects
run: |
docker images --format '{{.Repository}}:{{.Tag}} {{.ID}}' \
| grep '^mirror\.soroushasadi\.com/drsousan/' \
| grep '<none>' \
| awk '{print $2}' \
| xargs -r docker rmi || true