From 2e7927797a2b54c783c5df920f58462b9dad6f61 Mon Sep 17 00:00:00 2001 From: VIFEX Date: Wed, 11 Feb 2026 23:36:04 +0800 Subject: [PATCH 1/3] ci: add the coverage rate output to the comment section --- .github/workflows/ci.yml | 135 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc64b97..5e8b44e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -189,8 +189,143 @@ jobs: runs-on: ubuntu-latest needs: [lower-machine, upper-machine] if: always() + permissions: + pull-requests: write + contents: read steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download firmware coverage report + uses: actions/download-artifact@v4 + continue-on-error: true + with: + name: firmware-coverage-report + path: firmware-coverage + + - name: Download WebServer coverage report + uses: actions/download-artifact@v4 + continue-on-error: true + with: + name: coverage-report + path: webserver-coverage + + - name: Generate coverage summary + id: coverage + run: | + echo "=========================================" + echo " Generating Coverage Summary" + echo "=========================================" + + FIRMWARE_COV="N/A" + BACKEND_COV="N/A" + FRONTEND_COV="N/A" + + # Parse firmware coverage from lcov summary + if [ -f "firmware-coverage/coverage.info" ]; then + FIRMWARE_COV=$(lcov --summary firmware-coverage/coverage.info 2>&1 | grep "lines" | grep -oP '\d+\.\d+%' | head -1 || echo "N/A") + elif [ -f "firmware-coverage/coverage_summary.txt" ]; then + FIRMWARE_COV=$(grep -oP 'Line coverage: \K[\d.]+%' firmware-coverage/coverage_summary.txt || echo "N/A") + fi + + # Parse backend Python coverage + if [ -f "webserver-coverage/htmlcov/index.html" ]; then + BACKEND_COV=$(grep -oP 'pc_cov">\K\d+%' webserver-coverage/htmlcov/index.html | head -1 || echo "N/A") + elif [ -f "webserver-coverage/coverage.txt" ]; then + BACKEND_COV=$(grep -oP 'TOTAL.*\K\d+%' webserver-coverage/coverage.txt || echo "N/A") + fi + + # Parse frontend JavaScript coverage + if [ -f "webserver-coverage/coverage/coverage-summary.json" ]; then + FRONTEND_COV=$(jq -r '.total.lines.pct | tostring + "%"' webserver-coverage/coverage/coverage-summary.json 2>/dev/null || echo "N/A") + elif [ -f "webserver-coverage/coverage/index.html" ]; then + FRONTEND_COV=$(grep -oP 'Lines.*?(\d+\.?\d*%)' webserver-coverage/coverage/index.html | grep -oP '\d+\.?\d*%' | head -1 || echo "N/A") + fi + + echo "firmware_cov=$FIRMWARE_COV" >> $GITHUB_OUTPUT + echo "backend_cov=$BACKEND_COV" >> $GITHUB_OUTPUT + echo "frontend_cov=$FRONTEND_COV" >> $GITHUB_OUTPUT + + echo "Firmware Coverage: $FIRMWARE_COV" + echo "Backend Coverage: $BACKEND_COV" + echo "Frontend Coverage: $FRONTEND_COV" + + - name: Post coverage to PR + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const firmwareCov = '${{ steps.coverage.outputs.firmware_cov }}'; + const backendCov = '${{ steps.coverage.outputs.backend_cov }}'; + const frontendCov = '${{ steps.coverage.outputs.frontend_cov }}'; + + const lowerResult = '${{ needs.lower-machine.result }}'; + const upperResult = '${{ needs.upper-machine.result }}'; + + const getStatusEmoji = (result) => result === 'success' ? 'โœ…' : 'โŒ'; + const getCovEmoji = (cov) => { + if (cov === 'N/A') return 'โšช'; + const num = parseFloat(cov); + if (num >= 80) return '๐ŸŸข'; + if (num >= 60) return '๐ŸŸก'; + return '๐Ÿ”ด'; + }; + + const body = `## ๐Ÿ“Š FPBInject CI Coverage Report + + | Component | Status | Coverage | + |-----------|--------|----------| + | Firmware (Lower Machine) | ${getStatusEmoji(lowerResult)} ${lowerResult} | ${getCovEmoji(firmwareCov)} ${firmwareCov} | + | Backend (Python) | ${getStatusEmoji(upperResult)} ${upperResult} | ${getCovEmoji(backendCov)} ${backendCov} | + | Frontend (JavaScript) | ${getStatusEmoji(upperResult)} ${upperResult} | ${getCovEmoji(frontendCov)} ${frontendCov} | + + --- +
+ ๐Ÿ“ Coverage Artifacts + + - ๐Ÿ“ฆ **firmware-coverage-report**: Firmware unit test coverage (lcov) + - ๐Ÿ“ฆ **coverage-report**: WebServer backend & frontend coverage + + Download from the [Actions artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) tab. +
+ + > ๐ŸŽฏ Coverage threshold: **80%** + > ๐Ÿ“… Generated at: ${new Date().toISOString()} + `; + + // Find existing coverage 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(comment => + comment.user.type === 'Bot' && + comment.body.includes('FPBInject CI Coverage Report') + ); + + if (botComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: body + }); + console.log('Updated existing coverage comment'); + } else { + // Create new comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body + }); + console.log('Created new coverage comment'); + } + - name: Check job results run: | echo "=========================================" From 43f4cc056c0a37d62fef77a2f2a4b72cbae9b628 Mon Sep 17 00:00:00 2001 From: VIFEX Date: Wed, 11 Feb 2026 23:58:02 +0800 Subject: [PATCH 2/3] fix coverage parse failed --- .github/workflows/ci.yml | 44 ++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e8b44e..7b5c2c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -218,38 +218,56 @@ jobs: echo " Generating Coverage Summary" echo "=========================================" + # Install lcov for parsing + sudo apt-get update && sudo apt-get install -y lcov + FIRMWARE_COV="N/A" BACKEND_COV="N/A" FRONTEND_COV="N/A" - # Parse firmware coverage from lcov summary + # Debug: Show what files were downloaded + echo "--- Downloaded files ---" + find firmware-coverage webserver-coverage -type f 2>/dev/null || echo "No coverage files found" + echo "------------------------" + + # Parse firmware coverage from lcov if [ -f "firmware-coverage/coverage.info" ]; then - FIRMWARE_COV=$(lcov --summary firmware-coverage/coverage.info 2>&1 | grep "lines" | grep -oP '\d+\.\d+%' | head -1 || echo "N/A") - elif [ -f "firmware-coverage/coverage_summary.txt" ]; then - FIRMWARE_COV=$(grep -oP 'Line coverage: \K[\d.]+%' firmware-coverage/coverage_summary.txt || echo "N/A") + echo "Found firmware-coverage/coverage.info" + FIRMWARE_COV=$(lcov --summary firmware-coverage/coverage.info 2>&1 | grep -E "lines\.*:" | sed -E 's/.*: ([0-9.]+)%.*/\1%/' || echo "N/A") fi - # Parse backend Python coverage + # Parse backend Python coverage from htmlcov if [ -f "webserver-coverage/htmlcov/index.html" ]; then - BACKEND_COV=$(grep -oP 'pc_cov">\K\d+%' webserver-coverage/htmlcov/index.html | head -1 || echo "N/A") - elif [ -f "webserver-coverage/coverage.txt" ]; then - BACKEND_COV=$(grep -oP 'TOTAL.*\K\d+%' webserver-coverage/coverage.txt || echo "N/A") + echo "Found webserver-coverage/htmlcov/index.html" + # Python coverage.py html format: class="pc_cov">XX% + BACKEND_COV=$(grep -oE 'pc_cov">[0-9]+%' webserver-coverage/htmlcov/index.html | head -1 | sed 's/pc_cov">//' || echo "N/A") fi - # Parse frontend JavaScript coverage - if [ -f "webserver-coverage/coverage/coverage-summary.json" ]; then - FRONTEND_COV=$(jq -r '.total.lines.pct | tostring + "%"' webserver-coverage/coverage/coverage-summary.json 2>/dev/null || echo "N/A") + # Parse frontend JavaScript coverage from lcov.info + if [ -f "webserver-coverage/coverage/lcov.info" ]; then + echo "Found webserver-coverage/coverage/lcov.info" + FRONTEND_COV=$(lcov --summary webserver-coverage/coverage/lcov.info 2>&1 | grep -E "lines\.*:" | sed -E 's/.*: ([0-9.]+)%.*/\1%/' || echo "N/A") elif [ -f "webserver-coverage/coverage/index.html" ]; then - FRONTEND_COV=$(grep -oP 'Lines.*?(\d+\.?\d*%)' webserver-coverage/coverage/index.html | grep -oP '\d+\.?\d*%' | head -1 || echo "N/A") + echo "Found webserver-coverage/coverage/index.html (istanbul html)" + # Istanbul html format + FRONTEND_COV=$(grep -oE '[0-9]+\.?[0-9]*%' webserver-coverage/coverage/index.html | head -1 || echo "N/A") + fi + + # Fallback: if still N/A, check if we can extract from any txt or summary files + if [ "$FIRMWARE_COV" = "N/A" ] && [ -f "firmware-coverage/html/index.html" ]; then + FIRMWARE_COV=$(grep -oE '[0-9]+\.?[0-9]*%' firmware-coverage/html/index.html | head -1 || echo "N/A") fi echo "firmware_cov=$FIRMWARE_COV" >> $GITHUB_OUTPUT echo "backend_cov=$BACKEND_COV" >> $GITHUB_OUTPUT echo "frontend_cov=$FRONTEND_COV" >> $GITHUB_OUTPUT + echo "" + echo "=========================================" echo "Firmware Coverage: $FIRMWARE_COV" - echo "Backend Coverage: $BACKEND_COV" + echo "Backend Coverage: $BACKEND_COV" echo "Frontend Coverage: $FRONTEND_COV" + echo "=========================================" - name: Post coverage to PR if: github.event_name == 'pull_request' From 110b9e2147e3d1f301a0cba9ae5b782713d88f98 Mon Sep 17 00:00:00 2001 From: VIFEX Date: Thu, 12 Feb 2026 00:05:59 +0800 Subject: [PATCH 3/3] fix python converage not output --- .github/workflows/ci.yml | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b5c2c5..a7b8f1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,7 +154,7 @@ jobs: working-directory: Tools/WebServer run: | echo "๐Ÿงช Running backend Python tests..." - python tests/run_tests.py --coverage --target 80 + python tests/run_tests.py --coverage --html --target 80 echo "โœ… Backend tests passed!" - name: Install Node.js dependencies @@ -231,31 +231,33 @@ jobs: echo "------------------------" # Parse firmware coverage from lcov - if [ -f "firmware-coverage/coverage.info" ]; then - echo "Found firmware-coverage/coverage.info" - FIRMWARE_COV=$(lcov --summary firmware-coverage/coverage.info 2>&1 | grep -E "lines\.*:" | sed -E 's/.*: ([0-9.]+)%.*/\1%/' || echo "N/A") + FIRMWARE_LCOV=$(find firmware-coverage -name "coverage.info" -type f 2>/dev/null | head -1) + if [ -n "$FIRMWARE_LCOV" ]; then + echo "Found $FIRMWARE_LCOV" + FIRMWARE_COV=$(lcov --summary "$FIRMWARE_LCOV" 2>&1 | grep -E "lines\.*:" | sed -E 's/.*: ([0-9.]+)%.*/\1%/' || echo "N/A") fi - # Parse backend Python coverage from htmlcov - if [ -f "webserver-coverage/htmlcov/index.html" ]; then - echo "Found webserver-coverage/htmlcov/index.html" + # Parse backend Python coverage from htmlcov - search for it dynamically + BACKEND_HTML=$(find webserver-coverage -path "*/htmlcov/index.html" -type f 2>/dev/null | head -1) + if [ -n "$BACKEND_HTML" ]; then + echo "Found $BACKEND_HTML" # Python coverage.py html format: class="pc_cov">XX% - BACKEND_COV=$(grep -oE 'pc_cov">[0-9]+%' webserver-coverage/htmlcov/index.html | head -1 | sed 's/pc_cov">//' || echo "N/A") + BACKEND_COV=$(grep -oE 'pc_cov">[0-9]+%' "$BACKEND_HTML" | head -1 | sed 's/pc_cov">//' || echo "N/A") fi - # Parse frontend JavaScript coverage from lcov.info - if [ -f "webserver-coverage/coverage/lcov.info" ]; then - echo "Found webserver-coverage/coverage/lcov.info" - FRONTEND_COV=$(lcov --summary webserver-coverage/coverage/lcov.info 2>&1 | grep -E "lines\.*:" | sed -E 's/.*: ([0-9.]+)%.*/\1%/' || echo "N/A") - elif [ -f "webserver-coverage/coverage/index.html" ]; then - echo "Found webserver-coverage/coverage/index.html (istanbul html)" - # Istanbul html format - FRONTEND_COV=$(grep -oE '[0-9]+\.?[0-9]*%' webserver-coverage/coverage/index.html | head -1 || echo "N/A") + # Parse frontend JavaScript coverage from lcov.info - search dynamically + FRONTEND_LCOV=$(find webserver-coverage -name "lcov.info" -type f 2>/dev/null | head -1) + if [ -n "$FRONTEND_LCOV" ]; then + echo "Found $FRONTEND_LCOV" + FRONTEND_COV=$(lcov --summary "$FRONTEND_LCOV" 2>&1 | grep -E "lines\.*:" | sed -E 's/.*: ([0-9.]+)%.*/\1%/' || echo "N/A") fi - # Fallback: if still N/A, check if we can extract from any txt or summary files - if [ "$FIRMWARE_COV" = "N/A" ] && [ -f "firmware-coverage/html/index.html" ]; then - FIRMWARE_COV=$(grep -oE '[0-9]+\.?[0-9]*%' firmware-coverage/html/index.html | head -1 || echo "N/A") + # Fallback: if firmware still N/A, try html/index.html + if [ "$FIRMWARE_COV" = "N/A" ]; then + FIRMWARE_HTML=$(find firmware-coverage -name "index.html" -type f 2>/dev/null | head -1) + if [ -n "$FIRMWARE_HTML" ]; then + FIRMWARE_COV=$(grep -oE '[0-9]+\.?[0-9]*%' "$FIRMWARE_HTML" | head -1 || echo "N/A") + fi fi echo "firmware_cov=$FIRMWARE_COV" >> $GITHUB_OUTPUT