1+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2+ #
3+ # Licensed under the Apache License, Version 2.0 (the "License");
4+ # you may not use this file except in compliance with the License.
5+ # You may obtain a copy of the License at
6+ #
7+ # http://www.apache.org/licenses/LICENSE-2.0
8+ #
9+ # Unless required by applicable law or agreed to in writing, software
10+ # distributed under the License is distributed on an "AS IS" BASIS,
11+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ # See the License for the specific language governing permissions and
13+ # limitations under the License.
14+
15+ name : Coverage Report
16+
17+ on :
18+ workflow_run :
19+ workflows : ["Lint and Test"]
20+ types :
21+ - completed
22+ branches :
23+ - main
24+ - " pull-request/[0-9]+"
25+
26+ permissions :
27+ contents : read # Required for checking out code
28+ actions : write # Required for downloading artifacts
29+ pull-requests : write # Required for coverage report comments
30+
31+ env :
32+ # Go cache settings (specific to this workflow)
33+ GOPATH : /home/runner/go
34+ GOCACHE : /home/runner/.cache/go-build
35+
36+ jobs :
37+ coverage-report :
38+ # Only run on successful completion of lint-test workflow for PR branches
39+ if : github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.event == 'pull_request' || startsWith(github.event.workflow_run.head_branch, 'pull-request/'))
40+ runs-on : linux-amd64-cpu4
41+ timeout-minutes : 15
42+ steps :
43+ - uses : actions/checkout@v4
44+ with :
45+ ref : ${{ github.event.workflow_run.head_sha }}
46+
47+ - name : Download all coverage artifacts from completed workflow
48+ uses : actions/download-artifact@v4
49+ with :
50+ pattern : " *-results"
51+ path : coverage-artifacts
52+ merge-multiple : true
53+ run-id : ${{ github.event.workflow_run.id }}
54+
55+ - name : Consolidate coverage files
56+ run : |
57+ echo "Consolidating coverage files from all components..."
58+ mkdir -p consolidated-coverage
59+
60+ # Find all coverage.txt files and merge them
61+ find coverage-artifacts -name "coverage.txt" -type f | while read -r file; do
62+ echo "Processing: $file"
63+ # Extract the mode line (first line) if it's the first file
64+ if [ ! -f consolidated-coverage/coverage.txt ]; then
65+ head -n 1 "$file" > consolidated-coverage/coverage.txt
66+ fi
67+ # Append coverage data (skip mode line)
68+ tail -n +2 "$file" >> consolidated-coverage/coverage.txt
69+ done
70+
71+ echo "Consolidated coverage file created:"
72+ ls -la consolidated-coverage/
73+ head -n 10 consolidated-coverage/coverage.txt
74+
75+ - name : Upload consolidated coverage
76+ uses : actions/upload-artifact@v4
77+ with :
78+ name : consolidated-code-coverage
79+ path : consolidated-coverage/coverage.txt
80+ retention-days : 30
81+
82+ - name : Extract PR number from branch name
83+ id : pr-number
84+ run : |
85+ if [[ "${{ github.event.workflow_run.head_branch }}" =~ pull-request/([0-9]+) ]]; then
86+ echo "pr_number=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT
87+ else
88+ echo "pr_number=" >> $GITHUB_OUTPUT
89+ fi
90+
91+ - name : Setup Go
92+ uses : actions/setup-go@v5
93+ with :
94+ go-version : ' stable'
95+
96+ - name : Install go-coverage-report CLI tool
97+ run :
go install github.com/fgrosse/go-coverage-report/cmd/[email protected] 98+
99+ - name : Get changed files
100+ uses : tj-actions/changed-files@aa08304bd477b800d468db44fe10f6c61f7f7b11
101+ id : changed-files
102+ with :
103+ write_output_files : true
104+ json : true
105+ files : " **.go"
106+ files_ignore : " vendor/**"
107+ output_dir : .github/outputs
108+
109+ - name : Generate Coverage Report with Fixed PR Number
110+ run : |
111+ set -e # Exit on error
112+
113+ # Download current coverage from the completed workflow
114+ echo "Downloading current coverage from run ${{ github.event.workflow_run.id }}..."
115+ if ! gh run download "${{ github.event.workflow_run.id }}" --name=consolidated-code-coverage --dir=/tmp/current-coverage; then
116+ echo "❌ Failed to download current coverage artifacts"
117+ exit 1
118+ fi
119+
120+ if [[ ! -f /tmp/current-coverage/coverage.txt ]]; then
121+ echo "❌ Current coverage file not found"
122+ exit 1
123+ fi
124+
125+ mv /tmp/current-coverage/coverage.txt .github/outputs/new-coverage.txt
126+
127+ # Download baseline coverage from main (failure here is acceptable)
128+ echo "Downloading baseline coverage..."
129+ LAST_SUCCESSFUL_RUN=$(gh run list --status=success --branch=main --workflow=lint-test.yml --event=push --json=databaseId --limit=1 -q '.[] | .databaseId')
130+
131+ if [[ -n "$LAST_SUCCESSFUL_RUN" ]]; then
132+ echo "Found baseline run: $LAST_SUCCESSFUL_RUN"
133+ if gh run download "$LAST_SUCCESSFUL_RUN" --name=consolidated-code-coverage --dir=/tmp/baseline-coverage 2>/dev/null; then
134+ if [[ -f /tmp/baseline-coverage/coverage.txt ]]; then
135+ echo "✅ Baseline coverage found"
136+ mv /tmp/baseline-coverage/coverage.txt .github/outputs/old-coverage.txt
137+ else
138+ echo "⚠️ Baseline coverage file not found in artifact"
139+ touch .github/outputs/old-coverage.txt # Create empty file
140+ fi
141+ else
142+ echo "⚠️ Failed to download baseline coverage (creating empty baseline)"
143+ touch .github/outputs/old-coverage.txt # Create empty file
144+ fi
145+ else
146+ echo "⚠️ No successful baseline run found (creating empty baseline)"
147+ touch .github/outputs/old-coverage.txt # Create empty file
148+ fi
149+
150+ # Generate the report using fgrosse's CLI tool (same format!)
151+ echo "Generating coverage report..."
152+ if ! go-coverage-report -root=github.com/NVIDIA/nvsentinel \
153+ .github/outputs/old-coverage.txt \
154+ .github/outputs/new-coverage.txt \
155+ .github/outputs/all_modified_files.json > coverage-report.md 2>&1; then
156+ echo "❌ Failed to generate coverage report"
157+ echo "Coverage report output:"
158+ cat coverage-report.md || echo "No output file"
159+ exit 1
160+ fi
161+
162+ if [[ ! -f coverage-report.md || ! -s coverage-report.md ]]; then
163+ echo "❌ Coverage report is empty or missing"
164+ exit 1
165+ fi
166+
167+ echo "✅ Coverage report generated successfully"
168+
169+ # Post comment using our correct PR number
170+ if [[ -n "${{ steps.pr-number.outputs.pr_number }}" ]]; then
171+ echo "Posting coverage comment to PR #${{ steps.pr-number.outputs.pr_number }}..."
172+
173+ # Check for existing coverage comment
174+ EXISTING_COMMENT=$(gh api "repos/${{ github.repository }}/issues/${{ steps.pr-number.outputs.pr_number }}/comments" \
175+ --jq '.[] | select(.user.login=="github-actions[bot]" and (.body | test("Coverage Report|Coverage Δ"))) | .id' \
176+ | head -1 2>/dev/null || echo "")
177+
178+ if [[ -n "$EXISTING_COMMENT" ]]; then
179+ echo "Updating existing comment $EXISTING_COMMENT..."
180+ if ! gh api "repos/${{ github.repository }}/issues/${{ steps.pr-number.outputs.pr_number }}/comments/$EXISTING_COMMENT" \
181+ --method PATCH --input coverage-report.md; then
182+ echo "❌ Failed to update existing coverage comment"
183+ exit 1
184+ fi
185+ else
186+ echo "Creating new comment..."
187+ if ! gh pr comment "${{ steps.pr-number.outputs.pr_number }}" --body-file=coverage-report.md; then
188+ echo "❌ Failed to create coverage comment"
189+ exit 1
190+ fi
191+ fi
192+
193+ echo "✅ Coverage comment posted successfully"
194+ else
195+ echo "⚠️ No PR number found, skipping comment"
196+ fi
197+ env :
198+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
199+
200+ coverage-baseline :
201+ # Only run on successful completion of lint-test workflow for main branch
202+ if : github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main' && github.event.workflow_run.event == 'push'
203+ runs-on : linux-amd64-cpu4
204+ timeout-minutes : 15
205+ steps :
206+ - uses : actions/checkout@v4
207+ with :
208+ ref : ${{ github.event.workflow_run.head_sha }}
209+
210+ - name : Setup Go
211+ uses : actions/setup-go@v5
212+ with :
213+ go-version : ' stable'
214+
215+ - name : Download all coverage artifacts from completed workflow
216+ uses : actions/download-artifact@v4
217+ with :
218+ pattern : " *-results"
219+ path : coverage-artifacts
220+ merge-multiple : true
221+ run-id : ${{ github.event.workflow_run.id }}
222+
223+ - name : Consolidate coverage files
224+ run : |
225+ echo "Consolidating coverage files from all components for baseline..."
226+ mkdir -p consolidated-coverage
227+
228+ # Find all coverage.txt files and merge them
229+ find coverage-artifacts -name "coverage.txt" -type f | while read -r file; do
230+ echo "Processing: $file"
231+ # Extract the mode line (first line) if it's the first file
232+ if [ ! -f consolidated-coverage/coverage.txt ]; then
233+ head -n 1 "$file" > consolidated-coverage/coverage.txt
234+ fi
235+ # Append coverage data (skip mode line)
236+ tail -n +2 "$file" >> consolidated-coverage/coverage.txt
237+ done
238+
239+ echo "Baseline coverage file created:"
240+ ls -la consolidated-coverage/
241+ echo "Total coverage lines: $(wc -l < consolidated-coverage/coverage.txt)"
242+
243+ - name : Upload consolidated coverage baseline
244+ uses : actions/upload-artifact@v4
245+ with :
246+ name : consolidated-code-coverage
247+ path : consolidated-coverage/coverage.txt
248+ retention-days : 90 # Keep baseline longer
0 commit comments