feat(ci/cd): Gitea Actions + registry + Watchtower auto-update
CI pipeline (.gitea/workflows/ci.yml): - Job lint (ruff), typecheck (mypy mcp_common gating + servizi warn-only), test (pytest 455). - Job build-and-push solo su main: builda gateway + 6 image MCP via docker/build-push-action@v6, login al registry Gitea con docker/login-action@v3 + secrets.GITEA_TOKEN auto-iniettato. - Cache distribuita type=gha per layer Docker → run successivi 5-10x più veloci. Tag :latest + :sha-XXXXXXX per ogni image. Deploy VPS (docker-compose.prod.yml): - Niente build locale: solo `image:` da git.tielogic.xyz/adriano/ cerbero-mcp/<service>:latest. Variabile IMAGE_TAG per pin a sha specifico. - Servizio Watchtower containerizzato che polla ogni 5min (configurabile via WATCHTOWER_POLL_INTERVAL) e auto-aggiorna i container con label com.centurylinklabs.watchtower.enable=true. Auth registry riusa ~/.docker/config.json bind-mounted readonly. DEPLOYMENT.md: runbook completo per setup VPS, login registry, secrets, .env, smoke test post-deploy, rollback (pin a sha), disable auto-update, nota Traefik upload limit. README aggiornato con link. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
REGISTRY: git.tielogic.xyz
|
||||
IMAGE_PREFIX: git.tielogic.xyz/adriano/cerbero-mcp
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: ruff lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
- name: Cache uv
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/uv
|
||||
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
||||
restore-keys: |
|
||||
uv-${{ runner.os }}-
|
||||
|
||||
- name: Install deps
|
||||
run: $HOME/.local/bin/uv sync --frozen --group dev
|
||||
|
||||
- name: Ruff check
|
||||
run: $HOME/.local/bin/uv run ruff check services/
|
||||
|
||||
typecheck:
|
||||
name: mypy mcp_common
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
- name: Cache uv
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/uv
|
||||
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
||||
|
||||
- name: Install deps
|
||||
run: $HOME/.local/bin/uv sync --frozen --group dev
|
||||
|
||||
- name: Mypy on mcp_common (gating)
|
||||
run: $HOME/.local/bin/uv run mypy services/common/src/mcp_common
|
||||
|
||||
- name: Mypy on services (warn-only)
|
||||
run: $HOME/.local/bin/uv run mypy services/ || true
|
||||
|
||||
test:
|
||||
name: pytest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
- name: Cache uv
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/uv
|
||||
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
||||
|
||||
- name: Install deps
|
||||
run: $HOME/.local/bin/uv sync --frozen --group dev
|
||||
|
||||
- name: Pytest full suite
|
||||
run: $HOME/.local/bin/uv run pytest services/ -v --tb=short
|
||||
|
||||
build-and-push:
|
||||
name: build & push to registry
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, test]
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Gitea registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- name: Compute short SHA
|
||||
id: meta
|
||||
run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build base image (cache only, not pushed)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/base.Dockerfile
|
||||
tags: cerbero-base:latest
|
||||
load: true
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push gateway
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./gateway
|
||||
file: gateway/Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/gateway:latest
|
||||
${{ env.IMAGE_PREFIX }}/gateway:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push mcp-deribit
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/mcp-deribit.Dockerfile
|
||||
build-args: BASE_TAG=latest
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/mcp-deribit:latest
|
||||
${{ env.IMAGE_PREFIX }}/mcp-deribit:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push mcp-bybit
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/mcp-bybit.Dockerfile
|
||||
build-args: BASE_TAG=latest
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/mcp-bybit:latest
|
||||
${{ env.IMAGE_PREFIX }}/mcp-bybit:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push mcp-hyperliquid
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/mcp-hyperliquid.Dockerfile
|
||||
build-args: BASE_TAG=latest
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/mcp-hyperliquid:latest
|
||||
${{ env.IMAGE_PREFIX }}/mcp-hyperliquid:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push mcp-alpaca
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/mcp-alpaca.Dockerfile
|
||||
build-args: BASE_TAG=latest
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/mcp-alpaca:latest
|
||||
${{ env.IMAGE_PREFIX }}/mcp-alpaca:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push mcp-macro
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/mcp-macro.Dockerfile
|
||||
build-args: BASE_TAG=latest
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/mcp-macro:latest
|
||||
${{ env.IMAGE_PREFIX }}/mcp-macro:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Build & push mcp-sentiment
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/mcp-sentiment.Dockerfile
|
||||
build-args: BASE_TAG=latest
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/mcp-sentiment:latest
|
||||
${{ env.IMAGE_PREFIX }}/mcp-sentiment:sha-${{ steps.meta.outputs.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
Reference in New Issue
Block a user