Skip to content

Commit 6345d96

Browse files
authored
Add sonar gen workflow (#4686)
Signed-off-by: Fiachra Corcoran <fiachra.corcoran@est.tech>
1 parent c37d98d commit 6345d96

6 files changed

Lines changed: 255 additions & 3 deletions

File tree

.github/workflows/go.yml

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,30 @@ jobs:
7070
podman version
7171
- name: Check out code
7272
uses: actions/checkout@v6
73+
with:
74+
fetch-depth: 0
7375
- name: Set up Go
7476
uses: actions/setup-go@v6
7577
with:
7678
go-version-file: go.mod
77-
- name: Build, Test, Lint
79+
- name: Configure Git
7880
run: |
7981
git config --global user.email you@example.com
8082
git config --global user.name Your Name
81-
make all
82-
make test-docker
83+
- name: Lint and Format
84+
run: make fix vet fmt lint
85+
- name: Test with Coverage
86+
run: make test-coverage
87+
- name: Docker Runtime Tests
88+
run: make test-docker
8389
env:
8490
KRM_FN_RUNTIME: ${{ matrix.runtime }}
91+
- name: Upload coverage report
92+
uses: actions/upload-artifact@v6
93+
with:
94+
name: coverage-report-${{ matrix.runtime }}
95+
path: ./coverage.out
96+
retention-days: 1
8597

8698
build-macos:
8799
name: build-macos
@@ -99,6 +111,21 @@ jobs:
99111
run: |
100112
make build
101113
114+
save-pr-number:
115+
name: Save PR Number
116+
if: github.event_name == 'pull_request'
117+
runs-on: ubuntu-latest
118+
steps:
119+
- name: Save PR number
120+
run: echo ${{ github.event.number }} > PR_NUMBER.txt
121+
122+
- name: Archive PR number
123+
uses: actions/upload-artifact@v6
124+
with:
125+
name: PR_NUMBER
126+
path: PR_NUMBER.txt
127+
retention-days: 1
128+
102129
go-gate:
103130
name: go
104131
needs: [changes, build-test, build-macos]

.github/workflows/sonarcloud.yml

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Copyright 2026 The kpt Authors
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: SonarCloud analysis
16+
17+
on:
18+
workflow_run:
19+
workflows: [Go]
20+
types: [completed]
21+
22+
jobs:
23+
check-artifacts:
24+
runs-on: ubuntu-latest
25+
if: github.event.workflow_run.conclusion == 'success'
26+
permissions:
27+
actions: read
28+
outputs:
29+
has-artifacts: ${{ steps.check.outputs.has-artifacts }}
30+
steps:
31+
- name: Check for coverage artifact
32+
id: check
33+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
34+
with:
35+
script: |
36+
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
37+
owner: context.repo.owner,
38+
repo: context.repo.repo,
39+
run_id: ${{ github.event.workflow_run.id }}
40+
});
41+
const hasCoverage = artifacts.data.artifacts.some(a => a.name.startsWith('coverage-report-'));
42+
core.setOutput('has-artifacts', hasCoverage);
43+
44+
sonarqube:
45+
needs: check-artifacts
46+
if: needs.check-artifacts.outputs.has-artifacts == 'true'
47+
runs-on: ubuntu-latest
48+
permissions:
49+
actions: read
50+
contents: read
51+
pull-requests: read
52+
steps:
53+
- name: Download PR number artifact
54+
if: github.event.workflow_run.event == 'pull_request'
55+
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
56+
with:
57+
workflow: Go
58+
run_id: ${{ github.event.workflow_run.id }}
59+
name: PR_NUMBER
60+
continue-on-error: true
61+
62+
- name: Read PR_NUMBER.txt
63+
if: github.event.workflow_run.event == 'pull_request' && hashFiles('PR_NUMBER.txt') != ''
64+
id: pr_number
65+
uses: juliangruber/read-file-action@271ff311a4947af354c6abcd696a306553b9ec18 # v1.1.8
66+
with:
67+
path: ./PR_NUMBER.txt
68+
69+
- name: Request GitHub API for PR data
70+
if: github.event.workflow_run.event == 'pull_request' && hashFiles('PR_NUMBER.txt') != ''
71+
uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0
72+
id: get_pr_data
73+
with:
74+
route: GET /repos/{full_name}/pulls/{number}
75+
number: ${{ steps.pr_number.outputs.content }}
76+
full_name: ${{ github.event.repository.full_name }}
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
80+
- name: Extract PR metadata
81+
if: github.event.workflow_run.event == 'pull_request' && hashFiles('PR_NUMBER.txt') != ''
82+
id: pr_meta
83+
env:
84+
PR_DATA: ${{ steps.get_pr_data.outputs.data }}
85+
run: |
86+
echo "number=$(echo "$PR_DATA" | jq -r '.number')" >> "$GITHUB_OUTPUT"
87+
echo "head_ref=$(echo "$PR_DATA" | jq -r '.head.ref')" >> "$GITHUB_OUTPUT"
88+
echo "base_ref=$(echo "$PR_DATA" | jq -r '.base.ref')" >> "$GITHUB_OUTPUT"
89+
90+
- name: Checkout PR head
91+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
92+
with:
93+
repository: ${{ github.event.workflow_run.head_repository.full_name }}
94+
ref: ${{ github.event.workflow_run.head_sha }}
95+
fetch-depth: 0
96+
persist-credentials: false
97+
allow-unsafe-pr-checkout: true
98+
99+
- name: Checkout base branch
100+
if: github.event.workflow_run.event == 'pull_request'
101+
env:
102+
BASE_REF: ${{ steps.pr_meta.outputs.base_ref }}
103+
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
104+
CLONE_URL: ${{ github.event.repository.clone_url }}
105+
run: |
106+
git remote add upstream "$CLONE_URL"
107+
git fetch upstream
108+
git checkout -B "$BASE_REF" "upstream/$BASE_REF"
109+
git checkout "$HEAD_SHA"
110+
git clean -ffdx && git reset --hard HEAD
111+
112+
- name: Download coverage artifact (docker)
113+
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
114+
with:
115+
workflow: Go
116+
run_id: ${{ github.event.workflow_run.id }}
117+
name: coverage-report-docker
118+
use_unzip: true
119+
continue-on-error: true
120+
121+
- name: Download coverage artifact (podman)
122+
if: hashFiles('coverage.out') == ''
123+
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
124+
with:
125+
workflow: Go
126+
run_id: ${{ github.event.workflow_run.id }}
127+
name: coverage-report-podman
128+
use_unzip: true
129+
continue-on-error: true
130+
131+
- name: Fix Go module paths in coverage
132+
run: |
133+
sed -i 's|github.com/kptdev/kpt|.|g' coverage.out
134+
135+
- name: SonarQube Scan on PR
136+
if: github.event.workflow_run.event == 'pull_request' && hashFiles('PR_NUMBER.txt') != ''
137+
uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0
138+
env:
139+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
140+
with:
141+
args:
142+
-Dsonar.projectKey=kptdev_kpt
143+
-Dsonar.organization=kptdev
144+
-Dproject.settings=sonar.properties
145+
-Dsonar.pullrequest.key=${{ steps.pr_meta.outputs.number }}
146+
-Dsonar.pullrequest.branch=${{ steps.pr_meta.outputs.head_ref }}
147+
-Dsonar.pullrequest.base=${{ steps.pr_meta.outputs.base_ref }}
148+
149+
- name: SonarCloud Scan on push
150+
if: >-
151+
github.event.workflow_run.event == 'push' &&
152+
github.event.workflow_run.head_repository.full_name == github.event.repository.full_name
153+
uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0
154+
env:
155+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
156+
with:
157+
args:
158+
-Dsonar.projectKey=kptdev_kpt
159+
-Dsonar.organization=kptdev
160+
-Dproject.settings=sonar.properties
161+

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ go.work.sum
1818
.idea/
1919
*.iml
2020
coverage.out
21+
coverage_unit.html
22+
func_coverage.out
2123
kpt/kpt
2224
*.exe
2325
*.gif

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ SHELL := bash
1616
.SHELLFLAGS := -exc
1717

