Skip to content

Commit cf7efea

Browse files
committed
[WIP] test codeql and code coverage
Signed-off-by: Davanum Srinivas <[email protected]>
1 parent 0478308 commit cf7efea

File tree

5 files changed

+750
-12
lines changed

5 files changed

+750
-12
lines changed

.github/workflows/code-scanning.yml

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ jobs:
3232
prepare-environment:
3333
uses: ./.github/workflows/prepare-environment.yml
3434

35-
analyze:
36-
name: Analyze Go code with CodeQL
35+
codeql-pr-analysis:
36+
if: startsWith(github.ref, 'refs/heads/pull-request/')
37+
name: CodeQL PR Analysis
3738
runs-on: linux-amd64-cpu4
3839
timeout-minutes: 360
3940
needs: prepare-environment
@@ -57,16 +58,60 @@ jobs:
5758
shellcheck-version: ${{ needs.prepare-environment.outputs.shellcheck_version }}
5859

5960
- name: Initialize CodeQL
60-
uses: github/codeql-action/init@v3
61+
uses: github/codeql-action/init@v4
6162
with:
6263
languages: go
6364
build-mode: manual
6465
env:
6566
CODEQL_EXTRACTOR_GO_BUILD_TRACING: on
66-
- shell: bash
67+
68+
- name: Build with CodeQL
6769
run: |
6870
make build-all
71+
72+
- name: Perform CodeQL Analysis
73+
uses: github/codeql-action/analyze@v4
74+
with:
75+
category: "/language:go"
76+
77+
codeql-baseline-analysis:
78+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
79+
name: CodeQL Baseline Analysis
80+
runs-on: linux-amd64-cpu4
81+
timeout-minutes: 360
82+
needs: prepare-environment
83+
permissions:
84+
security-events: write
85+
packages: read
86+
steps:
87+
- name: Checkout repository
88+
uses: actions/checkout@v4
89+
90+
- name: Setup build environment
91+
uses: ./.github/actions/setup-build-env
92+
with:
93+
go-version: ${{ needs.prepare-environment.outputs.go_version }}
94+
python-version: ${{ needs.prepare-environment.outputs.python_version }}
95+
poetry-version: ${{ needs.prepare-environment.outputs.poetry_version }}
96+
golangci-lint-version: ${{ needs.prepare-environment.outputs.golangci_lint_version }}
97+
protobuf-version: ${{ needs.prepare-environment.outputs.protobuf_version }}
98+
protoc-gen-go-version: ${{ needs.prepare-environment.outputs.protoc_gen_go_version }}
99+
protoc-gen-go-grpc-version: ${{ needs.prepare-environment.outputs.protoc_gen_go_grpc_version }}
100+
shellcheck-version: ${{ needs.prepare-environment.outputs.shellcheck_version }}
101+
102+
- name: Initialize CodeQL
103+
uses: github/codeql-action/init@v4
104+
with:
105+
languages: go
106+
build-mode: manual
107+
env:
108+
CODEQL_EXTRACTOR_GO_BUILD_TRACING: on
109+
110+
- name: Build with CodeQL
111+
run: |
112+
make build-all
113+
69114
- name: Perform CodeQL Analysis
70-
uses: github/codeql-action/analyze@v3
115+
uses: github/codeql-action/analyze@v4
71116
with:
72117
category: "/language:go"
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
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

Comments
 (0)