2021-10-10 16:18:14 +02:00
|
|
|
package api
|
2021-06-24 14:38:04 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2021-10-03 17:57:22 +02:00
|
|
|
"log"
|
2021-06-24 14:38:04 +02:00
|
|
|
"net/http"
|
2021-06-24 16:52:06 +02:00
|
|
|
"strings"
|
2021-06-24 14:38:04 +02:00
|
|
|
|
2021-10-10 16:28:59 +02:00
|
|
|
giteaSdk "gitea-sonarqube-pr-bot/internal/clients/gitea"
|
2021-10-10 16:43:37 +02:00
|
|
|
sqSdk "gitea-sonarqube-pr-bot/internal/clients/sonarqube"
|
2021-10-03 17:57:22 +02:00
|
|
|
"gitea-sonarqube-pr-bot/internal/settings"
|
2021-06-29 11:59:49 +02:00
|
|
|
webhook "gitea-sonarqube-pr-bot/internal/webhooks/sonarqube"
|
2021-06-24 14:38:04 +02:00
|
|
|
)
|
|
|
|
|
2021-06-29 11:59:49 +02:00
|
|
|
type SonarQubeWebhookHandler struct {
|
2021-07-11 12:28:00 +02:00
|
|
|
fetchDetails func(w *webhook.Webhook)
|
2021-10-03 17:57:22 +02:00
|
|
|
giteaSdk giteaSdk.GiteaSdkInterface
|
|
|
|
sqSdk sqSdk.SonarQubeSdkInterface
|
2021-06-29 11:59:49 +02:00
|
|
|
}
|
|
|
|
|
2021-10-09 18:09:54 +02:00
|
|
|
func (*SonarQubeWebhookHandler) inProjectsMapping(p []settings.Project, n string) (bool, int) {
|
2021-07-12 12:36:22 +02:00
|
|
|
for idx, proj := range p {
|
2021-06-24 14:38:04 +02:00
|
|
|
if proj.SonarQube.Key == n {
|
2021-07-12 12:36:22 +02:00
|
|
|
return true, idx
|
2021-06-24 14:38:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 12:36:22 +02:00
|
|
|
return false, 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *SonarQubeWebhookHandler) processData(w *webhook.Webhook, repo settings.GiteaRepository) {
|
|
|
|
if strings.ToLower(w.Branch.Type) != "pull_request" {
|
|
|
|
log.Println("Ignore Hook for non-PR")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
h.fetchDetails(w)
|
|
|
|
|
2021-10-10 16:14:09 +02:00
|
|
|
status := giteaSdk.StatusOK
|
|
|
|
if w.QualityGate.Status != "OK" {
|
|
|
|
status = giteaSdk.StatusFailure
|
2021-10-09 20:45:21 +02:00
|
|
|
}
|
2021-10-11 14:21:17 +02:00
|
|
|
_ = h.giteaSdk.UpdateStatus(repo, w.GetRevision(), giteaSdk.StatusDetails{
|
2021-10-10 16:14:09 +02:00
|
|
|
Url: w.Branch.Url,
|
|
|
|
Message: w.QualityGate.Status,
|
|
|
|
State: status,
|
|
|
|
})
|
2021-10-09 20:45:21 +02:00
|
|
|
|
2021-10-10 19:39:33 +02:00
|
|
|
comment, err := h.sqSdk.ComposeGiteaComment(&sqSdk.CommentComposeData{
|
|
|
|
Key: w.Project.Key,
|
|
|
|
PRName: w.Branch.Name,
|
|
|
|
Url: w.Branch.Url,
|
|
|
|
QualityGate: w.QualityGate.Status,
|
|
|
|
})
|
2021-10-09 18:09:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2021-07-12 12:36:22 +02:00
|
|
|
h.giteaSdk.PostComment(repo, w.PRIndex, comment)
|
2021-06-24 14:38:04 +02:00
|
|
|
}
|
|
|
|
|
2021-06-29 11:59:49 +02:00
|
|
|
func (h *SonarQubeWebhookHandler) Handle(rw http.ResponseWriter, r *http.Request) {
|
2021-06-24 14:38:04 +02:00
|
|
|
rw.Header().Set("Content-Type", "application/json")
|
|
|
|
|
2021-07-12 12:36:22 +02:00
|
|
|
projectName := r.Header.Get("X-SonarQube-Project")
|
|
|
|
found, pIdx := h.inProjectsMapping(settings.Projects, projectName)
|
|
|
|
if !found {
|
|
|
|
log.Printf("Received hook for project '%s' which is not configured. Request ignored.", projectName)
|
2021-06-24 14:38:04 +02:00
|
|
|
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
2021-07-12 12:36:22 +02:00
|
|
|
io.WriteString(rw, fmt.Sprintf(`{"message": "Project '%s' not in configured list. Request ignored."}`, projectName))
|
2021-06-24 14:38:04 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-07-12 12:36:22 +02:00
|
|
|
log.Printf("Received hook for project '%s'. Processing data.", projectName)
|
2021-06-24 14:38:04 +02:00
|
|
|
|
2021-10-10 15:58:03 +02:00
|
|
|
if r.Body != nil {
|
|
|
|
defer r.Body.Close()
|
|
|
|
}
|
|
|
|
|
2021-06-24 16:52:06 +02:00
|
|
|
raw, err := ioutil.ReadAll(r.Body)
|
2021-06-24 14:38:04 +02:00
|
|
|
if err != nil {
|
2021-06-24 16:52:06 +02:00
|
|
|
log.Printf("Error reading request body %s", err.Error())
|
2021-06-24 14:38:04 +02:00
|
|
|
rw.WriteHeader(http.StatusInternalServerError)
|
|
|
|
io.WriteString(rw, fmt.Sprintf(`{"message": "%s"}`, err.Error()))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-29 11:59:49 +02:00
|
|
|
w, ok := webhook.New(raw)
|
2021-06-24 16:52:06 +02:00
|
|
|
if !ok {
|
2021-06-24 14:38:04 +02:00
|
|
|
rw.WriteHeader(http.StatusUnprocessableEntity)
|
|
|
|
io.WriteString(rw, `{"message": "Error parsing POST body."}`)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send response to SonarQube at this point to ensure being within 10 seconds limit of webhook response timeout
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
|
|
|
io.WriteString(rw, `{"message": "Processing data. See bot logs for details."}`)
|
2021-06-24 16:52:06 +02:00
|
|
|
|
2021-07-12 12:36:22 +02:00
|
|
|
h.processData(w, settings.Projects[pIdx].Gitea)
|
2021-06-29 11:59:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func fetchDetails(w *webhook.Webhook) {
|
2021-07-12 12:36:22 +02:00
|
|
|
log.Printf("This method will load additional data from SonarQube based on PR %d", w.PRIndex)
|
2021-06-29 11:59:49 +02:00
|
|
|
}
|
|
|
|
|
2021-07-12 16:58:48 +02:00
|
|
|
func NewSonarQubeWebhookHandler(g giteaSdk.GiteaSdkInterface, sq sqSdk.SonarQubeSdkInterface) *SonarQubeWebhookHandler {
|
|
|
|
return &SonarQubeWebhookHandler{
|
|
|
|
fetchDetails: fetchDetails,
|
2021-10-03 17:57:22 +02:00
|
|
|
giteaSdk: g,
|
|
|
|
sqSdk: sq,
|
2021-07-12 16:58:48 +02:00
|
|
|
}
|
2021-06-24 14:38:04 +02:00
|
|
|
}
|