1
0
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:
Christopher Fenner 2020-04-21 15:45:52 +02:00 committed by GitHub
parent c9cc2e1d30
commit 989c47db2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 131 additions and 4 deletions

View File

@ -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 {

View File

@ -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
View File

@ -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
View File

@ -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
View 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
View 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")
})
}

View 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