Retrieve actual data from SonarQube for comment
Signed-off-by: Steven Kriegler <61625851+justusbunsi@users.noreply.github.com>
This commit is contained in:
parent
c3566d9208
commit
e608a8f969
|
@ -28,7 +28,7 @@ func (sdk *GiteaSdk) PostComment(repo settings.GiteaRepository, idx int, msg str
|
|||
func New() *GiteaSdk {
|
||||
client, err := gitea.NewClient(settings.Gitea.Url, gitea.SetToken(settings.Gitea.Token.Value))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Cannot initialize Gitea client: %w", err))
|
||||
panic(fmt.Errorf("cannot initialize Gitea client: %w", err))
|
||||
}
|
||||
|
||||
return &GiteaSdk{client}
|
||||
|
|
53
internal/clients/sonarqube_sdk/measures.go
Normal file
53
internal/clients/sonarqube_sdk/measures.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package sonarqube_sdk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type period struct {
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type MeasuresComponentMeasure struct {
|
||||
Metric string `json:"metric"`
|
||||
Value string `json:"value"`
|
||||
Period *period `json:"period,omitempty"`
|
||||
}
|
||||
|
||||
type MeasuresComponentMetric struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type MeasuresComponent struct {
|
||||
PullRequest string `json:"pullRequest"`
|
||||
Measures []MeasuresComponentMeasure `json:"measures"`
|
||||
}
|
||||
|
||||
type MeasuresResponse struct {
|
||||
Component MeasuresComponent `json:"component"`
|
||||
Metrics []MeasuresComponentMetric `json:"metrics"`
|
||||
}
|
||||
|
||||
func (mr *MeasuresResponse) GetRenderedMarkdownTable() string {
|
||||
metricsTranslations := map[string]string{}
|
||||
for _, metric := range mr.Metrics {
|
||||
metricsTranslations[metric.Key] = metric.Name
|
||||
}
|
||||
measures := make([]string, len(mr.Component.Measures))
|
||||
for i, measure := range mr.Component.Measures {
|
||||
value := measure.Value
|
||||
if measure.Period != nil {
|
||||
value = measure.Period.Value
|
||||
}
|
||||
measures[i] = fmt.Sprintf("| %s | %s |", metricsTranslations[measure.Metric], value)
|
||||
}
|
||||
|
||||
table := `
|
||||
| Metric | Current |
|
||||
| -------- | -------- |
|
||||
%s`
|
||||
|
||||
return fmt.Sprintf(table, strings.Join(measures, "\n"))
|
||||
}
|
|
@ -2,16 +2,16 @@ package sonarqube_sdk
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"gitea-sonarqube-pr-bot/internal/settings"
|
||||
)
|
||||
|
||||
type SonarQubeSdkInterface interface {
|
||||
GetMeasures(string, string) (string, error)
|
||||
GetMeasures(string, string) (*MeasuresResponse, error)
|
||||
}
|
||||
|
||||
type SonarQubeSdk struct {
|
||||
|
@ -20,20 +20,26 @@ type SonarQubeSdk struct {
|
|||
token string
|
||||
}
|
||||
|
||||
func (sdk *SonarQubeSdk) GetMeasures(project string, branch string) (string, error) {
|
||||
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,violations&component=%s&pullRequest=%s", sdk.baseUrl, project, branch)
|
||||
log.Println(url)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Cannot initialize Request: %w", err))
|
||||
return nil, fmt.Errorf("cannot initialize Request: %w", err)
|
||||
}
|
||||
req.Header.Add("Authorization", sdk.basicAuth())
|
||||
resp, _ := sdk.client.Do(req)
|
||||
rawResp, _ := sdk.client.Do(req)
|
||||
if rawResp.Body != nil {
|
||||
defer rawResp.Body.Close()
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(rawResp.Body)
|
||||
response := &MeasuresResponse{}
|
||||
err = json.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse response from SonarQube: %w", err)
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (sdk *SonarQubeSdk) basicAuth() string {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
giteaSdk "gitea-sonarqube-pr-bot/internal/clients/gitea_sdk"
|
||||
sqSdk "gitea-sonarqube-pr-bot/internal/clients/sonarqube_sdk"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
|
|
@ -20,34 +20,23 @@ type SonarQubeWebhookHandler struct {
|
|||
sqSdk sqSdk.SonarQubeSdkInterface
|
||||
}
|
||||
|
||||
func (h *SonarQubeWebhookHandler) composeGiteaComment(w *webhook.Webhook) string {
|
||||
a, _ := h.sqSdk.GetMeasures(w.Project.Key, w.Branch.Name)
|
||||
|
||||
log.Println(a)
|
||||
|
||||
status := ":white_check_mark:"
|
||||
if w.QualityGate.Status != "OK" {
|
||||
status = ":x:"
|
||||
func (h *SonarQubeWebhookHandler) composeGiteaComment(w *webhook.Webhook) (string, error) {
|
||||
m, err := h.sqSdk.GetMeasures(w.Project.Key, w.Branch.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
measures := `| Metric | Current |
|
||||
| -------- | -------- |
|
||||
| Bugs | 123 |
|
||||
| Code Smells | 1 |
|
||||
| Vulnerabilities | 1 |
|
||||
`
|
||||
message := make([]string, 5)
|
||||
message[0] = w.GetRenderedQualityGate()
|
||||
message[1] = m.GetRenderedMarkdownTable()
|
||||
message[2] = fmt.Sprintf("See [SonarQube](%s) for details.", w.Branch.Url)
|
||||
message[3] = "---"
|
||||
message[4] = "- If you want the bot to check again, post `/sqbot review`"
|
||||
|
||||
msg := `**Quality Gate**: %s
|
||||
|
||||
**Measures**
|
||||
|
||||
%s
|
||||
|
||||
See [SonarQube](https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1) for details.`
|
||||
return fmt.Sprintf(msg, status, measures)
|
||||
return strings.Join(message, "\n\n"), nil
|
||||
}
|
||||
|
||||
func (_ *SonarQubeWebhookHandler) inProjectsMapping(p []settings.Project, n string) (bool, int) {
|
||||
func (*SonarQubeWebhookHandler) inProjectsMapping(p []settings.Project, n string) (bool, int) {
|
||||
for idx, proj := range p {
|
||||
if proj.SonarQube.Key == n {
|
||||
return true, idx
|
||||
|
@ -65,7 +54,11 @@ func (h *SonarQubeWebhookHandler) processData(w *webhook.Webhook, repo settings.
|
|||
|
||||
h.fetchDetails(w)
|
||||
|
||||
comment := h.composeGiteaComment(w)
|
||||
comment, err := h.composeGiteaComment(w)
|
||||
if err != nil {
|
||||
log.Printf("Error composing Gitea comment: %s", err.Error())
|
||||
return
|
||||
}
|
||||
h.giteaSdk.PostComment(repo, w.PRIndex, comment)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
sqSDK "gitea-sonarqube-pr-bot/internal/clients/sonarqube_sdk"
|
||||
"gitea-sonarqube-pr-bot/internal/settings"
|
||||
webhook "gitea-sonarqube-pr-bot/internal/webhooks/sonarqube"
|
||||
|
||||
|
@ -33,8 +34,8 @@ type SQSdkMock struct {
|
|||
mock.Mock
|
||||
}
|
||||
|
||||
func (h *SQSdkMock) GetMeasures(project string, branch string) (string, error) {
|
||||
return "", nil
|
||||
func (h *SQSdkMock) GetMeasures(project string, branch string) (*sqSDK.MeasuresResponse, error) {
|
||||
return &sqSDK.MeasuresResponse{}, nil
|
||||
}
|
||||
|
||||
func defaultMockPreparation(h *HandlerPartialMock) {
|
||||
|
|
|
@ -33,6 +33,15 @@ type Webhook struct {
|
|||
PRIndex int
|
||||
}
|
||||
|
||||
func (w *Webhook) GetRenderedQualityGate() string {
|
||||
status := ":white_check_mark:"
|
||||
if w.QualityGate.Status != "OK" {
|
||||
status = ":x:"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("**Quality Gate**: %s", status)
|
||||
}
|
||||
|
||||
func New(raw []byte) (*Webhook, bool) {
|
||||
v := viper.New()
|
||||
v.SetConfigType("json")
|
||||
|
@ -61,8 +70,8 @@ func parsePRIndex(w *Webhook) (int, error) {
|
|||
re := regexp.MustCompile(`^PR-(\d+)$`)
|
||||
res := re.FindSubmatch([]byte(w.Branch.Name))
|
||||
if len(res) != 2 {
|
||||
return 0, fmt.Errorf("Branch name '%s' does not match regex '%s'.", w.Branch.Name, re.String())
|
||||
return 0, fmt.Errorf("branch name '%s' does not match regex '%s'", w.Branch.Name, re.String())
|
||||
}
|
||||
|
||||
return strconv.Atoi(fmt.Sprintf("%s", res[1]))
|
||||
return strconv.Atoi(string(res[1]))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue