mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-16 05:16:08 +02:00
feat(sonar): extract sonar project link to report JSON (#1390)
* add test cases for sonar pkg
* add sonar pkg
* read task report and write reports JSON
* use alias
* rename type
* set read permission on created files
* archive reports
* handle empty report lists
* use filepath
* simplify report creation
* improve error message
* Revert "archive reports"
This reverts commit ba4b56fec1
.
* improve test cases
* Add descriptions
Co-Authored-By: Stephan Aßmus <stephan.assmus@sap.com>
* improve tests
Co-Authored-By: Stephan Aßmus <stephan.assmus@sap.com>
Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
parent
c9cc2e1d30
commit
989c47db2c
@ -15,11 +15,14 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
FileUtils "github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
SliceUtils "github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
StepResults "github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
SonarUtils "github.com/SAP/jenkins-library/pkg/sonar"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type sonarSettings struct {
|
||||
workingDir string
|
||||
binary string
|
||||
environment []string
|
||||
options []string
|
||||
@ -48,6 +51,7 @@ func sonarExecuteScan(config sonarExecuteScanOptions, _ *telemetry.CustomData) {
|
||||
client.SetOptions(piperhttp.ClientOptions{TransportTimeout: 20 * time.Second})
|
||||
|
||||
sonar = sonarSettings{
|
||||
workingDir: "./",
|
||||
binary: "sonar-scanner",
|
||||
environment: []string{},
|
||||
options: []string{},
|
||||
@ -93,9 +97,27 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne
|
||||
WithField("options", sonar.options).
|
||||
WithField("environment", sonar.environment).
|
||||
Debug("Executing sonar scan command")
|
||||
|
||||
// execute scan
|
||||
runner.SetEnv(sonar.environment)
|
||||
return runner.RunExecutable(sonar.binary, sonar.options...)
|
||||
err := runner.RunExecutable(sonar.binary, sonar.options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// load task results
|
||||
taskReport, err := SonarUtils.ReadTaskReport(sonar.workingDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// write links JSON
|
||||
links := []StepResults.Path{
|
||||
StepResults.Path{
|
||||
Target: taskReport.DashboardURL,
|
||||
Name: "Sonar Web UI",
|
||||
},
|
||||
}
|
||||
StepResults.PersistReportsAndLinks("sonarExecuteScan", sonar.workingDir, nil, links)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handlePullRequest(config sonarExecuteScanOptions) error {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -64,13 +65,25 @@ func mockOsRename(t *testing.T, expectOld, expectNew string) func(string, string
|
||||
}
|
||||
}
|
||||
|
||||
func createTaskReportFile(t *testing.T, workingDir string) {
|
||||
require.NoError(t, os.MkdirAll(filepath.Join(workingDir, ".scannerwork"), 0755))
|
||||
require.NoError(t, ioutil.WriteFile(filepath.Join(workingDir, ".scannerwork", "report-task.txt"), []byte("projectKey=piper-test\nserverUrl=https://sonarcloud.io\nserverVersion=8.0.0.12345\ndashboardUrl=https://sonarcloud.io/dashboard/index/piper-test\nceTaskId=AXERR2JBbm9IiM5TEST\nceTaskUrl=https://sonarcloud.io/api/ce/task?id=AXERR2JBbm9IiMTEST"), 0755))
|
||||
require.FileExists(t, filepath.Join(workingDir, ".scannerwork", "report-task.txt"))
|
||||
}
|
||||
|
||||
func TestRunSonar(t *testing.T) {
|
||||
mockRunner := mock.ExecMockRunner{}
|
||||
mockClient := mockDownloader{shouldFail: false}
|
||||
|
||||
t.Run("default", func(t *testing.T) {
|
||||
// init
|
||||
tmpFolder, err := ioutil.TempDir(".", "test-sonar-")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpFolder)
|
||||
createTaskReportFile(t, tmpFolder)
|
||||
|
||||
sonar = sonarSettings{
|
||||
workingDir: tmpFolder,
|
||||
binary: "sonar-scanner",
|
||||
environment: []string{},
|
||||
options: []string{},
|
||||
@ -90,7 +103,7 @@ func TestRunSonar(t *testing.T) {
|
||||
os.Unsetenv("PIPER_SONAR_LOAD_CERTIFICATES")
|
||||
}()
|
||||
// test
|
||||
err := runSonar(options, &mockClient, &mockRunner)
|
||||
err = runSonar(options, &mockClient, &mockRunner)
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sonar.options, "-Dsonar.projectVersion=1.2.3")
|
||||
@ -98,10 +111,18 @@ func TestRunSonar(t *testing.T) {
|
||||
assert.Contains(t, sonar.environment, "SONAR_HOST_URL=https://sonar.sap.com")
|
||||
assert.Contains(t, sonar.environment, "SONAR_TOKEN=secret-ABC")
|
||||
assert.Contains(t, sonar.environment, "SONAR_SCANNER_OPTS=-Djavax.net.ssl.trustStore="+filepath.Join(getWorkingDir(), ".certificates", "cacerts"))
|
||||
assert.FileExists(t, filepath.Join(sonar.workingDir, "sonarExecuteScan_reports.json"))
|
||||
assert.FileExists(t, filepath.Join(sonar.workingDir, "sonarExecuteScan_links.json"))
|
||||
})
|
||||
t.Run("with custom options", func(t *testing.T) {
|
||||
// init
|
||||
tmpFolder, err := ioutil.TempDir(".", "test-sonar-")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpFolder)
|
||||
createTaskReportFile(t, tmpFolder)
|
||||
|
||||
sonar = sonarSettings{
|
||||
workingDir: tmpFolder,
|
||||
binary: "sonar-scanner",
|
||||
environment: []string{},
|
||||
options: []string{},
|
||||
@ -114,7 +135,7 @@ func TestRunSonar(t *testing.T) {
|
||||
fileUtilsExists = FileUtils.FileExists
|
||||
}()
|
||||
// test
|
||||
err := runSonar(options, &mockClient, &mockRunner)
|
||||
err = runSonar(options, &mockClient, &mockRunner)
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sonar.options, "-Dsonar.projectKey=piper")
|
||||
|
1
go.mod
1
go.mod
@ -16,6 +16,7 @@ require (
|
||||
github.com/google/go-containerregistry v0.0.0-20200413145205-82d30a103c0a
|
||||
github.com/google/go-github/v28 v28.1.1
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/magiconair/properties v1.8.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sirupsen/logrus v1.5.0
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
|
1
go.sum
1
go.sum
@ -273,6 +273,7 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
|
36
pkg/sonar/sonar.go
Normal file
36
pkg/sonar/sonar.go
Normal file
@ -0,0 +1,36 @@
|
||||
package sonar
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/magiconair/properties"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// TaskReportData encapsulates information about an executed Sonar scan task.
|
||||
// https://pkg.go.dev/github.com/magiconair/properties@v1.8.0?tab=doc#Properties.Decode
|
||||
type TaskReportData struct {
|
||||
ProjectKey string `properties:"projectKey"`
|
||||
TaskID string `properties:"ceTaskId"`
|
||||
DashboardURL string `properties:"dashboardUrl"`
|
||||
TaskURL string `properties:"ceTaskUrl"`
|
||||
ServerURL string `properties:"serverUrl"`
|
||||
ServerVersion string `properties:"serverVersion"`
|
||||
}
|
||||
|
||||
//ReadTaskReport expects a file ".scannerwork/report-task.txt" to exist in the provided workspace directory,
|
||||
//and parses its contents into the returned TaskReportData struct.
|
||||
func ReadTaskReport(workspace string) (result TaskReportData, err error) {
|
||||
reportFile := filepath.Join(workspace, ".scannerwork", "report-task.txt")
|
||||
// read file content
|
||||
reportContent, err := properties.LoadFile(reportFile, properties.UTF8)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// read content into struct
|
||||
err = reportContent.Decode(&result)
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, "decode %s", reportFile)
|
||||
}
|
||||
return
|
||||
}
|
40
pkg/sonar/sonar_test.go
Normal file
40
pkg/sonar/sonar_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package sonar
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestReadTaskReport(t *testing.T) {
|
||||
t.Run("default", func(t *testing.T) {
|
||||
// test
|
||||
result, err := ReadTaskReport("./testData/valid")
|
||||
// assert
|
||||
assert.Equal(t, "piper-test", result.ProjectKey)
|
||||
assert.Equal(t, "AXERR2JBbm9IiM5TEST", result.TaskID)
|
||||
assert.Equal(t, "https://sonarcloud.io/api/ce/task?id=AXERR2JBbm9IiMTEST", result.TaskURL)
|
||||
assert.Equal(t, "https://sonarcloud.io/dashboard/index/piper-test", result.DashboardURL)
|
||||
assert.Equal(t, "https://sonarcloud.io", result.ServerURL)
|
||||
assert.Equal(t, "8.0.0.12345", result.ServerVersion)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("missing file", func(t *testing.T) {
|
||||
// test
|
||||
result, err := ReadTaskReport("./testData/missing")
|
||||
// assert
|
||||
assert.Empty(t, result.ProjectKey)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, err, "open testData/missing/.scannerwork/report-task.txt: no such file or directory")
|
||||
})
|
||||
|
||||
t.Run("invalid file", func(t *testing.T) {
|
||||
// test
|
||||
result, err := ReadTaskReport("./testData/invalid")
|
||||
// assert
|
||||
assert.Empty(t, result.ProjectKey)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, err, "decode testData/invalid/.scannerwork/report-task.txt: missing required key projectKey")
|
||||
})
|
||||
}
|
6
pkg/sonar/testData/valid/.scannerwork/report-task.txt
Normal file
6
pkg/sonar/testData/valid/.scannerwork/report-task.txt
Normal file
@ -0,0 +1,6 @@
|
||||
projectKey=piper-test
|
||||
serverUrl=https://sonarcloud.io
|
||||
serverVersion=8.0.0.12345
|
||||
dashboardUrl=https://sonarcloud.io/dashboard/index/piper-test
|
||||
ceTaskId=AXERR2JBbm9IiM5TEST
|
||||
ceTaskUrl=https://sonarcloud.io/api/ce/task?id=AXERR2JBbm9IiMTEST
|
Loading…
Reference in New Issue
Block a user