@@ -178,32 +178,58 @@ jobs:
178178 steps :
179179 - uses : actions/checkout@v4
180180
181+ - name : Setup Go
182+ uses : actions/setup-go@v5
183+ with :
184+ go-version : ' stable'
185+
181186 - name : Download all coverage artifacts
182187 uses : actions/download-artifact@v4
183188 with :
184189 pattern : " *-results"
185190 path : coverage-artifacts
186- merge-multiple : true
191+ merge-multiple : false
187192
188193 - name : Consolidate coverage files
189194 run : |
195+ set -e
190196 echo "Consolidating coverage files from all components..."
191197 mkdir -p consolidated-coverage
192198
193- # Find all coverage.txt files and merge them
199+ # Initialize consolidated coverage with mode line
200+ echo "mode: set" > consolidated-coverage/coverage.txt
201+
202+ # Find all coverage.txt files and merge them properly
194203 find coverage-artifacts -name "coverage.txt" -type f | while read -r file; do
195204 echo "Processing: $file"
196- # Extract the mode line (first line) if it's the first file
197- if [ ! -f consolidated-coverage/coverage.txt ]; then
198- head -n 1 "$file" > consolidated-coverage/coverage.txt
205+
206+ # Validate file exists and is not empty
207+ if [[ ! -f "$file" || ! -s "$file" ]]; then
208+ echo "Warning: Skipping empty or missing file: $file"
209+ continue
210+ fi
211+
212+ # Validate coverage file format
213+ if ! head -n 1 "$file" | grep -q "^mode:"; then
214+ echo "Warning: Skipping file with invalid format (no mode line): $file"
215+ continue
199216 fi
200- # Append coverage data (skip mode line)
201- tail -n +2 "$file" >> consolidated-coverage/coverage.txt
217+
218+ # Extract coverage data (skip mode line) and validate each line
219+ tail -n +2 "$file" | while IFS= read -r line; do
220+ # Skip empty lines
221+ [[ -z "$line" ]] && continue
222+
223+ # Validate coverage line format: file.go:start.col,end.col numStmts count
224+ if [[ "$line" =~ ^[^:]+:[0-9]+\.[0-9]+,[0-9]+\.[0-9]+[[:space:]]+[0-9]+[[:space:]]+[0-9]+$ ]]; then
225+ echo "$line" >> consolidated-coverage/coverage.txt
226+ else
227+ echo "Warning: Skipping malformed coverage line: $line"
228+ fi
229+ done
202230 done
203231
204- echo "Consolidated coverage file created:"
205- ls -la consolidated-coverage/
206- head -n 10 consolidated-coverage/coverage.txt
232+ echo "✅ Coverage consolidation completed successfully"
207233
208234 - name : Upload consolidated coverage
209235 uses : actions/upload-artifact@v4
@@ -212,14 +238,124 @@ jobs:
212238 path : consolidated-coverage/coverage.txt
213239 retention-days : 30
214240
215- - name : Generate Go Coverage Report
216- uses : fgrosse/go-coverage-report@8c1d1a09864211d258937b1b1a5b849f7e4f2682 # v1.2.0
241+ - name : Extract PR number from branch name
242+ id : pr-number
243+ run : |
244+ if [[ "${{ github.ref }}" =~ pull-request/([0-9]+) ]]; then
245+ echo "pr_number=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT
246+ else
247+ echo "pr_number=" >> $GITHUB_OUTPUT
248+ fi
249+
250+ - name : Install go-coverage-report CLI tool
251+ run :
go install github.com/fgrosse/go-coverage-report/cmd/[email protected] 252+
253+ - name : Get changed files
254+ uses : tj-actions/changed-files@aa08304bd477b800d468db44fe10f6c61f7f7b11
255+ id : changed-files
217256 with :
218- coverage-artifact-name : " consolidated-code-coverage"
219- coverage-file-name : " coverage.txt"
220- root-package : " github.com/NVIDIA/nvsentinel"
221- skip-comment : false
222- continue-on-error : true # Don't fail if baseline coverage doesn't exist yet
257+ write_output_files : true
258+ json : true
259+ files : " **.go"
260+ files_ignore : " vendor/**"
261+ output_dir : .github/outputs
262+
263+ - name : Generate Coverage Report with Fixed PR Number
264+ run : |
265+ set -e # Exit on error
266+
267+ # Current coverage is already uploaded in this workflow
268+ echo "Downloading current coverage..."
269+ if ! gh run download "${{ github.run_id }}" --name=consolidated-code-coverage --dir=/tmp/current-coverage; then
270+ echo "❌ Failed to download current coverage artifacts"
271+ exit 1
272+ fi
273+
274+ if [[ ! -f /tmp/current-coverage/coverage.txt ]]; then
275+ echo "❌ Current coverage file not found"
276+ exit 1
277+ fi
278+
279+ mv /tmp/current-coverage/coverage.txt .github/outputs/new-coverage.txt
280+
281+ # Download baseline coverage from main (failure here is acceptable)
282+ echo "Downloading baseline coverage..."
283+ LAST_SUCCESSFUL_RUN=$(gh run list --status=success --branch=main --workflow=lint-test.yml --event=push --json=databaseId --limit=1 -q '.[] | .databaseId')
284+
285+ if [[ -n "$LAST_SUCCESSFUL_RUN" ]]; then
286+ echo "Found baseline run: $LAST_SUCCESSFUL_RUN"
287+ if gh run download "$LAST_SUCCESSFUL_RUN" --name=consolidated-code-coverage --dir=/tmp/baseline-coverage 2>/dev/null; then
288+ if [[ -f /tmp/baseline-coverage/coverage.txt ]]; then
289+ echo "✅ Baseline coverage found"
290+ mv /tmp/baseline-coverage/coverage.txt .github/outputs/old-coverage.txt
291+ else
292+ echo "⚠️ Baseline coverage file not found in artifact"
293+ touch .github/outputs/old-coverage.txt # Create empty file
294+ fi
295+ else
296+ echo "⚠️ Failed to download baseline coverage (creating empty baseline)"
297+ touch .github/outputs/old-coverage.txt # Create empty file
298+ fi
299+ else
300+ echo "⚠️ No successful baseline run found (creating empty baseline)"
301+ touch .github/outputs/old-coverage.txt # Create empty file
302+ fi
303+
304+ # Generate the report using fgrosse's CLI tool (same format!)
305+ echo "Generating coverage report..."
306+ if ! go-coverage-report -root=github.com/NVIDIA/nvsentinel \
307+ .github/outputs/old-coverage.txt \
308+ .github/outputs/new-coverage.txt \
309+ .github/outputs/all_modified_files.json > coverage-report.md 2> coverage-report.err; then
310+ echo "❌ Failed to generate coverage report"
311+ exit 1
312+ fi
313+
314+ # Check if report is empty and why
315+ if [[ ! -f coverage-report.md || ! -s coverage-report.md ]]; then
316+ if grep -q "no changed files" coverage-report.err 2>/dev/null; then
317+ echo "ℹ️ No Go files changed - skipping coverage report"
318+ echo "## 📊 Coverage Report\n\nNo Go files were modified in this PR, so no coverage analysis is needed." > coverage-report.md
319+ else
320+ echo "❌ Coverage report is empty or missing for unknown reason"
321+ echo "Error output from go-coverage-report:"
322+ cat coverage-report.err || echo "No error output"
323+ exit 1
324+ fi
325+ fi
326+
327+ echo "✅ Coverage report generated successfully"
328+
329+ # Post comment using our correct PR number
330+ if [[ -n "${{ steps.pr-number.outputs.pr_number }}" ]]; then
331+ echo "Posting coverage comment to PR #${{ steps.pr-number.outputs.pr_number }}..."
332+
333+ # Check for existing coverage comment
334+ EXISTING_COMMENT=$(gh api "repos/${{ github.repository }}/issues/${{ steps.pr-number.outputs.pr_number }}/comments" \
335+ --jq '.[] | select(.user.login=="github-actions[bot]" and (.body | test("Coverage Report|Coverage Δ"))) | .id' \
336+ | head -1 2>/dev/null || echo "")
337+
338+ if [[ -n "$EXISTING_COMMENT" ]]; then
339+ echo "Updating existing comment $EXISTING_COMMENT..."
340+ if ! gh api "repos/${{ github.repository }}/issues/${{ steps.pr-number.outputs.pr_number }}/comments/$EXISTING_COMMENT" \
341+ --method PATCH --input coverage-report.md; then
342+ echo "❌ Failed to update existing coverage comment"
343+ exit 1
344+ fi
345+ else
346+ echo "Creating new comment..."
347+ if ! gh pr comment "${{ steps.pr-number.outputs.pr_number }}" --body-file=coverage-report.md; then
348+ echo "❌ Failed to create coverage comment"
349+ exit 1
350+ fi
351+ fi
352+
353+ echo "✅ Coverage comment posted successfully"
354+ else
355+ echo "⚠️ No PR number found, skipping comment"
356+ fi
357+ env :
358+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
223359
224360 consolidated-coverage-baseline :
225361 if : github.ref == 'refs/heads/main' && github.event_name == 'push'
@@ -234,27 +370,48 @@ jobs:
234370 with :
235371 pattern : " *-results"
236372 path : coverage-artifacts
237- merge-multiple : true
373+ merge-multiple : false
238374
239375 - name : Consolidate coverage files
240376 run : |
377+ set -e
241378 echo "Consolidating coverage files from all components for baseline..."
242379 mkdir -p consolidated-coverage
243380
244- # Find all coverage.txt files and merge them
381+ # Initialize consolidated coverage with mode line
382+ echo "mode: set" > consolidated-coverage/coverage.txt
383+
384+ # Find all coverage.txt files and merge them properly
245385 find coverage-artifacts -name "coverage.txt" -type f | while read -r file; do
246386 echo "Processing: $file"
247- # Extract the mode line (first line) if it's the first file
248- if [ ! -f consolidated-coverage/coverage.txt ]; then
249- head -n 1 "$file" > consolidated-coverage/coverage.txt
387+
388+ # Validate file exists and is not empty
389+ if [[ ! -f "$file" || ! -s "$file" ]]; then
390+ echo "Warning: Skipping empty or missing file: $file"
391+ continue
392+ fi
393+
394+ # Validate coverage file format
395+ if ! head -n 1 "$file" | grep -q "^mode:"; then
396+ echo "Warning: Skipping file with invalid format (no mode line): $file"
397+ continue
250398 fi
251- # Append coverage data (skip mode line)
252- tail -n +2 "$file" >> consolidated-coverage/coverage.txt
399+
400+ # Extract coverage data (skip mode line) and validate each line
401+ tail -n +2 "$file" | while IFS= read -r line; do
402+ # Skip empty lines
403+ [[ -z "$line" ]] && continue
404+
405+ # Validate coverage line format: file.go:start.col,end.col numStmts count
406+ if [[ "$line" =~ ^[^:]+:[0-9]+\.[0-9]+,[0-9]+\.[0-9]+[[:space:]]+[0-9]+[[:space:]]+[0-9]+$ ]]; then
407+ echo "$line" >> consolidated-coverage/coverage.txt
408+ else
409+ echo "Warning: Skipping malformed coverage line: $line"
410+ fi
411+ done
253412 done
254413
255- echo "Baseline coverage file created:"
256- ls -la consolidated-coverage/
257- echo "Total coverage lines: $(wc -l < consolidated-coverage/coverage.txt)"
414+ echo "✅ Coverage consolidation completed successfully"
258415
259416 - name : Upload consolidated coverage baseline
260417 uses : actions/upload-artifact@v4
0 commit comments