fix: resolve race conditions and update CI workflows #27
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: 📊 Code Coverage | |
| on: | |
| push: | |
| branches: ["main", "codebase-improvements"] | |
| pull_request: | |
| branches: ["main", "codebase-improvements"] | |
| schedule: | |
| # Run coverage analysis every Sunday at 12:00 PM UTC | |
| - cron: "0 12 * * 0" | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| GO_VERSION: "1.24" | |
| jobs: | |
| # =================================== | |
| # Test Coverage Analysis | |
| # =================================== | |
| coverage: | |
| name: 📊 Coverage Analysis | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: 📂 Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: 🐹 Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: 📥 Download dependencies | |
| run: go mod download | |
| - name: 🧪 Run tests with coverage | |
| run: | | |
| echo "🧪 Running tests with coverage analysis..." | |
| go test -v -coverprofile=coverage.out -covermode=atomic ./... | |
| # Generate coverage report | |
| go tool cover -html=coverage.out -o coverage.html | |
| # Calculate coverage percentage | |
| COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') | |
| echo "COVERAGE_PERCENT=$COVERAGE" >> $GITHUB_ENV | |
| echo "📊 Coverage: ${COVERAGE}%" | |
| - name: 📊 Generate coverage summary | |
| run: | | |
| echo "## 📊 Test Coverage Report" > coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo "**Overall Coverage:** ${COVERAGE_PERCENT}%" >> coverage-summary.md | |
| echo "**Generated:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo "### 📋 Coverage by Package" >> coverage-summary.md | |
| echo "| Package | Coverage |" >> coverage-summary.md | |
| echo "|---------|----------|" >> coverage-summary.md | |
| # Extract per-package coverage | |
| go tool cover -func=coverage.out | grep -v total | while read -r line; do | |
| if [[ $line == *".go:"* ]]; then | |
| package=$(echo "$line" | awk '{print $1}' | sed 's|github.com/M0Rf30/yap/v2/||' | sed 's|/[^/]*\.go:.*||' | sort -u) | |
| coverage=$(echo "$line" | awk '{print $3}') | |
| if [[ -n "$package" && "$package" != "." ]]; then | |
| echo "| $package | $coverage |" >> coverage-summary.md | |
| fi | |
| fi | |
| done || true | |
| echo "" >> coverage-summary.md | |
| # Coverage status | |
| if (( $(echo "$COVERAGE_PERCENT >= 80" | bc -l) )); then | |
| echo "### ✅ Coverage Status: EXCELLENT (≥80%)" >> coverage-summary.md | |
| elif (( $(echo "$COVERAGE_PERCENT >= 70" | bc -l) )); then | |
| echo "### 🟡 Coverage Status: GOOD (≥70%)" >> coverage-summary.md | |
| elif (( $(echo "$COVERAGE_PERCENT >= 60" | bc -l) )); then | |
| echo "### 🟠 Coverage Status: FAIR (≥60%)" >> coverage-summary.md | |
| else | |
| echo "### 🔴 Coverage Status: NEEDS IMPROVEMENT (<60%)" >> coverage-summary.md | |
| fi | |
| - name: 📤 Upload coverage reports | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-reports | |
| path: | | |
| coverage.out | |
| coverage.html | |
| coverage-summary.md | |
| retention-days: 30 | |
| - name: 📊 Upload to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| file: ./coverage.out | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| verbose: true | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| - name: 💬 Comment coverage on PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| if (fs.existsSync('coverage-summary.md')) { | |
| const summary = fs.readFileSync('coverage-summary.md', 'utf8'); | |
| // Look for existing coverage comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| const existingComment = comments.find(comment => | |
| comment.body.includes('📊 Test Coverage Report') && | |
| comment.user.type === 'Bot' | |
| ); | |
| const commentBody = `🤖 **Automated Coverage Report**\n\n${summary}\n\n---\n\n*This comment will be updated with each push to the PR.*`; | |
| if (existingComment) { | |
| await github.rest.issues.updateComment({ | |
| comment_id: existingComment.id, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: commentBody | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: commentBody | |
| }); | |
| } | |
| } | |
| # =================================== | |
| # Coverage Trend Analysis | |
| # =================================== | |
| trend-analysis: | |
| name: 📈 Coverage Trends | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: coverage | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| steps: | |
| - name: 📂 Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: 📥 Download coverage reports | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: coverage-reports | |
| - name: 📈 Analyze coverage trends | |
| run: | | |
| echo "📈 Analyzing coverage trends..." | |
| # Create trends directory if it doesn't exist | |
| mkdir -p .coverage-trends | |
| # Save current coverage to trends file | |
| TIMESTAMP=$(date -u '+%Y-%m-%d %H:%M:%S') | |
| echo "${TIMESTAMP},${COVERAGE_PERCENT}" >> .coverage-trends/coverage-history.csv | |
| # Keep only last 30 entries to avoid file growth | |
| tail -30 .coverage-trends/coverage-history.csv > .coverage-trends/coverage-history.tmp | |
| mv .coverage-trends/coverage-history.tmp .coverage-trends/coverage-history.csv | |
| echo "📊 Coverage trend data updated" | |
| - name: 📝 Generate trend summary | |
| run: | | |
| echo "## 📈 Coverage Trend Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Current Coverage:** ${COVERAGE_PERCENT}%" >> $GITHUB_STEP_SUMMARY | |
| echo "**Analysis Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ -f .coverage-trends/coverage-history.csv ]]; then | |
| echo "### 📊 Recent Coverage History" >> $GITHUB_STEP_SUMMARY | |
| echo "| Date | Coverage |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|----------|" >> $GITHUB_STEP_SUMMARY | |
| tail -10 .coverage-trends/coverage-history.csv | while IFS=',' read -r date coverage; do | |
| echo "| $date | ${coverage}% |" >> $GITHUB_STEP_SUMMARY | |
| done | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🔗 Coverage Resources" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Codecov Dashboard](https://codecov.io/gh/${{ github.repository }})" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Coverage Artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY | |
| # =================================== | |
| # Coverage Quality Gate | |
| # =================================== | |
| quality-gate: | |
| name: 🚪 Coverage Quality Gate | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: coverage | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: 📥 Download coverage reports | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: coverage-reports | |
| - name: 🚪 Check coverage quality gate | |
| run: | | |
| echo "🚪 Checking coverage quality gate..." | |
| # Define minimum coverage threshold | |
| MINIMUM_COVERAGE=60 | |
| echo "📊 Current coverage: ${COVERAGE_PERCENT}%" | |
| echo "🎯 Minimum required: ${MINIMUM_COVERAGE}%" | |
| if (( $(echo "$COVERAGE_PERCENT >= $MINIMUM_COVERAGE" | bc -l) )); then | |
| echo "✅ Coverage quality gate PASSED" | |
| echo "QUALITY_GATE=passed" >> $GITHUB_ENV | |
| exit 0 | |
| else | |
| echo "❌ Coverage quality gate FAILED" | |
| echo "🔍 Coverage is below minimum threshold of ${MINIMUM_COVERAGE}%" | |
| echo "QUALITY_GATE=failed" >> $GITHUB_ENV | |
| exit 1 | |
| fi | |
| - name: 💬 Report quality gate status | |
| if: always() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const status = process.env.QUALITY_GATE; | |
| const coverage = process.env.COVERAGE_PERCENT; | |
| let statusEmoji = ''; | |
| let statusText = ''; | |
| let statusColor = ''; | |
| if (status === 'passed') { | |
| statusEmoji = '✅'; | |
| statusText = 'PASSED'; | |
| statusColor = 'success'; | |
| } else { | |
| statusEmoji = '❌'; | |
| statusText = 'FAILED'; | |
| statusColor = 'failure'; | |
| } | |
| const body = `${statusEmoji} **Coverage Quality Gate ${statusText}** | |
| **Current Coverage:** ${coverage}% | |
| **Minimum Required:** 60% | |
| ${status === 'failed' ? '⚠️ Please add more tests to improve coverage before merging.' : '🎉 Coverage meets quality standards!'}`; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); |