Skip to content

Instantly share code, notes, and snippets.

@rbalman
Created July 25, 2023 08:13
Show Gist options
  • Save rbalman/e0808100a077a78542ba62b5989471ea to your computer and use it in GitHub Desktop.
Save rbalman/e0808100a077a78542ba62b5989471ea to your computer and use it in GitHub Desktop.
Export sonar cloud report in a CSV format
package main
import (
"encoding/csv"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
/*
The source of data is sonarcloud API. Please find more details here: https://docs.sonarcloud.io/advanced-setup/web-api/. To better understand the report please consult this documentaion: https://docs.sonarsource.com/sonarqube/latest/user-guide/metric-definitions/#security.
*/
const (
baseURL = "https://sonarcloud.io/api"
organization = "cloudfactory"
metricKeys = "violations,minor_violations,major_violations,critical_violations,blocker_violations,bugs,security_rating,coverage"
csvFileName = "sonar_report.csv"
)
type Project struct {
Key string `json:"key"`
Name string `json:"name"`
}
type ProjectData struct {
Projects []Project `json:"components"`
}
type MetricValue struct {
Measures []map[string]interface{} `json:"measures"`
Key string `json:"key"`
Name string `json:"name"`
}
type MetricsResponse struct {
Metrics MetricValue `json:"component"`
}
func main() {
apiToken := os.Getenv("SONAR_TOKEN")
if apiToken == "" {
fmt.Println("Please provide SONAR_TOKEN as a environment variable.")
os.Exit(1)
}
// Step 1: Fetch the list of projects
projectsURL := fmt.Sprintf("%s/projects/search?organization=%s&ps=150&qualifier=TRK", baseURL, organization)
res, err := fetchData(apiToken, projectsURL)
if err != nil {
fmt.Println("Error fetching projects:", err)
return
}
var pd ProjectData
err = json.Unmarshal(res, &pd)
if err != nil {
fmt.Println("Error decoding projects JSON:", err)
return
}
// Step 2: Fetch metrics for each project and save in CSV
csvFile, err := os.Create(csvFileName)
if err != nil {
fmt.Println("Error creating CSV file:", err)
return
}
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
defer writer.Flush()
// Write CSV headers
writer.Write([]string{"project_name", "project_id", "project_url", "violations", "minor_violations", "major_violations", "critical_violations", "blocker_violations", "bugs", "security_rating", "coverage"})
for _, project := range pd.Projects {
fmt.Println("Sleeping..")
time.Sleep(500 * time.Millisecond)
projectMetricsURL := fmt.Sprintf("%s/measures/component?organization=%s&componentKey=%s&metricKeys=%s", baseURL, organization, project.Key, metricKeys)
fmt.Printf("Enpdoint: %s\n", projectMetricsURL)
metricsData, err := fetchData(apiToken, projectMetricsURL)
if err != nil {
fmt.Printf("Error fetching metrics for project %s: %v\n", project.Name, err)
continue
}
var metricsResponse MetricsResponse
err = json.Unmarshal(metricsData, &metricsResponse)
if err != nil {
fmt.Printf("Error decoding metrics JSON for project %s: %v\n", project.Name, err)
continue
}
// Collect the metric values
var violations, minorViolations, majorViolations, criticalViolations, blockerViolations, bugs, securityRating, coverage string
for _, metric := range metricsResponse.Metrics.Measures {
switch metric["metric"] {
case "violations":
violations = metric["value"].(string)
case "minor_violations":
minorViolations = metric["value"].(string)
case "major_violations":
majorViolations = metric["value"].(string)
case "critical_violations":
criticalViolations = metric["value"].(string)
case "blocker_violations":
blockerViolations = metric["value"].(string)
case "bugs":
bugs = metric["value"].(string)
case "security_rating":
securityRating = metric["value"].(string)
case "coverage":
coverage = metric["value"].(string)
}
}
// Write project data to CSV
writer.Write([]string{project.Name, project.Key, fmt.Sprintf("https://sonarcloud.io/summary/overall?id=%s&organization=%s", project.Key, organization), violations, minorViolations, majorViolations, criticalViolations, blockerViolations, bugs, securityRating, coverage})
}
fmt.Printf("SonarCloud report has been saved in %s\n", csvFileName)
}
func fetchData(apiToken, url string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.SetBasicAuth(apiToken, "")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment