name: Tests on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] workflow_dispatch: jobs: test: name: Run Tests runs-on: ubuntu-latest strategy: matrix: python-version: ['3.11', '3.12'] steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install pytest pytest-asyncio pytest-cov hypothesis httpx - name: Create necessary directories run: | mkdir -p tests/logs mkdir -p logs - name: Run unit tests run: | pytest tests/unit -v --cov=src --cov-report=xml --cov-report=term -m unit continue-on-error: false - name: Run integration tests run: | pytest tests/integration -v --cov=src --cov-append --cov-report=xml --cov-report=term -m integration continue-on-error: true - name: Run end-to-end tests run: | pytest tests/e2e -v --cov=src --cov-append --cov-report=xml --cov-report=term -m e2e continue-on-error: true - name: Generate coverage report run: | coverage report --fail-under=80 continue-on-error: true - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: file: ./coverage.xml flags: unittests name: codecov-umbrella fail_ci_if_error: false token: ${{ secrets.CODECOV_TOKEN }} - name: Upload coverage artifacts uses: actions/upload-artifact@v4 if: always() with: name: coverage-report-${{ matrix.python-version }} path: | coverage.xml htmlcov/ retention-days: 30 - name: Upload test logs uses: actions/upload-artifact@v4 if: always() with: name: test-logs-${{ matrix.python-version }} path: tests/logs/ retention-days: 7 lint: name: Code Quality runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' - name: Install linting tools run: | python -m pip install --upgrade pip pip install flake8 black isort mypy - name: Run flake8 run: | flake8 src tests --count --select=E9,F63,F7,F82 --show-source --statistics flake8 src tests --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics continue-on-error: true - name: Check code formatting with black run: | black --check src tests continue-on-error: true - name: Check import sorting with isort run: | isort --check-only src tests continue-on-error: true - name: Type checking with mypy run: | mypy src --ignore-missing-imports continue-on-error: true security: name: Security Scan runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install security tools run: | python -m pip install --upgrade pip pip install safety bandit - name: Run safety check run: | pip install -r requirements.txt safety check --json continue-on-error: true - name: Run bandit security scan run: | bandit -r src -f json -o bandit-report.json continue-on-error: true - name: Upload security reports uses: actions/upload-artifact@v4 if: always() with: name: security-reports path: | bandit-report.json retention-days: 30 build-status: name: Build Status runs-on: ubuntu-latest needs: [test, lint, security] if: always() steps: - name: Check build status run: | if [ "${{ needs.test.result }}" == "success" ]; then echo "✅ Tests passed" else echo "❌ Tests failed" exit 1 fi