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 compose up -d --no-deps --force-recreate 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 '' \ | awk '{print $2}' \ | xargs -r docker rmi || true