---
name: easypanel-cicd
description: Configuracao de CI/CD com Gitea Actions para auto-deploy no EasyPanel via webhook — setup de workflows, secrets e validacao.
---

# /easypanel-cicd - CI/CD Gitea Actions para EasyPanel

Configuracao completa de pipelines CI/CD que ligam repositorios Gitea ao EasyPanel para auto-deploy.

---

## Quando usar

- Configurar auto-deploy de um repositorio Gitea para EasyPanel
- Criar workflow Gitea Actions com testes + deploy
- Obter e configurar webhook URL de um servico
- Diagnosticar pipelines CI/CD falhados
- Adicionar CI/CD a projectos existentes no EasyPanel

## Quando nao usar

- Para deploy manual (usar `/easypanel-deploy`)
- Para scaffold de projecto novo (usar `/easypanel-init`)
- Para troubleshooting de containers (usar `/easypanel-troubleshoot`)

---

## Sintaxe

```bash
/easypanel-cicd <repo-name>                    # Setup completo (workflow + secrets + webhook)
/easypanel-cicd <repo-name> --webhook-only      # Apenas obter/configurar webhook
/easypanel-cicd <repo-name> --diagnose          # Diagnosticar pipeline falhado
```

---

## Arquitectura

```
Gitea (push main) --> Gitea Actions Runner --> Testes + Build --> Webhook POST --> EasyPanel Redeploy
                      (3 runners activos)                        (deploy URL)     (build + container)
```

**Componentes:**
- **Gitea Actions Runners:** 3 replicas activas (`descomplicar_gitea-runner`)
- **Webhook URL:** Cada servico EasyPanel tem `deploymentUrl` unico
- **Formato:** `http://<IP>:3000/api/deploy/<service-token>`

---

## Workflow completo

### 1. Obter webhook URL do servico

```bash
TOKEN=$(cat /etc/easypanel/.api-token)

# Via inspectService — campo deploymentUrl
INPUT='{"json":{"projectName":"descomplicar","serviceName":"SERVICE_NAME"}}'
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$INPUT'))")
curl -s "http://localhost:3000/api/trpc/services.app.inspectService?input=$ENCODED" \
  -H "Authorization: Bearer $TOKEN" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['data']['json']['deploymentUrl'])"
```

**Formato da URL:** `http://178.63.18.51:3000/api/deploy/<service-token>`

**Nota:** O token e unico por servico e nao expira. Nao confundir com o API token geral.

### 2. Configurar secret no repositorio Gitea

Via MCP Gitea:
```
mcp__gitea__upsert_repo_action_secret({
  owner: "ealmeida",
  repo: "REPO_NAME",
  secretname: "EASYPANEL_DEPLOY_URL",
  body: { data: "http://178.63.18.51:3000/api/deploy/<service-token>" }
})
```

Secrets adicionais recomendados:
- `EASYPANEL_DEPLOY_URL` — webhook URL (obrigatorio)
- `DEPLOY_DOMAIN` — dominio do servico (opcional, para health check)

### 3. Criar workflow Gitea Actions

Criar `.gitea/workflows/deploy.yml` no repositorio:

#### Template basico (apenas deploy)

```yaml
name: Deploy to EasyPanel

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger EasyPanel Deploy
        run: |
          RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${{ secrets.EASYPANEL_DEPLOY_URL }}")
          if [ "$RESPONSE" != "200" ]; then
            echo "Deploy trigger failed with HTTP $RESPONSE"
            exit 1
          fi
          echo "Deploy triggered successfully"
```

#### Template completo (testes + build + deploy + health check)

```yaml
name: CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint --if-present

      - name: Test
        run: npm test --if-present

      - name: Build
        run: npm run build

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    steps:
      - name: Trigger EasyPanel Deploy
        run: |
          echo "Triggering deploy..."
          RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${{ secrets.EASYPANEL_DEPLOY_URL }}")
          if [ "$RESPONSE" != "200" ]; then
            echo "Deploy trigger failed with HTTP $RESPONSE"
            exit 1
          fi
          echo "Deploy triggered (HTTP $RESPONSE)"

      - name: Wait for deployment
        run: sleep 120

      - name: Health check
        if: ${{ secrets.DEPLOY_DOMAIN != '' }}
        run: |
          for i in 1 2 3 4 5; do
            STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://${{ secrets.DEPLOY_DOMAIN }}/health" || echo "000")
            echo "Health check $i/5: HTTP $STATUS"
            if [ "$STATUS" = "200" ]; then
              echo "Service healthy"
              exit 0
            fi
            sleep 15
          done
          echo "Health check failed after 5 attempts"
          exit 1
```

