Allow customizing metrics fetch from SonarQube

Signed-off-by: Steven Kriegler <sk.bunsenbrenner@gmail.com>
This commit is contained in:
justusbunsi 2021-10-12 13:10:35 +02:00
parent a2d68ccc12
commit f187d4f8c6
No known key found for this signature in database
GPG key ID: 82B29BF2507F9F8B
7 changed files with 88 additions and 17 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@
/coverage.html
/*.log
/cover.out
/cover.html

View file

@ -7,8 +7,8 @@ gitea:
# User needs "Read project" permissions with access to "Pull Requests"
token:
value: ""
# # or path to file containing the plain text secret
# file: /path/to/gitea/token
# # or path to file containing the plain text secret
# file: /path/to/gitea/token
# If the sent webhook has a signature header, the bot validates the request payload. If the value does not match, the
# request will be ignored.
@ -16,8 +16,8 @@ gitea:
# exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be validated.
webhook:
secret: ""
# # or path to file containing the plain text secret
# secretFile: /path/to/gitea/webhook/secret
# # or path to file containing the plain text secret
# secretFile: /path/to/gitea/webhook/secret
# SonarQube related configuration. Necessary for requesting data from the API and processing the webhook.
sonarqube:
@ -28,8 +28,8 @@ sonarqube:
# User needs "Browse on project" permissions
token:
value: ""
# # or path to file containing the plain text secret
# file: /path/to/sonarqube/token
# # or path to file containing the plain text secret
# file: /path/to/sonarqube/token
# If the sent webhook has a signature header, the bot validates the request payload. If the value does not match, the
# request will be ignored.
@ -38,8 +38,14 @@ sonarqube:
# validated.
webhook:
secret: ""
# # or path to file containing the plain text secret
# secretFile: /path/to/sonarqube/webhook/secret
# # or path to file containing the plain text secret
# secretFile: /path/to/sonarqube/webhook/secret
# Some useful metrics depend on the edition in use. There are various ones like code_smells, vulnerabilities, bugs, etc.
# By default the bot will extract "bugs,vulnerabilities,code_smells"
# Setting this option you can extend that default list by your own metrics.
additionalMetrics: []
# - "new_security_hotspots"
# List of project mappings to take care of. Webhooks for other projects will be ignored.
# At least one must be configured. Otherwise all webhooks (no matter which source) because the bot cannot map on its own.

View file

@ -55,6 +55,12 @@ app:
secret: ""
# # or path to file containing the plain text secret
# secretFile: /bot/secrets/sonarqube/webhook-secret
# Some useful metrics depend on the edition in use. There are various ones like code_smells, vulnerabilities, bugs, etc.
# By default the bot will extract "bugs,vulnerabilities,code_smells"
# Setting this option you can extend that default list by your own metrics.
additionalMetrics: []
# - "new_security_hotspots"
# List of project mappings to take care of. Webhooks for other projects will be ignored.
# At least one must be configured. Otherwise all webhooks (no matter which source) because the bot cannot map on its own.

View file

@ -102,7 +102,7 @@ func (sdk *SonarQubeSdk) GetPullRequest(project string, index int64) (*PullReque
}
func (sdk *SonarQubeSdk) GetMeasures(project string, branch string) (*MeasuresResponse, error) {
url := fmt.Sprintf("%s/api/measures/component?additionalFields=metrics&metricKeys=bugs,vulnerabilities,new_security_hotspots,code_smells&component=%s&pullRequest=%s", sdk.baseUrl, project, branch)
url := fmt.Sprintf("%s/api/measures/component?additionalFields=metrics&metricKeys=%s&component=%s&pullRequest=%s", sdk.baseUrl, settings.SonarQube.GetMetricsList(), project, branch)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("cannot initialize Request: %w", err)

View file

@ -32,6 +32,7 @@ func newConfigReader() *viper.Viper {
v.SetDefault("sonarqube.token.file", "")
v.SetDefault("sonarqube.webhook.secret", "")
v.SetDefault("sonarqube.webhook.secretFile", "")
v.SetDefault("sonarqube.additionalMetrics", []string{})
v.SetDefault("projects", []Project{})
return v
@ -43,14 +44,14 @@ func Load(configPath string) {
err := r.ReadInConfig()
if err != nil {
panic(fmt.Errorf("Fatal error while reading config file: %w \n", err))
panic(fmt.Errorf("fatal error while reading config file: %w", err))
}
var projects []Project
err = r.UnmarshalKey("projects", &projects)
if err != nil {
panic(fmt.Errorf("Unable to load project mapping: %s", err.Error()))
panic(fmt.Errorf("unable to load project mapping: %s", err.Error()))
}
if len(projects) == 0 {
@ -67,8 +68,9 @@ func Load(configPath string) {
Webhook: NewWebhook(r, "gitea", errCallback),
}
SonarQube = sonarQubeConfig{
Url: r.GetString("sonarqube.url"),
Token: NewToken(r, "sonarqube", errCallback),
Webhook: NewWebhook(r, "sonarqube", errCallback),
Url: r.GetString("sonarqube.url"),
Token: NewToken(r, "sonarqube", errCallback),
Webhook: NewWebhook(r, "sonarqube", errCallback),
AdditionalMetrics: r.GetStringSlice("sonarqube.additionalMetrics"),
}
}

View file

@ -22,6 +22,7 @@ sonarqube:
value: a09eb5785b25bb2cbacf48808a677a0709f02d8e
webhook:
secret: haxxor-sonarqube-secret
additionalMetrics: []
projects:
- sonarqube:
key: gitea-sonarqube-pr-bot
@ -107,6 +108,45 @@ func TestLoadSonarQubeStructure(t *testing.T) {
}
assert.EqualValues(t, expected, SonarQube)
assert.EqualValues(t, expected.GetMetricsList(), "bugs,vulnerabilities,code_smells")
}
func TestLoadSonarQubeStructureWithAdditionalMetrics(t *testing.T) {
WriteConfigFile(t, []byte(
`gitea:
url: https://example.com/gitea
token:
value: fake-gitea-token
sonarqube:
url: https://example.com/sonarqube
token:
value: fake-sonarqube-token
additionalMetrics: "new_security_hotspots"
projects:
- sonarqube:
key: gitea-sonarqube-pr-bot
gitea:
owner: example-organization
name: pr-bot
`))
Load(os.TempDir())
expected := sonarQubeConfig{
Url: "https://example.com/sonarqube",
Token: &token{
Value: "fake-sonarqube-token",
},
Webhook: &webhook{
Secret: "",
},
AdditionalMetrics: []string{
"new_security_hotspots",
},
}
assert.EqualValues(t, expected, SonarQube)
assert.EqualValues(t, expected.AdditionalMetrics, []string{"new_security_hotspots"})
assert.EqualValues(t, "bugs,vulnerabilities,code_smells,new_security_hotspots", SonarQube.GetMetricsList())
}
func TestLoadSonarQubeStructureInjectedEnvs(t *testing.T) {
@ -189,6 +229,7 @@ projects:
Secret: "sonarqube-totally-secret",
secretFile: sonarqubeWebhookSecretFile,
},
AdditionalMetrics: []string{},
}
Load(os.TempDir())

View file

@ -1,7 +1,22 @@
package settings
import "strings"
type sonarQubeConfig struct {
Url string
Token *token
Webhook *webhook
Url string
Token *token
Webhook *webhook
AdditionalMetrics []string
}
func (c *sonarQubeConfig) GetMetricsList() string {
metrics := []string{
"bugs",
"vulnerabilities",
"code_smells",
}
if len(c.AdditionalMetrics) != 0 {
metrics = append(metrics, c.AdditionalMetrics...)
}
return strings.Join(metrics, ",")
}