Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ef7c7f0
ci: add GitHub Actions workflows for CI, executor validation and depe…
profsergiocosta May 2, 2026
912c10e
fix(ci): resolve invalid hashFiles expression and missing .env errors
profsergiocosta May 2, 2026
1882e21
ci: fix missing .env in test-api and stabilize docker compose cleanup
profsergiocosta May 2, 2026
b51f09f
fix(ci): prevent invalid port errors during docker compose up
profsergiocosta May 2, 2026
9e299f1
ci: fix Python indentation in worker inline test script
profsergiocosta May 2, 2026
d322a5a
ci: fix YAML syntax and improve Python inline script execution
profsergiocosta May 2, 2026
41c2b55
ci: fix YAML syntax and improve Python inline script execution
profsergiocosta May 2, 2026
bb9a7b3
ci: fix YAML syntax and improve Python inline script execution
profsergiocosta May 2, 2026
56d3d72
fix(ci): correct PYTHONPATH for worker executor contract validation
profsergiocosta May 2, 2026
5cb5b3f
> fix(worker): correct package structure for executor validation
profsergiocosta May 2, 2026
ce4ff88
ci: relax executor validation to allow empty registry and improve re…
profsergiocosta May 2, 2026
fcf8d9c
refactor: remove redundant executor logic and unify with dissmodel li…
profsergiocosta May 2, 2026
74d6cbc
refactor: removed executors/init
profsergiocosta May 2, 2026
7182180
ci: automate executor discovery and validation
profsergiocosta May 2, 2026
71dd6f1
Merge pull request #34 from DisSModel/ci-cd
profsergiocosta May 2, 2026
835cc53
removed unused pipelines
profsergiocosta May 3, 2026
a2206ae
Merge pull request #35 from DisSModel/ci-cd
profsergiocosta May 3, 2026
0db150c
update dissmodel version
profsergiocosta May 3, 2026
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
2 changes: 0 additions & 2 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.8'

services:
nginx:
image: nginx:alpine
Expand Down
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.8'

services:
configs-sync:
image: alpine/git
Expand Down
66 changes: 66 additions & 0 deletions scripts/validate_executors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# scripts/validate_executors.py
#
# Valida automaticamente todos os executors na pasta services/worker/executors/
# Não requer imports manuais em __init__.py

import sys
import os
import importlib.util
from pathlib import Path

# Configura o path para encontrar o pacote 'worker'
BASE_DIR = Path(__file__).parent.parent
SERVICES_DIR = BASE_DIR / "services"
sys.path.insert(0, str(SERVICES_DIR))

from dissmodel.executor.testing import ExecutorTestHarness
from dissmodel.executor.registry import ExecutorRegistry

def discover_and_import_executors():
"""Varre a pasta de executors e importa todos os arquivos .py"""
executors_path = SERVICES_DIR / "worker" / "executors"
if not executors_path.exists():
return

for path in executors_path.glob("*.py"):
if path.name in ("__init__.py", "schemas.py", "testing.py"):
continue

# Importa o módulo dinamicamente para disparar o __init_subclass__
module_name = f"worker.executors.{path.stem}"
spec = importlib.util.spec_from_file_location(module_name, path)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
print(f"📦 Carregado: {module_name}")

if __name__ == "__main__":
print("🔍 Iniciando descoberta de executors...")
discover_and_import_executors()

executors = ExecutorRegistry._executors

if not executors:
print("⚠️ Nenhum executor encontrado em services/worker/executors/")
sys.exit(0)

failed = []
print(f"🧪 Validando {len(executors)} executor(es)...\n")

for name, cls in executors.items():
try:
harness = ExecutorTestHarness(cls)
if harness.run_contract_tests():
print(f"✅ {name} passou nos testes de contrato")
else:
print(f"❌ {name} falhou nos testes de contrato")
failed.append(name)
except Exception as e:
print(f"💥 Erro ao testar {name}: {e}")
failed.append(name)

if failed:
print(f"\n❌ Falha na validação de {len(failed)} executor(es).")
sys.exit(1)

print("\n✨ Todos os executors validados com sucesso!")
2 changes: 1 addition & 1 deletion services/api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ requests>=2.31.0,<3.0.0

apscheduler
tomli
dissmodel>=0.4.1
dissmodel>=0.5.0
2 changes: 1 addition & 1 deletion services/frontend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ folium>=0.14.0,<0.16.0
requests>=2.31.0,<3.0.0
python-dotenv>=1.0.0,<2.0.0

dissmodel>=0.4.1
dissmodel>=0.5.0
Empty file added services/worker/__init__.py
Empty file.
Loading
Loading