chore: move non-essential markdown docs to docs/ #35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # GitHub Actions CI/CD Quality Pipeline | |
| # Generated by BMad TEA Agent - Test Architect Module | |
| # Optimized for: Quality Gates, Coverage Thresholds, Parallel Execution | |
| # Stack: backend (Python) | Framework: pytest | |
| # | |
| # Quality Gates: | |
| # - Lint: ruff check (zero errors) | |
| # - Format: ruff format --check | |
| # - Type: mypy (strict mode) | |
| # - Coverage: fail_under=40 (verified full-suite baseline threshold) | |
| # - Security: bandit, pip-audit | |
| name: Tests | |
| on: | |
| push: | |
| branches: [main, master, develop] | |
| pull_request: | |
| branches: [main, master, develop] | |
| workflow_dispatch: | |
| inputs: | |
| test-markers: | |
| description: 'Pytest markers to filter tests (e.g., "unit", "not slow")' | |
| required: false | |
| default: '' | |
| coverage-threshold: | |
| description: 'Minimum coverage percentage' | |
| required: false | |
| default: '40' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| PYTHON_VERSION_DEFAULT: '3.11' | |
| COVERAGE_THRESHOLD: 40 | |
| jobs: | |
| # ============================================================================ | |
| # STAGE 1: FAST FEEDBACK (< 5 minutes) | |
| # Code quality checks - lint, format, type, security | |
| # ============================================================================ | |
| quality: | |
| name: Quality Gates | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION_DEFAULT }} | |
| cache: pip | |
| - name: Install package + quality tools | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| pip install bandit pip-audit | |
| - name: Ruff lint check | |
| run: ruff check bt_api_py tests --output-format=github | |
| - name: Ruff format check | |
| run: ruff format --check bt_api_py tests | |
| - name: MyPy type check | |
| run: mypy bt_api_py --ignore-missing-imports | |
| - name: Bandit security scan | |
| run: bandit -r bt_api_py -ll --skip B101,B311 | |
| - name: Dependency audit | |
| run: pip-audit || true | |
| continue-on-error: true | |
| # ============================================================================ | |
| # STAGE 2: COMPREHENSIVE TESTING (10-20 minutes) | |
| # Full test suite with coverage reporting | |
| # ============================================================================ | |
| test: | |
| name: Test (Python ${{ matrix.python-version }}, ${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| needs: quality | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest] | |
| python-version: ['3.11'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| - name: Install build tools (Linux) | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update && sudo apt-get install -y build-essential | |
| - name: Install package + dev deps | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Run unit tests | |
| env: | |
| # Security: inputs passed through env: to prevent script injection | |
| TEST_MARKERS: ${{ github.event.inputs.test-markers }} | |
| run: | | |
| # Security: inputs passed through env: to prevent script injection | |
| if [ -n "$TEST_MARKERS" ]; then | |
| pytest tests -v -m "$TEST_MARKERS" \ | |
| -n 8 \ | |
| --dist=loadgroup | |
| else | |
| pytest tests -v -m "unit" \ | |
| -n 8 \ | |
| --dist=loadgroup | |
| fi | |
| - name: Run full test suite with coverage gate | |
| env: | |
| SKIP_LIVE_TESTS: "true" | |
| run: | | |
| pytest tests -v \ | |
| --cov=bt_api_py \ | |
| --cov-report=xml:coverage-full.xml \ | |
| --cov-report=html \ | |
| --cov-report=term-missing \ | |
| --cov-fail-under=${{ github.event.inputs.coverage-threshold || env.COVERAGE_THRESHOLD }} \ | |
| -n 8 \ | |
| --dist=loadgroup | |
| - name: Upload coverage to Codecov | |
| if: always() | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: ./coverage-full.xml | |
| flags: ${{ matrix.os }}-py${{ matrix.python-version }} | |
| fail_ci_if_error: false | |
| verbose: true | |
| - name: Archive coverage report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report-${{ matrix.os }}-py${{ matrix.python-version }} | |
| path: htmlcov/ | |
| retention-days: 30 | |
| - name: Archive test results | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-${{ matrix.os }}-py${{ matrix.python-version }} | |
| path: | | |
| .pytest_cache/ | |
| test-results/ | |
| retention-days: 30 | |
| # ============================================================================ | |
| # STAGE 3: QUALITY GATE ENFORCEMENT | |
| # Ensure coverage threshold is met across all matrix combinations | |
| # ============================================================================ | |
| quality-gate: | |
| name: Quality Gate | |
| runs-on: ubuntu-latest | |
| needs: [quality, test] | |
| if: always() | |
| steps: | |
| - name: Check test results | |
| run: | | |
| if [ "${{ needs.test.result }}" == "failure" ]; then | |
| echo "::error::Tests failed - Quality gate not passed" | |
| exit 1 | |
| fi | |
| echo "✅ All quality gates passed" | |
| - name: Generate summary | |
| run: | | |
| echo "## 🎯 Quality Gate Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Gate | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Lint | ${{ needs.quality.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Tests | ${{ needs.test.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Coverage | ✅ ≥${{ github.event.inputs.coverage-threshold || env.COVERAGE_THRESHOLD }}% |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Required CI platform**: ubuntu-latest" >> $GITHUB_STEP_SUMMARY | |
| echo "**Required CI Python version**: 3.11" >> $GITHUB_STEP_SUMMARY | |
| # ============================================================================ | |
| # BURN-IN: FLAKY TEST DETECTION (scheduled only) | |
| # Runs 5 iterations to detect flaky tests | |
| # ============================================================================ | |
| burn-in: | |
| name: Burn-In (Flaky Detection) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| needs: quality | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION_DEFAULT }} | |
| cache: pip | |
| - name: Install build tools | |
| run: sudo apt-get update && sudo apt-get install -y build-essential | |
| - name: Install package + dev deps | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Run burn-in loop (5 iterations) | |
| env: | |
| SKIP_LIVE_TESTS: "true" | |
| run: | | |
| echo "🔥 Starting burn-in loop - detecting flaky tests" | |
| for i in {1..5}; do | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "🔥 Burn-in iteration $i/5" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| pytest tests -v -m "unit" -n 8 --dist=loadgroup || exit 1 | |
| done | |
| echo "✅ Burn-in complete - no flaky tests detected" | |
| - name: Upload burn-in failure artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: burn-in-failures | |
| path: | | |
| .pytest_cache/ | |
| htmlcov/ | |
| retention-days: 30 | |
| # ============================================================================ | |
| # EXTENSION PATTERNS — Script Injection Prevention | |
| # ============================================================================ | |
| # When extending this template into reusable workflows, manual dispatch | |
| # workflows, or composite actions, NEVER use ${{ inputs.* }} directly in | |
| # run: blocks. Always pass through env: intermediaries. | |
| # | |
| # KEY PRINCIPLE: Inputs must be DATA, not COMMANDS. | |
| # Pass inputs through env: and interpolate as quoted arguments into fixed | |
| # commands. NEVER accept command-shaped inputs (e.g., install-command, | |
| # test-command) that get executed as shell code — even through env:. | |
| # ============================================================================ |