#### Template Python

```yaml
name: CI/CD Pipeline (Python)

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: pip install -r requirements.txt
      - run: python -m pytest --if-present

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Trigger EasyPanel Deploy
        run: |
          curl -sf -X POST "${{ secrets.EASYPANEL_DEPLOY_URL }}" || exit 1
```

### 4. Commit e push

```bash
git add .gitea/workflows/deploy.yml
git commit -m "ci: add Gitea Actions deploy pipeline"
git push origin main
```

### 5. Validar pipeline

```bash
# Via MCP Gitea — verificar runs
mcp__gitea__list_repo_action_runs({
  owner: "ealmeida",
  repo: "REPO_NAME",
  limit: 5
})
```

Ou verificar logs:
```bash
mcp__gitea__list_repo_action_run_jobs({
  owner: "ealmeida",
  repo: "REPO_NAME",
  run_id: RUN_ID
})
```

---

## Diagnostico (--diagnose)

### Pipeline nao dispara

1. Verificar se o ficheiro esta em `.gitea/workflows/` (nao `.github/workflows/`)
2. Verificar se o branch e `main` (ou o configurado no `on.push.branches`)
3. Verificar se os runners estao activos:
   ```bash
   docker service ls | grep gitea-runner
   # Esperado: 3/3 replicas
   ```

### Webhook falha (HTTP != 200)

1. Verificar se o `deploymentUrl` esta correcto (servico pode ter sido recriado)
2. Verificar se o EasyPanel esta acessivel internamente:
   ```bash
   curl -s http://localhost:3000/api/trpc/projects.listProjects -H "Authorization: Bearer $TOKEN"
   ```
3. Verificar se o token do servico nao mudou (re-obter via inspectService)

### Build falha no EasyPanel

1. Verificar Dockerfile:
   ```bash
   /easypanel-validate
   ```
2. Verificar logs do build:
   ```bash
   /easypanel-troubleshoot SERVICE_NAME
   ```

### Testes falham no runner

1. Verificar logs do job:
   ```bash
   mcp__gitea__get_repo_action_job_log_preview({
     owner: "ealmeida",
     repo: "REPO_NAME",
     job_id: JOB_ID
   })
   ```
2. Verificar se dependencias estao no `package.json`/`requirements.txt`
3. Verificar se env vars de teste estao configuradas

---

## Servicos com CI/CD activo (inventario)

Para listar todos os servicos com source git (candidatos a CI/CD):

```bash
TOKEN=$(cat /etc/easypanel/.api-token)
curl -s "http://localhost:3000/api/trpc/projects.listProjectsAndServices" \
  -H "Authorization: Bearer $TOKEN" \
  | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']['data']['json']
for s in d.get('services',[]):
    src=s.get('source',{}) or {}
    if src.get('type')=='git' and s.get('type')=='app':
        repo=src.get('repo','').split('@')[-1] if '@' in src.get('repo','') else src.get('repo','')
        print(f\"{s['projectName']}/{s['name']} | repo={repo} | ref={src.get('ref','?')}\")
"
```

---

## Checklist de execucao

- [ ] Identificar servico EasyPanel alvo (projectName + serviceName)
- [ ] Obter deploymentUrl via inspectService (SSH ao servidor easy)
- [ ] Criar secret EASYPANEL_DEPLOY_URL no repo Gitea (via MCP)
- [ ] Criar secret DEPLOY_DOMAIN no repo Gitea (opcional, para health check)
- [ ] Criar `.gitea/workflows/deploy.yml` com template adequado
- [ ] Commit e push do workflow
- [ ] Verificar que o primeiro run dispara (list_repo_action_runs)
- [ ] Verificar que o deploy completa no EasyPanel
- [ ] Health check do servico apos deploy

---

## MCPs necessarios

- `ssh-unified` — Acesso ao servidor easy para obter deploymentUrl
- `gitea` — Criar secrets e verificar action runs

---

## Skills relacionadas

| Skill | Quando usar |
|-------|-------------|
| `/easypanel-deploy` | Deploy manual com validacao completa |
| `/easypanel-validate` | Validar projecto antes de configurar CI/CD |
| `/easypanel-init` | Scaffold novo projecto (ja inclui workflow template) |
| `/easypanel-troubleshoot` | Diagnosticar deploy falhado |
| `/easypanel-api` | Referencia API tRPC |

---

*Skill v1.0.0 | 24-03-2026 | Descomplicar(r)*

---

## Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

```jsonl
{"date":"","issue":"","fix":"","source":"user|auto"}
```

*Adicionar nova linha após cada erro corrigido.*
