연금계좌 (22) 및 퇴직연금 (29) 지원 #39
Workflow file for this run
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
| name: Coverage Boost | |
| on: | |
| pull_request: | |
| types: [opened, synchronize] | |
| paths: | |
| - "kis_agent/**/*.py" | |
| - "tests/**/*.py" | |
| workflow_dispatch: | |
| inputs: | |
| target_coverage: | |
| description: "Target coverage percentage" | |
| required: false | |
| default: "100" | |
| env: | |
| PYTHON_VERSION: "3.12" | |
| TARGET_COVERAGE: ${{ github.event.inputs.target_coverage || '100' }} | |
| jobs: | |
| coverage-analysis: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: "pip" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pytest pytest-cov coverage | |
| pip install -e ".[dev]" || pip install -e . | |
| - name: Run coverage analysis | |
| id: coverage | |
| run: | | |
| # Run tests with coverage | |
| pytest tests/ \ | |
| --cov=kis_agent \ | |
| --cov-fail-under="${TARGET_COVERAGE}" \ | |
| --cov-report=json:coverage.json \ | |
| --cov-report=term-missing \ | |
| --timeout=60 \ | |
| --disable-warnings \ | |
| -q --tb=no | |
| # Extract overall coverage | |
| TOTAL_COV=$(python -c "import json; print(json.load(open('coverage.json'))['totals']['percent_covered'])" 2>/dev/null || echo "0") | |
| echo "total_coverage=${TOTAL_COV}" >> $GITHUB_OUTPUT | |
| # Find files below target coverage | |
| python << 'EOF' > low_coverage_files.txt | |
| import json | |
| import sys | |
| TARGET = int("${{ env.TARGET_COVERAGE }}") | |
| try: | |
| with open('coverage.json') as f: | |
| data = json.load(f) | |
| low_coverage = [] | |
| for filepath, info in data.get('files', {}).items(): | |
| if filepath.startswith('kis_agent/'): | |
| pct = info['summary']['percent_covered'] | |
| missing = info['missing_lines'] | |
| if pct < TARGET and missing: | |
| low_coverage.append({ | |
| 'file': filepath, | |
| 'coverage': round(pct, 1), | |
| 'missing_lines': len(missing), | |
| 'missing': missing[:20] # First 20 lines | |
| }) | |
| # Sort by coverage (lowest first) | |
| low_coverage.sort(key=lambda x: x['coverage']) | |
| # Output top 10 files | |
| for item in low_coverage[:10]: | |
| print(f"{item['file']}|{item['coverage']}|{item['missing_lines']}|{','.join(map(str, item['missing']))}") | |
| except Exception as e: | |
| print(f"Error: {e}", file=sys.stderr) | |
| EOF | |
| # Count low coverage files | |
| LOW_COUNT=$(wc -l < low_coverage_files.txt | tr -d ' ') | |
| echo "low_coverage_count=${LOW_COUNT}" >> $GITHUB_OUTPUT | |
| - name: Generate coverage report | |
| id: report | |
| run: | | |
| # Create markdown report | |
| cat << 'EOF' > coverage_report.md | |
| ## 📊 Coverage Analysis Report | |
| | Metric | Value | | |
| |--------|-------| | |
| | **Total Coverage** | ${{ steps.coverage.outputs.total_coverage }}% | | |
| | **Target Coverage** | ${{ env.TARGET_COVERAGE }}% | | |
| | **Files Below Target** | ${{ steps.coverage.outputs.low_coverage_count }} | | |
| EOF | |
| if [ -s low_coverage_files.txt ]; then | |
| echo "### 🔴 Files Requiring Test Coverage" >> coverage_report.md | |
| echo "" >> coverage_report.md | |
| echo "| File | Coverage | Missing Lines | Sample Lines |" >> coverage_report.md | |
| echo "|------|----------|---------------|--------------|" >> coverage_report.md | |
| while IFS='|' read -r file cov missing sample; do | |
| if [ -n "$file" ]; then | |
| echo "| \`$file\` | ${cov}% | $missing | \`$sample\` |" >> coverage_report.md | |
| fi | |
| done < low_coverage_files.txt | |
| echo "" >> coverage_report.md | |
| echo "---" >> coverage_report.md | |
| echo "" >> coverage_report.md | |
| echo "💡 **Tip**: Consider adding tests for these files to improve coverage." >> coverage_report.md | |
| else | |
| echo "✅ All files meet the target coverage of ${{ env.TARGET_COVERAGE }}%!" >> coverage_report.md | |
| fi | |
| cat coverage_report.md | |
| - name: Post coverage comment | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const report = fs.readFileSync('coverage_report.md', 'utf8'); | |
| // Find existing comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number | |
| }); | |
| const botComment = comments.find(c => | |
| c.user.login === 'github-actions[bot]' && | |
| c.body.includes('📊 Coverage Analysis Report') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: report | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: report | |
| }); | |
| } | |
| - name: Upload coverage artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: | | |
| coverage.json | |
| coverage_report.md | |
| low_coverage_files.txt |