Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3097,6 +3097,29 @@ evidenceDetails := evidenceService.EvidenceDetails{
}
body, err = evideceManager.UploadEvidence(evidenceDetails)
```

#### Fetch Sonar Task Report

```go
// Fetches the status of a SonarQube task by its task ID.
taskID := "your-task-id"
// sonarQubeURL is the URL of the SonarQube server.
sonarQubeURL := "http://localhost:9000"
// proxy is optional and can be used to specify a proxy server.
proxy := ""
body, err := evidenceManager.FetchSonarTaskStatus(taskID, sonarQubeURL, proxy)
```
#### Fetch Sonar Analysis Report

```go
// Retrieves the analysis report from SonarQube by analysis ID.
analysisID := "your-analysis-id"
// sonarQubeURL is the URL of the SonarQube server.
sonarQubeURL := "http://localhost:9000"
// proxy is optional and can be used to specify a proxy server.
proxy := ""
body, err := evidenceManager.GetSonarAnalysisReport(analysisID, sonarQubeURL, proxy)
```
## Metadata APIs

### Creating Metadata Service Manager
Expand Down
145 changes: 145 additions & 0 deletions evidence/external/sonarqube/sonarqube.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package sonarqube

import (
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"io"
"net/http"
"net/url"
"os"
"time"
)

const SonarAccessTokenKey = "JF_SONARQUBE_ACCESS_TOKEN"

type SonarQube struct {
Proxy string
ServiceConfig
}

type ServiceConfig struct {
url string
taskAPIPath string
projectStatusAPIPath string
}

func NewSonarQubeEvidence(sonarQubeURL, proxy string) *SonarQube {
return &SonarQube{
Proxy: proxy,
ServiceConfig: ServiceConfig{
url: sonarQubeURL,
taskAPIPath: "/api/ce/task",
projectStatusAPIPath: "/api/qualitygates/project_status",
},
}
}

func (sqe *SonarQube) createQueryParam(params map[string]string, key, value string) map[string]string {
if params != nil {
params[key] = value
return params
}
return map[string]string{
key: value,
}
}

func createHttpClient(proxy string) *http.Client {
transport := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableKeepAlives: false,
Proxy: http.ProxyFromEnvironment,
}
if proxy != "" {
proxyURL, err := url.Parse(proxy)
if err != nil {

// Fallback to environment proxy or no proxy
log.Error("Failed to parse proxy URL: " + err.Error())
} else {
transport.Proxy = http.ProxyURL(proxyURL)
}
}
return &http.Client{
Timeout: 30 * time.Second,
Transport: transport,
}
}

func (sqe *SonarQube) GetSonarAnalysis(analysisID string) ([]byte, error) {
log.Debug("Fetching quality gate analysis for analysisID" + analysisID)
queryParams := sqe.createQueryParam(nil, "analysisId", analysisID)
sonarServerURL := sqe.ServiceConfig.url + sqe.ServiceConfig.projectStatusAPIPath

req, err := http.NewRequest("GET", sonarServerURL, nil)

Check failure on line 75 in evidence/external/sonarqube/sonarqube.go

View workflow job for this annotation

GitHub Actions / Static-Check

"GET" can be replaced by http.MethodGet (usestdlibvars)
if err != nil {
return nil, err
}

q := req.URL.Query()
for key, value := range queryParams {
q.Add(key, value)
}
req.URL.RawQuery = q.Encode()
resp, bytes, err := sqe.sendRequestUsingSonarQubeToken(req, sqe.Proxy)
if err != nil {
return bytes, err
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
log.Error("Failed to close response body" + err.Error())
}
}(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}

func (sqe *SonarQube) CollectSonarQubePredicate(taskID string) ([]byte, error) {
queryParams := sqe.createQueryParam(nil, "id", taskID)
sonarServerURL := sqe.ServiceConfig.url + sqe.ServiceConfig.taskAPIPath
req, err := http.NewRequest(http.MethodGet, sonarServerURL, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
for key, value := range queryParams {
q.Add(key, value)
}
req.URL.RawQuery = q.Encode()
resp, bytes, err := sqe.sendRequestUsingSonarQubeToken(req, sqe.Proxy)
if err != nil {
return bytes, err
}
defer func() {
if cerr := resp.Body.Close(); cerr != nil {
log.Error("Failed to close response body" + cerr.Error())
}
}()
if resp.StatusCode != http.StatusOK {
return nil, errorutils.CheckErrorf("Failed to get SonarQube task report. Status code: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}

func (sqe *SonarQube) sendRequestUsingSonarQubeToken(req *http.Request, proxy string) (*http.Response, []byte, error) {

Check failure on line 133 in evidence/external/sonarqube/sonarqube.go

View workflow job for this annotation

GitHub Actions / Static-Check

(*SonarQube).sendRequestUsingSonarQubeToken - result 1 ([]byte) is always nil (unparam)
sonarQubeToken := os.Getenv(SonarAccessTokenKey)
if sonarQubeToken == "" {
return nil, nil, errorutils.CheckErrorf("Sonar access token not found in environment variable " + SonarAccessTokenKey)
}
req.Header.Set("Authorization", "Bearer "+sonarQubeToken)
httpClient := createHttpClient(proxy)
resp, err := httpClient.Do(req)
if err != nil {
return nil, nil, err
}
return resp, nil, nil
}
11 changes: 11 additions & 0 deletions evidence/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package evidence

import (
"github.com/jfrog/jfrog-client-go/config"
"github.com/jfrog/jfrog-client-go/evidence/external/sonarqube"
"github.com/jfrog/jfrog-client-go/evidence/services"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
)
Expand Down Expand Up @@ -39,3 +40,13 @@ func (esm *EvidenceServicesManager) UploadEvidence(evidenceDetails services.Evid
evidenceService := services.NewEvidenceService(esm.config.GetServiceDetails(), esm.client)
return evidenceService.UploadEvidence(evidenceDetails)
}

func (esm *EvidenceServicesManager) FetchSonarTaskStatus(taskID, sonarQubeURL, proxy string) ([]byte, error) {
sonarTaskStatus := sonarqube.NewSonarQubeEvidence(sonarQubeURL, proxy)
return sonarTaskStatus.CollectSonarQubePredicate(taskID)
}

func (esm *EvidenceServicesManager) GetSonarAnalysisReport(analysisID, sonarQubeURL, proxy string) ([]byte, error) {
sonarAnalysisReport := sonarqube.NewSonarQubeEvidence(sonarQubeURL, proxy)
return sonarAnalysisReport.GetSonarAnalysis(analysisID)
}
Loading