name: Automated Testing on: push: branches: [main, develop] paths: - 'scripts/**' - '.github/workflows/test.yml' - 'pyproject.toml' - 'requirements*.txt' pull_request: branches: [main] paths: - 'scripts/**' - '.github/workflows/test.yml' - 'pyproject.toml' - 'requirements*.txt' # Cancel in-progress runs for the same branch concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: pytest: name: Unit Tests (Python ${{ matrix.python-version }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12'] steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 - name: Set up Python ${{ matrix.python-version }} run: uv python install ${{ matrix.python-version }} - name: Create venv and install dependencies run: | uv venv uv pip install -r scripts/requirements-dev.txt - name: Run pytest run: uv run pytest scripts/tests/ -v --tb=short --cov=scripts --cov-report=xml --cov-report=html continue-on-error: false - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: files: ./coverage.xml flags: unittests name: codecov-python-${{ matrix.python-version }} fail_ci_if_error: false verbose: true - name: Archive test results if: always() uses: actions/upload-artifact@v4 with: name: pytest-results-${{ matrix.python-version }} path: | coverage.xml htmlcov/ retention-days: 7 lint: name: Code Quality (Lint & Format) runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 - name: Set up Python run: uv python install 3.11 - name: Create venv and install Ruff run: | uv venv uv pip install ruff - name: Ruff Format Check run: uv run ruff format --check scripts/ - name: Ruff Lint Check run: uv run ruff check scripts/ security: name: Security Scan runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 - name: Set up Python run: uv python install 3.11 - name: Create venv and install Bandit run: | uv venv uv pip install "bandit[toml]" - name: Run Bandit Security Scan run: uv run bandit -c scripts/pyproject.toml -r scripts/ --exclude scripts/tests/ -f json -o bandit-report.json - name: Upload security report uses: actions/upload-artifact@v4 if: always() with: name: bandit-security-report path: bandit-report.json retention-days: 7 type-check: name: Type Checking runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 - name: Set up Python run: uv python install 3.11 - name: Create venv and install mypy run: | uv venv uv pip install -r scripts/requirements-dev.txt mypy - name: Run mypy run: uv run mypy scripts/ --config-file scripts/pyproject.toml build-epub: name: Build EPUB Artifact runs-on: ubuntu-latest needs: [pytest, lint, security, type-check] if: ${{ !failure() && !cancelled() }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 - name: Set up Python run: uv python install 3.11 - name: Create venv and install dependencies run: | uv venv uv pip install -r scripts/requirements-dev.txt - name: Install mmdc (Mermaid CLI) run: npm install -g @mermaid-js/mermaid-cli - name: Build EPUB run: | echo '{"args":["--no-sandbox","--disable-setuid-sandbox"]}' > /tmp/puppeteer-ci.json uv run scripts/build_epub.py --puppeteer-config /tmp/puppeteer-ci.json - name: Verify EPUB Created run: | if [ -f claude-howto-guide.epub ]; then echo "✅ EPUB built successfully" ls -lh claude-howto-guide.epub else echo "❌ EPUB file not found!" exit 1 fi - name: Upload EPUB Artifact uses: actions/upload-artifact@v4 with: name: claude-howto-guide-epub path: claude-howto-guide.epub retention-days: 7 compression-level: 0 summary: name: Test Summary needs: [pytest, lint, security, type-check, build-epub] runs-on: ubuntu-latest if: always() steps: - name: Download all artifacts uses: actions/download-artifact@v4 - name: Generate Summary run: | echo "# Test Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "## Results" >> $GITHUB_STEP_SUMMARY echo "- **Unit Tests**: ${{ needs.pytest.result }}" >> $GITHUB_STEP_SUMMARY echo "- **Code Quality**: ${{ needs.lint.result }}" >> $GITHUB_STEP_SUMMARY echo "- **Security Scan**: ${{ needs.security.result }}" >> $GITHUB_STEP_SUMMARY echo "- **Type Checking**: ${{ needs.type-check.result }}" >> $GITHUB_STEP_SUMMARY echo "- **EPUB Build**: ${{ needs.build-epub.result }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "## Artifacts" >> $GITHUB_STEP_SUMMARY echo "- pytest-results-* (coverage and test results)" >> $GITHUB_STEP_SUMMARY echo "- bandit-security-report (security scan JSON)" >> $GITHUB_STEP_SUMMARY echo "- claude-howto-guide-epub (built EPUB file)" >> $GITHUB_STEP_SUMMARY - name: Check if all tests passed if: | needs.pytest.result != 'success' || needs.build-epub.result != 'success' run: | echo "❌ Critical tests failed" exit 1 - name: All tests passed if: success() run: echo "✅ All tests passed successfully!"