1818
include ./make/info.mk
19+
include ./make/testing.mk
1920

2021
all: fix vet fmt lint test build tidy
2122

make/testing.mk

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright 2026 The kpt Authors
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+
# Testing tools and targets for SonarQube coverage generation
16+
17+
TEST_COVERAGE_FILE=coverage.out
18+
TEST_COVERAGE_HTML_FILE=coverage_unit.html
19+
TEST_COVERAGE_FUNC_FILE=func_coverage.out
20+
21+
##@ Testing
22+
23+
.PHONY: test-coverage
24+
test-coverage: ## Generate coverage reports (runs tests with coverage instrumentation)
25+
go test -cover -coverprofile=$(TEST_COVERAGE_FILE) ${LDFLAGS} ./...
26+
go tool cover -html=$(TEST_COVERAGE_FILE) -o $(TEST_COVERAGE_HTML_FILE)
27+
go tool cover -func=$(TEST_COVERAGE_FILE) -o $(TEST_COVERAGE_FUNC_FILE)
28+
@echo "Coverage reports generated:"
29+
@echo " - $(TEST_COVERAGE_FILE): Coverage data (for SonarQube)"
30+
@echo " - $(TEST_COVERAGE_HTML_FILE): HTML coverage report"
31+
@echo " - $(TEST_COVERAGE_FUNC_FILE): Function-level coverage"
32+
33+
.PHONY: test-clean
34+
test-clean: ## Clean up coverage artifacts
35+
rm -f $(TEST_COVERAGE_FILE) $(TEST_COVERAGE_HTML_FILE) $(TEST_COVERAGE_FUNC_FILE)
36+
@echo "Coverage artifacts cleaned"
37+

sonar.properties

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Required metadata
2+
sonar.projectKey=kptdev_kpt
3+
sonar.projectName=kpt
4+
sonar.organization=kptdev
5+
6+
sonar.language=go
7+
8+
# Path to your Go source code
9+
# Includes all relevant source directories, excluding vendor and thirdparty
10+
sonar.sources=commands,pkg,run,internal,mdtogo,api/fnresult,api/kptfile,api/resourcegroup,api/schema
11+
12+
# Exclude files if needed
13+
sonar.exclusions=**/test/**, **/examples/*, **/scripts/*, **/*_test.go, **/testing*, **/generated/**, **/testdata/**, **/*zz_generated.*, vendor/**, thirdparty/**, .github/**, documentation/**, Formula/**
14+
15+
# To include test coverage reports
16+
sonar.test.inclusions=**/*_test.go
17+
sonar.coverage.exclusions=**/test/**, **/*_test.go, **/testing*, **/generated/**, **/*zz_generated.*
18+
19+
# Coverage and test report paths
20+
sonar.go.tests.reportPaths=report.xml
21+
sonar.go.coverage.reportPaths=coverage.out
22+
23+
# To exclude duplicated blocks from CPD (Copy-Paste Detection)
24+
sonar.cpd.exclusions=**/*_test.go, **/test/**, **/testing**, **/generated/**, **/*zz_generated.*

0 commit comments

Comments
 (0)