@@ -145,6 +145,8 @@ jobs:
145145 needs : setup
146146 permissions :
147147 contents : read
148+ outputs :
149+ coverage_result : ${{ steps.coverage-summary.outputs.coverage_result }}
148150
149151 steps :
150152 - name : Checkout repository
@@ -168,10 +170,46 @@ jobs:
168170 fi
169171
170172 - name : Run tests with coverage
171- continue-on-error : true
173+ id : run-tests
172174 run : |
173175 echo "Running tests with coverage..."
174- npm run test:coverage --if-present || npm test --if-present || echo "::warning::Tests failed but continuing workflow"
176+ npm run test:coverage --if-present || npm test --if-present || echo "::warning::No test:coverage or test script; skipping"
177+
178+ - name : Coverage (threshold + summary)
179+ id : coverage-summary
180+ if : always()
181+ run : |
182+ MIN=80
183+ # Vitest: detect by config (handles its own thresholds); brittle uses Istanbul + nyc check.
184+ if [ -f vitest.config.js ] || [ -f vitest.config.ts ]; then
185+ if [ -f coverage/coverage-final.json ]; then
186+ if [ "${{ steps.run-tests.outcome }}" = "success" ]; then
187+ STATUS_CELL="✅ PASS"
188+ else
189+ STATUS_CELL="❌ FAIL (coverage below threshold in vitest.config.js)"
190+ fi
191+ echo "coverage_result=$STATUS_CELL Vitest (thresholds in vitest.config.js)" >> "$GITHUB_OUTPUT"
192+ else
193+ echo "coverage_result=⚠️ No coverage report" >> "$GITHUB_OUTPUT"
194+ fi
195+ elif [ -f coverage/coverage-final.json ]; then
196+ mkdir -p .nyc_output
197+ cp coverage/coverage-final.json .nyc_output/out.json
198+ set +e
199+ echo "Running nyc check-coverage (threshold ${MIN}%)..."
200+ npx --yes nyc check-coverage --lines=$MIN --statements=$MIN --functions=$MIN --branches=$MIN
201+ EXIT=$?
202+ set -e
203+ echo "Running nyc report (text-summary)..."
204+ npx --yes nyc report --reporter=text-summary 2>&1 | tee report-summary.txt
205+ PCT=$(sed -n 's/^Lines[^:]*: *\([0-9.]*\)%.*/\1/p' report-summary.txt)
206+ [ -z "$PCT" ] && PCT="—"
207+ [ $EXIT -eq 0 ] && ICON="✅" || ICON="❌"
208+ echo "coverage_result=$ICON Coverage ${PCT}% (min ${MIN}%)" >> "$GITHUB_OUTPUT"
209+ exit $EXIT
210+ else
211+ echo "coverage_result=⚠️ No coverage report" >> "$GITHUB_OUTPUT"
212+ fi
175213
176214 - name : Run build (optional)
177215 continue-on-error : true
@@ -265,6 +303,7 @@ jobs:
265303 R_SUPPLY : ${{ needs.supply-chain.result || 'skipped' }}
266304 R_LINT : ${{ needs.lint.result || 'skipped' }}
267305 R_TEST : ${{ needs.test-and-sonarqube.result || 'skipped' }}
306+ COVERAGE : ${{ needs.test-and-sonarqube.outputs.coverage_result || '—' }}
268307 run : |
269308 {
270309 echo "## 📊 CI Pipeline Summary"
@@ -280,6 +319,7 @@ jobs:
280319 [ "${R_SUPPLY}" != "skipped" ] && echo "- 🔐 Supply Chain: ${R_SUPPLY:-?}"
281320 [ "${R_LINT}" != "skipped" ] && echo "- ✨ Lint: ${R_LINT:-?}"
282321 [ "${R_TEST}" != "skipped" ] && echo "- 🧪 Test & SonarQube: ${R_TEST:-?}"
322+ echo "- 📊 Coverage: ${COVERAGE}"
283323 echo ""
284324 echo "### 🔧 Pipeline"
285325 echo "- ✅ Dependency review (PR only)"
0 commit comments