Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
services/worker/executors/ @sergio
.github/ @sergio
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
commit-message:
prefix: "chore(deps):"

- package-ecosystem: "pip"
directory: "/services/api"
schedule:
interval: "weekly"
commit-message:
prefix: "chore(deps):"

- package-ecosystem: "pip"
directory: "/services/worker"
schedule:
interval: "weekly"
commit-message:
prefix: "chore(deps):"
203 changes: 203 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
name: CI

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

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:

lint:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Ruff
run: pip install ruff

- name: Run Lint
run: ruff check services/api/ services/worker/ --exclude __pycache__,*.apagar,*.pyc || true


typecheck:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: pip
- name: Install dependencies
run: |
pip install mypy
pip install -r services/api/requirements.txt
pip install -r services/worker/requirements.txt
- name: Run Mypy
run: |
# Focamos apenas na lógica da API e Worker da plataforma
mypy --ignore-missing-imports services/api/main.py services/worker/worker.py || true


security:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Bandit
run: pip install bandit

- name: Run Bandit
run: bandit -r services/api/ services/worker/ -ll -ii -f txt -o bandit-report.txt || true

- name: Upload Bandit Report
uses: actions/upload-artifact@v4
with:
name: bandit-report
path: bandit-report.txt


test-api:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- name: Create empty .env file
run: touch .env

- name: Start Redis and MinIO
run: docker compose up -d redis minio

- name: Wait for Redis
run: |
for i in $(seq 1 10); do
docker compose exec redis redis-cli ping && break
sleep 3
done

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: pip

- name: Install dependencies
run: |
pip install -r services/api/requirements.txt
pip install pytest

- name: Run API Tests
run: |
if [ -d "services/api/tests/" ]; then
pytest services/api/tests/
else
echo "Aviso: diretório de testes da API não encontrado, continuando..."
fi

- name: Stop services
if: always()
run: docker compose --env-file /dev/null down


test-worker:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- name: Create empty .env file
run: touch .env

- name: Start Redis
run: docker compose up -d redis

- name: Wait for Redis
run: |
for i in $(seq 1 10); do
docker compose exec redis redis-cli ping && break
sleep 3
done

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: pip

- name: Install dependencies
run: |
pip install -r services/worker/requirements.txt
pip install pytest

- name: Run Worker Tests
run: |
if [ -d "services/worker/tests/" ]; then
pytest services/worker/tests/
else
echo "Sem diretório de testes — validando contratos dos executors..."
PYTHONPATH=$PWD/services python3 scripts/validate_executors.py
fi

- name: Stop services
if: always()
run: docker compose --env-file /dev/null down


build-docker:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build API
uses: docker/build-push-action@v5
with:
context: ./services/api
file: ./services/api/Dockerfile
push: false
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build Worker
uses: docker/build-push-action@v5
with:
context: ./services/worker
file: ./services/worker/Dockerfile
push: false
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build Frontend
uses: docker/build-push-action@v5
with:
context: ./services/frontend
file: ./services/frontend/Dockerfile
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
151 changes: 151 additions & 0 deletions .github/workflows/deploy.yml.disabled
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
name: Deploy

# Secrets necessários:
# DEPLOY_HOST → IP ou hostname do servidor
# DEPLOY_USER → usuário SSH
# DEPLOY_SSH_KEY → chave privada SSH (RSA ou Ed25519)
# DEPLOY_PATH → path no servidor (ex: /opt/dissmodel-platform)
# MINIO_ROOT_USER → usado no .env do servidor
# MINIO_ROOT_PASSWORD → usado no .env do servidor
# API_KEYS → chaves de API para o FastAPI

on:
push:
branches:
- main
workflow_dispatch:
inputs:
environment:
description: 'Ambiente para deploy'
required: true
type: choice
options:
- staging
- production

jobs:
build-and-push:
runs-on: ubuntu-latest
outputs:
image_tag: ${{ github.sha }}
steps:
- uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push API
uses: docker/build-push-action@v5
with:
context: ./services/api
file: ./services/api/Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}/api:${{ github.sha }}
ghcr.io/${{ github.repository }}/api:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push Worker
uses: docker/build-push-action@v5
with:
context: ./services/worker
file: ./services/worker/Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}/worker:${{ github.sha }}
ghcr.io/${{ github.repository }}/worker:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push Frontend
uses: docker/build-push-action@v5
with:
context: ./services/frontend
file: ./services/frontend/Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}/frontend:${{ github.sha }}
ghcr.io/${{ github.repository }}/frontend:latest
cache-from: type=gha
cache-to: type=gha,mode=max

deploy-ssh:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
cd ${{ secrets.DEPLOY_PATH }} || exit 1
git pull origin main

sed -i '/^IMAGE_TAG=/d' .env
echo "IMAGE_TAG=${{ github.sha }}" >> .env

sed -i '/^MINIO_ROOT_USER=/d' .env
echo "MINIO_ROOT_USER=${{ secrets.MINIO_ROOT_USER }}" >> .env

sed -i '/^MINIO_ROOT_PASSWORD=/d' .env
echo "MINIO_ROOT_PASSWORD=${{ secrets.MINIO_ROOT_PASSWORD }}" >> .env

sed -i '/^API_KEYS=/d' .env
echo "API_KEYS=${{ secrets.API_KEYS }}" >> .env

docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans

sleep 10

if ! docker compose -f docker-compose.prod.yml exec api curl -f http://localhost:8000/health; then
echo "Healthcheck API falhou, iniciando rollback..."
git checkout HEAD^
PREV_SHA=$(git rev-parse HEAD)
sed -i '/^IMAGE_TAG=/d' .env
echo "IMAGE_TAG=$PREV_SHA" >> .env
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans
exit 1
fi

sleep 30
if [ -f "scripts/health-check.sh" ]; then
bash scripts/health-check.sh || {
echo "Healthcheck completo falhou, iniciando rollback..."
git checkout HEAD^
PREV_SHA=$(git rev-parse HEAD)
sed -i '/^IMAGE_TAG=/d' .env
echo "IMAGE_TAG=$PREV_SHA" >> .env
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans
exit 1
}
fi

notify:
needs: [deploy-ssh]
if: always()
runs-on: ubuntu-latest
steps:
- name: Generate Summary
run: |
echo "## Deploy Summary" >> $GITHUB_STEP_SUMMARY
echo "- **Tag Deployada**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Ambiente**: \`${{ github.event.inputs.environment || 'production' }}\`" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.deploy-ssh.result }}" = "success" ]; then
echo "- **Status**: ✅ Sucesso" >> $GITHUB_STEP_SUMMARY
else
echo "- **Status**: ❌ Falha" >> $GITHUB_STEP_SUMMARY
fi
echo "- **Link para o Run**: [Run #${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
Loading
Loading