This is an automated email from the ASF dual-hosted git repository.

zky pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new e856b603e SonarCloud API support (#8132)
e856b603e is described below

commit e856b603ef96b62a23c9834dc5ff4b7901115e3b
Author: Klesh Wong <[email protected]>
AuthorDate: Fri Oct 11 14:36:49 2024 +0800

    SonarCloud API support (#8132)
    
    * feat(sonarcloud): add org to the connections table
    
    * feat: add sonarqube cloud connection config
    
    * fix: sonarcloud now working
    
    * fix: linting
    
    * fix: copywriting for sonarqube cloud
    
    * feat: added cq_issue_impacts table
    
    * fix: unit test
    
    * fix: adjust sonarqube cloud config
    
    * feat: add sonarcloud dashboard (#8140)
    
    Co-authored-by: Startrekzky <[email protected]>
    
    ---------
    
    Co-authored-by: mintsweet <[email protected]>
    Co-authored-by: Louis.z <[email protected]>
    Co-authored-by: Startrekzky <[email protected]>
---
 .../models/domainlayer/codequality/cq_issues.go    |   11 +
 .../models/domainlayer/domaininfo/domaininfo.go    |    1 +
 .../20241010_add_ca_issue_impacts.go               |   49 +
 backend/core/models/migrationscripts/register.go   |    1 +
 backend/helpers/pluginhelper/api/api_client.go     |   21 +-
 backend/plugins/sonarqube/impl/impl.go             |    2 +
 backend/plugins/sonarqube/models/connection.go     |   25 +-
 ...register.go => 20240930_add_connection_orgs.go} |   50 +-
 .../migrationscripts/20241010_add_issue_impacts.go |   55 +
 .../sonarqube/models/migrationscripts/register.go  |    2 +
 .../plugins/sonarqube/models/sonarqube_issue.go    |   12 +
 .../sonarqube/tasks/issue_impacts_convertor.go     |   75 +
 .../plugins/sonarqube/tasks/issues_extractor.go    |   14 +
 .../components/connection-form/fields/endpoint.tsx |    4 +-
 .../src/plugins/register/sonarqube/config.tsx      |   23 +-
 .../sonarqube/connection-fields/organization.tsx   |   71 +
 grafana/dashboards/SonarQubeCloud.json             | 1503 ++++++++++++++++++++
 17 files changed, 1895 insertions(+), 24 deletions(-)

diff --git a/backend/core/models/domainlayer/codequality/cq_issues.go 
b/backend/core/models/domainlayer/codequality/cq_issues.go
index 6856b8f7c..1e9ea7134 100644
--- a/backend/core/models/domainlayer/codequality/cq_issues.go
+++ b/backend/core/models/domainlayer/codequality/cq_issues.go
@@ -52,3 +52,14 @@ type CqIssue struct {
 func (CqIssue) TableName() string {
        return "cq_issues"
 }
+
+type CqIssueImpact struct {
+       common.NoPKModel
+       CqIssueId       string `gorm:"primaryKey;type:varchar(255)"`
+       SoftwareQuality string `gorm:"primaryKey;type:varchar(255)"`
+       Severity        string `gorm:"type:varchar(100)"`
+}
+
+func (CqIssueImpact) TableName() string {
+       return "cq_issue_impacts"
+}
diff --git a/backend/core/models/domainlayer/domaininfo/domaininfo.go 
b/backend/core/models/domainlayer/domaininfo/domaininfo.go
index 6837126f8..3bec3b810 100644
--- a/backend/core/models/domainlayer/domaininfo/domaininfo.go
+++ b/backend/core/models/domainlayer/domaininfo/domaininfo.go
@@ -53,6 +53,7 @@ func GetDomainTablesInfo() []dal.Tabler {
                &codequality.CqFileMetrics{},
                &codequality.CqIssueCodeBlock{},
                &codequality.CqIssue{},
+               &codequality.CqIssueImpact{},
                &codequality.CqProject{},
                // crossdomain
                &crossdomain.Account{},
diff --git 
a/backend/core/models/migrationscripts/20241010_add_ca_issue_impacts.go 
b/backend/core/models/migrationscripts/20241010_add_ca_issue_impacts.go
new file mode 100644
index 000000000..307df0147
--- /dev/null
+++ b/backend/core/models/migrationscripts/20241010_add_ca_issue_impacts.go
@@ -0,0 +1,49 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       
"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
+       "github.com/apache/incubator-devlake/core/plugin"
+)
+
+var _ plugin.MigrationScript = (*addCqIssueImpacts)(nil)
+
+type cqIssueImpacts struct {
+       archived.NoPKModel
+       CqIssueId       string `gorm:"primaryKey;type:varchar(255)"`
+       SoftwareQuality string `gorm:"primaryKey;type:varchar(255)"`
+       Severity        string `gorm:"type:varchar(100)"`
+}
+
+type addCqIssueImpacts struct {
+}
+
+func (script *addCqIssueImpacts) Up(basicRes context.BasicRes) errors.Error {
+       return basicRes.GetDal().AutoMigrate(&cqIssueImpacts{})
+}
+
+func (*addCqIssueImpacts) Version() uint64 {
+       return 20241010162658
+}
+
+func (*addCqIssueImpacts) Name() string {
+       return "add cq_issue_impacts table"
+}
diff --git a/backend/core/models/migrationscripts/register.go 
b/backend/core/models/migrationscripts/register.go
index 709099d59..abdcde958 100644
--- a/backend/core/models/migrationscripts/register.go
+++ b/backend/core/models/migrationscripts/register.go
@@ -134,5 +134,6 @@ func All() []plugin.MigrationScript {
                new(addIsSubtaskToIssue),
                new(addIsChildToCicdPipeline),
                new(increaseCqIssueComponentLength),
+               new(addCqIssueImpacts),
        }
 }
diff --git a/backend/helpers/pluginhelper/api/api_client.go 
b/backend/helpers/pluginhelper/api/api_client.go
index 5e1535de2..1e7e57d44 100644
--- a/backend/helpers/pluginhelper/api/api_client.go
+++ b/backend/helpers/pluginhelper/api/api_client.go
@@ -62,6 +62,7 @@ type ApiClient struct {
        data       map[string]interface{}
        data_mutex sync.Mutex
 
+       authFunc      plugin.ApiClientBeforeRequest
        beforeRequest plugin.ApiClientBeforeRequest
        afterResponse plugin.ApiClientAfterResponse
        ctx           gocontext.Context
@@ -92,7 +93,7 @@ func NewApiClientFromConnection(
 
        // if connection requires authorization
        if authenticator, ok := connection.(plugin.ApiAuthenticator); ok {
-               apiClient.SetBeforeFunction(func(req *http.Request) 
errors.Error {
+               apiClient.SetAuthFunction(func(req *http.Request) errors.Error {
                        return authenticator.SetupAuthentication(req)
                })
        }
@@ -255,6 +256,16 @@ func (apiClient *ApiClient) SetBeforeFunction(callback 
plugin.ApiClientBeforeReq
        apiClient.beforeRequest = callback
 }
 
+// GetAuthFunction
+func (apiClient *ApiClient) GetAuthFunction() plugin.ApiClientBeforeRequest {
+       return apiClient.authFunc
+}
+
+// SetAuthFunction
+func (apiClient *ApiClient) SetAuthFunction(callback 
plugin.ApiClientBeforeRequest) {
+       apiClient.authFunc = callback
+}
+
 // GetAfterFunction return afterResponseFunction
 func (apiClient *ApiClient) GetAfterFunction() plugin.ApiClientAfterResponse {
        return apiClient.afterResponse
@@ -345,6 +356,14 @@ func (apiClient *ApiClient) Do(
        }
 
        var res *http.Response
+       // authFunc
+       if apiClient.authFunc != nil {
+               err = apiClient.authFunc(req)
+               if err != nil {
+                       apiClient.logError(err, "[api-client] authFunc returned 
error for %s", req.URL.String())
+                       return nil, err
+               }
+       }
        // before send
        if apiClient.beforeRequest != nil {
                err = apiClient.beforeRequest(req)
diff --git a/backend/plugins/sonarqube/impl/impl.go 
b/backend/plugins/sonarqube/impl/impl.go
index f0da89812..9aae5247b 100644
--- a/backend/plugins/sonarqube/impl/impl.go
+++ b/backend/plugins/sonarqube/impl/impl.go
@@ -80,6 +80,7 @@ func (p Sonarqube) GetTablesInfo() []dal.Tabler {
                &models.SonarqubeConnection{},
                &models.SonarqubeProject{},
                &models.SonarqubeIssue{},
+               &models.SonarqubeIssueImpact{},
                &models.SonarqubeIssueCodeBlock{},
                &models.SonarqubeHotspot{},
                &models.SonarqubeFileMetrics{},
@@ -102,6 +103,7 @@ func (p Sonarqube) SubTaskMetas() []plugin.SubTaskMeta {
                tasks.ExtractAccountsMeta,
                tasks.ConvertProjectsMeta,
                tasks.ConvertIssuesMeta,
+               tasks.ConvertIssueImpactsMeta,
                tasks.ConvertIssueCodeBlocksMeta,
                tasks.ConvertHotspotsMeta,
                tasks.ConvertFileMetricsMeta,
diff --git a/backend/plugins/sonarqube/models/connection.go 
b/backend/plugins/sonarqube/models/connection.go
index e4113e306..66c32f57c 100644
--- a/backend/plugins/sonarqube/models/connection.go
+++ b/backend/plugins/sonarqube/models/connection.go
@@ -20,9 +20,10 @@ package models
 import (
        "encoding/base64"
        "fmt"
-       "github.com/apache/incubator-devlake/core/utils"
        "net/http"
 
+       "github.com/apache/incubator-devlake/core/utils"
+
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/plugin"
        helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
@@ -49,6 +50,7 @@ func (sat SonarqubeAccessToken) GetEncodedToken() string {
 type SonarqubeConn struct {
        helper.RestConnection `mapstructure:",squash"`
        SonarqubeAccessToken  `mapstructure:",squash"`
+       Organization          string `gorm:"serializer:json" json:"org" 
mapstructure:"org"`
 }
 
 func (connection SonarqubeConn) Sanitize() SonarqubeConn {
@@ -89,3 +91,24 @@ func (connection *SonarqubeConnection) 
MergeFromRequest(target *SonarqubeConnect
        }
        return nil
 }
+
+func (connection *SonarqubeConnection) IsCloud() bool {
+       return connection.Endpoint == "https://sonarcloud.io/api/";
+}
+
+const ORG = "org"
+
+func (connection *SonarqubeConn) PrepareApiClient(apiClient plugin.ApiClient) 
errors.Error {
+       apiClient.SetData(ORG, connection.Organization)
+       apiClient.SetBeforeFunction(func(req *http.Request) errors.Error {
+               org := apiClient.GetData(ORG).(string)
+               if org != "" {
+                       query := req.URL.Query()
+                       query.Add("organization", org)
+                       req.URL.RawQuery = query.Encode()
+               }
+               return nil
+       })
+
+       return nil
+}
diff --git a/backend/plugins/sonarqube/models/migrationscripts/register.go 
b/backend/plugins/sonarqube/models/migrationscripts/20240930_add_connection_orgs.go
similarity index 50%
copy from backend/plugins/sonarqube/models/migrationscripts/register.go
copy to 
backend/plugins/sonarqube/models/migrationscripts/20240930_add_connection_orgs.go
index b11549cb8..87f64a1d4 100644
--- a/backend/plugins/sonarqube/models/migrationscripts/register.go
+++ 
b/backend/plugins/sonarqube/models/migrationscripts/20240930_add_connection_orgs.go
@@ -17,24 +17,34 @@ limitations under the License.
 
 package migrationscripts
 
-import "github.com/apache/incubator-devlake/core/plugin"
-
-// All return all the migration scripts
-func All() []plugin.MigrationScript {
-       return []plugin.MigrationScript{
-               new(addInitTables),
-               new(modifyCharacterSet),
-               new(expandProjectKey20230206),
-               new(addRawParamTableForScope),
-               new(addScopeConfigIdToProject),
-               new(modifyFileMetricsKeyLength),
-               new(modifyComponentLength),
-               new(addSonarQubeScopeConfig20231214),
-               new(modifyCommitCharacterType),
-               new(modifyCommitCharacterType0508),
-               new(updateSonarQubeScopeConfig20240614),
-               new(modifyNameLength),
-               new(changeIssueComponentType),
-               new(increaseProjectKeyLength),
-       }
+import (
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/plugin"
+       "github.com/apache/incubator-devlake/helpers/migrationhelper"
+)
+
+var _ plugin.MigrationScript = (*addOrgToConn)(nil)
+
+type connection20240930 struct {
+       Organization string
+}
+
+func (connection20240930) TableName() string {
+       return "_tool_sonarqube_connections"
+}
+
+type addOrgToConn struct {
+}
+
+func (script *addOrgToConn) Up(basicRes context.BasicRes) errors.Error {
+       return migrationhelper.AutoMigrateTables(basicRes, 
&connection20240930{})
+}
+
+func (*addOrgToConn) Version() uint64 {
+       return 20240930151715
+}
+
+func (*addOrgToConn) Name() string {
+       return "add organizations to the connections table"
 }
diff --git 
a/backend/plugins/sonarqube/models/migrationscripts/20241010_add_issue_impacts.go
 
b/backend/plugins/sonarqube/models/migrationscripts/20241010_add_issue_impacts.go
new file mode 100644
index 000000000..00ed24358
--- /dev/null
+++ 
b/backend/plugins/sonarqube/models/migrationscripts/20241010_add_issue_impacts.go
@@ -0,0 +1,55 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       
"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
+       "github.com/apache/incubator-devlake/core/plugin"
+       "github.com/apache/incubator-devlake/helpers/migrationhelper"
+)
+
+var _ plugin.MigrationScript = (*addIssueImpacts)(nil)
+
+type issueImpacts20241010 struct {
+       ConnectionId    uint64 `gorm:"primaryKey"`
+       IssueKey        string `gorm:"primaryKey;type:varchar(100)"`
+       SoftwareQuality string `gorm:"primaryKey;type:varchar(255)"`
+       Severity        string `gorm:"type:varchar(100)"`
+       archived.NoPKModel
+}
+
+func (issueImpacts20241010) TableName() string {
+       return "_tool_sonarqube_issue_impacts"
+}
+
+type addIssueImpacts struct {
+}
+
+func (script *addIssueImpacts) Up(basicRes context.BasicRes) errors.Error {
+       return migrationhelper.AutoMigrateTables(basicRes, 
&issueImpacts20241010{})
+}
+
+func (*addIssueImpacts) Version() uint64 {
+       return 20241010162943
+}
+
+func (*addIssueImpacts) Name() string {
+       return "add issue_impacts table for sonarcloud"
+}
diff --git a/backend/plugins/sonarqube/models/migrationscripts/register.go 
b/backend/plugins/sonarqube/models/migrationscripts/register.go
index b11549cb8..849f11248 100644
--- a/backend/plugins/sonarqube/models/migrationscripts/register.go
+++ b/backend/plugins/sonarqube/models/migrationscripts/register.go
@@ -36,5 +36,7 @@ func All() []plugin.MigrationScript {
                new(modifyNameLength),
                new(changeIssueComponentType),
                new(increaseProjectKeyLength),
+               new(addOrgToConn),
+               new(addIssueImpacts),
        }
 }
diff --git a/backend/plugins/sonarqube/models/sonarqube_issue.go 
b/backend/plugins/sonarqube/models/sonarqube_issue.go
index fefd75721..0c8df2292 100644
--- a/backend/plugins/sonarqube/models/sonarqube_issue.go
+++ b/backend/plugins/sonarqube/models/sonarqube_issue.go
@@ -50,3 +50,15 @@ type SonarqubeIssue struct {
 func (SonarqubeIssue) TableName() string {
        return "_tool_sonarqube_issues"
 }
+
+type SonarqubeIssueImpact struct {
+       ConnectionId    uint64 `gorm:"primaryKey"`
+       IssueKey        string `gorm:"primaryKey;type:varchar(100)"`
+       SoftwareQuality string `gorm:"primaryKey;type:varchar(255)"`
+       Severity        string `gorm:"type:varchar(100)"`
+       common.NoPKModel
+}
+
+func (SonarqubeIssueImpact) TableName() string {
+       return "_tool_sonarqube_issue_impacts"
+}
diff --git a/backend/plugins/sonarqube/tasks/issue_impacts_convertor.go 
b/backend/plugins/sonarqube/tasks/issue_impacts_convertor.go
new file mode 100644
index 000000000..be8ab451b
--- /dev/null
+++ b/backend/plugins/sonarqube/tasks/issue_impacts_convertor.go
@@ -0,0 +1,75 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tasks
+
+import (
+       "reflect"
+
+       "github.com/apache/incubator-devlake/core/dal"
+       "github.com/apache/incubator-devlake/core/errors"
+       
"github.com/apache/incubator-devlake/core/models/domainlayer/codequality"
+       "github.com/apache/incubator-devlake/core/models/domainlayer/didgen"
+       "github.com/apache/incubator-devlake/core/plugin"
+       "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+       sonarqubeModels 
"github.com/apache/incubator-devlake/plugins/sonarqube/models"
+)
+
+var ConvertIssueImpactsMeta = plugin.SubTaskMeta{
+       Name:             "convertIssueImpacts",
+       EntryPoint:       ConvertIssueImpacts,
+       EnabledByDefault: true,
+       Description:      "Convert tool layer table sonarqube_issue_impacts 
into  domain layer table cq_issue_impacts",
+       DomainTypes:      []string{plugin.DOMAIN_TYPE_CODE_QUALITY},
+}
+
+func ConvertIssueImpacts(taskCtx plugin.SubTaskContext) errors.Error {
+       db := taskCtx.GetDal()
+       rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, 
RAW_ISSUES_TABLE)
+       cursor, err := db.Cursor(
+               dal.From("_tool_sonarqube_issue_impacts p"),
+               dal.Join("LEFT JOIN _tool_sonarqube_issues i ON 
(i.connection_id = p.connection_id AND i.issue_key = p.issue_key)"),
+               dal.Where("i.connection_id = ? AND i.project_key = ?", 
data.Options.ConnectionId, data.Options.ProjectKey))
+       if err != nil {
+               return err
+       }
+       defer cursor.Close()
+
+       issueIdGen := 
didgen.NewDomainIdGenerator(&sonarqubeModels.SonarqubeIssue{})
+       converter, err := api.NewDataConverter(api.DataConverterArgs{
+               InputRowType:       
reflect.TypeOf(sonarqubeModels.SonarqubeIssueImpact{}),
+               Input:              cursor,
+               RawDataSubTaskArgs: *rawDataSubTaskArgs,
+               Convert: func(inputRow interface{}) ([]interface{}, 
errors.Error) {
+                       impact := 
inputRow.(*sonarqubeModels.SonarqubeIssueImpact)
+                       domainIssueImpact := &codequality.CqIssueImpact{
+                               CqIssueId:       
issueIdGen.Generate(data.Options.ConnectionId, impact.IssueKey),
+                               SoftwareQuality: impact.SoftwareQuality,
+                               Severity:        impact.Severity,
+                       }
+                       return []interface{}{
+                               domainIssueImpact,
+                       }, nil
+               },
+       })
+
+       if err != nil {
+               return err
+       }
+
+       return converter.Execute()
+}
diff --git a/backend/plugins/sonarqube/tasks/issues_extractor.go 
b/backend/plugins/sonarqube/tasks/issues_extractor.go
index 80c1193c9..1cd9a93c0 100644
--- a/backend/plugins/sonarqube/tasks/issues_extractor.go
+++ b/backend/plugins/sonarqube/tasks/issues_extractor.go
@@ -107,6 +107,16 @@ func ExtractIssues(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        results = append(results, codeBlock)
                                }
                        }
+
+                       for _, v := range body.Impacts {
+                               impact := &models.SonarqubeIssueImpact{
+                                       ConnectionId:    
data.Options.ConnectionId,
+                                       IssueKey:        
sonarqubeIssue.IssueKey,
+                                       SoftwareQuality: v.SoftwareQuality,
+                                       Severity:        v.Severity,
+                               }
+                               results = append(results, impact)
+                       }
                        return results, nil
                },
        })
@@ -151,6 +161,10 @@ type IssuesResponse struct {
        Type              string              `json:"type"`
        Scope             string              `json:"scope"`
        QuickFixAvailable bool                `json:"quickFixAvailable"`
+       Impacts           []struct {
+               SoftwareQuality string `json:"softwareQuality"`
+               Severity        string `json:"severity"`
+       } `json:"impacts"`
 }
 
 type flow struct {
diff --git 
a/config-ui/src/plugins/components/connection-form/fields/endpoint.tsx 
b/config-ui/src/plugins/components/connection-form/fields/endpoint.tsx
index 882951dab..4639f65e2 100644
--- a/config-ui/src/plugins/components/connection-form/fields/endpoint.tsx
+++ b/config-ui/src/plugins/components/connection-form/fields/endpoint.tsx
@@ -29,6 +29,7 @@ interface Props {
   disabled?: boolean;
   name: string;
   multipleVersions?: Record<VersionType, string>;
+  cloudName?: string;
   initialValue: string;
   value: string;
   error: string;
@@ -41,6 +42,7 @@ export const ConnectionEndpoint = ({
   disabled = false,
   name,
   multipleVersions,
+  cloudName,
   initialValue,
   value,
   setValue,
@@ -79,7 +81,7 @@ export const ConnectionEndpoint = ({
       <>
         <Block title={`${name} Version`} required>
           <Radio.Group value={version} onChange={handleChange}>
-            <Radio value="cloud">{name} Cloud</Radio>
+            <Radio value="cloud">{cloudName ? cloudName : `${name} 
Cloud`}</Radio>
             <Radio value="server" disabled={!multipleVersions.server}>
               {name} Server {multipleVersions.server ? multipleVersions.server 
: '(to be supported)'}
             </Radio>
diff --git a/config-ui/src/plugins/register/sonarqube/config.tsx 
b/config-ui/src/plugins/register/sonarqube/config.tsx
index a2922a4ee..60d1d4837 100644
--- a/config-ui/src/plugins/register/sonarqube/config.tsx
+++ b/config-ui/src/plugins/register/sonarqube/config.tsx
@@ -21,6 +21,8 @@ import { IPluginConfig } from '@/types';
 
 import Icon from './assets/icon.svg?react';
 
+import { Organization } from './connection-fields/organization';
+
 export const SonarQubeConfig: IPluginConfig = {
   plugin: 'sonarqube',
   name: 'SonarQube',
@@ -28,12 +30,31 @@ export const SonarQubeConfig: IPluginConfig = {
   sort: 11,
   connection: {
     docLink: DOC_URL.PLUGIN.SONARQUBE.BASIS,
+    initialValues: {
+      endpoint: 'https://sonarcloud.io/api/',
+    },
     fields: [
       'name',
       {
         key: 'endpoint',
-        subLabel: 'Provide the SonarQube instance API endpoint. E.g. 
http://<host>:<port>/api/',
+        multipleVersions: {
+          cloud: 'https://sonarcloud.io/api/',
+          server: ' ',
+        },
+        cloudName: 'SonarCloud',
+        subLabel: 'The URL should be `http://<sonarqube-host>:<port>/api/`',
       },
+      ({ type, initialValues, values, errors, setValues, setErrors }: any) => (
+        <Organization
+          key="organization"
+          type={type}
+          initialValues={initialValues}
+          values={values}
+          errors={errors}
+          setValues={setValues}
+          setErrors={setErrors}
+        />
+      ),
       'token',
       'proxy',
       {
diff --git 
a/config-ui/src/plugins/register/sonarqube/connection-fields/organization.tsx 
b/config-ui/src/plugins/register/sonarqube/connection-fields/organization.tsx
new file mode 100644
index 000000000..4537ed1fd
--- /dev/null
+++ 
b/config-ui/src/plugins/register/sonarqube/connection-fields/organization.tsx
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Input } from 'antd';
+
+import { Block, ExternalLink } from '@/components';
+import { useEffect } from 'react';
+
+interface Props {
+  type: 'create' | 'update';
+  initialValues: any;
+  values: any;
+  errors: any;
+  setValues: (value: any) => void;
+  setErrors: (value: any) => void;
+}
+
+export const Organization = ({ initialValues, values, setValues, setErrors }: 
Props) => {
+  const { endpoint } = values;
+
+  useEffect(() => {
+    setValues({ org: initialValues.org });
+  }, [initialValues.org]);
+
+  useEffect(() => {
+    setErrors({
+      org: values.org ? '' : 'organization is required',
+    });
+  }, [values.org]);
+
+  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    setValues({
+      org: e.target.value,
+    });
+  };
+
+  if (endpoint !== 'https://sonarcloud.io/api/') {
+    return null;
+  }
+
+  return (
+    <Block
+      title="Organization"
+      description={
+        <>
+          Copy the organization key at{' '}
+          <ExternalLink 
link="https://sonarcloud.io/account/organizations";>here</ExternalLink>. If you 
have more than
+          one, please create another connection.
+        </>
+      }
+      required
+    >
+      <Input style={{ width: 386 }} placeholder="e.g. org-1" 
value={values.org} onChange={handleChange} />
+    </Block>
+  );
+};
diff --git a/grafana/dashboards/SonarQubeCloud.json 
b/grafana/dashboards/SonarQubeCloud.json
new file mode 100644
index 000000000..1a2907038
--- /dev/null
+++ b/grafana/dashboards/SonarQubeCloud.json
@@ -0,0 +1,1503 @@
+{
+  "annotations": {
+    "list": [
+      {
+        "builtIn": 1,
+        "datasource": {
+          "type": "datasource",
+          "uid": "grafana"
+        },
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "name": "Annotations & Alerts",
+        "type": "dashboard"
+      }
+    ]
+  },
+  "editable": true,
+  "fiscalYearStartMonth": 0,
+  "graphTooltip": 0,
+  "id": 40,
+  "links": [],
+  "liveNow": false,
+  "panels": [
+    {
+      "datasource": {
+        "type": "datasource",
+        "uid": "grafana"
+      },
+      "gridPos": {
+        "h": 4,
+        "w": 24,
+        "x": 0,
+        "y": 0
+      },
+      "id": 19,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "SonarQube",
+          "url": "https://devlake.apache.org/docs/Plugins/sonarqube";
+        }
+      ],
+      "options": {
+        "code": {
+          "language": "plaintext",
+          "showLineNumbers": false,
+          "showMiniMap": false
+        },
+        "content": "- Use Cases: This dashboard shows the code quality metrics 
from SonarCloud.\n- Data Source Required: SonarCloud\n- This dashboard does not 
honor the time filter on the top-right side as SonarQube metrics are all from 
the latest scan.",
+        "mode": "markdown"
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "datasource": {
+            "type": "datasource",
+            "uid": "grafana"
+          },
+          "queryType": "randomWalk",
+          "refId": "A"
+        }
+      ],
+      "title": "Dashboard Introduction",
+      "type": "text"
+    },
+    {
+      "datasource": {
+        "type": "datasource",
+        "uid": "grafana"
+      },
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 4
+      },
+      "id": 16,
+      "targets": [
+        {
+          "datasource": {
+            "type": "datasource",
+            "uid": "grafana"
+          },
+          "refId": "A"
+        }
+      ],
+      "title": "Software Quality",
+      "type": "row"
+    },
+    {
+      "datasource": "mysql",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 0,
+        "y": 5
+      },
+      "id": 3,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Issue Count",
+          "url": "https://devlake.apache.org/docs/Metrics/CQIssueCount";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "value",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  count(distinct ci.id)\nFROM \n  cq_issues ci\n  
join cq_issue_impacts cii on ci.id = cii.cq_issue_id\nWHERE\n  ci.project_key 
in (${project_id})\n  and cii.software_quality = 'SECURITY'\n  and ci.severity 
in (${severity})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Security",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 8,
+        "y": 5
+      },
+      "id": 2,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Issue Count",
+          "url": "https://devlake.apache.org/docs/Metrics/CQIssueCount";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "center",
+        "orientation": "vertical",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "value",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  count(distinct ci.id)\nFROM \n  cq_issues ci\n  
join cq_issue_impacts cii on ci.id = cii.cq_issue_id\nWHERE\n  ci.project_key 
in (${project_id})\n  and cii.software_quality = 'RELIABILITY'\n  and 
ci.severity in (${severity})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Reliability",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 16,
+        "y": 5
+      },
+      "id": 20,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Issue Count",
+          "url": "https://devlake.apache.org/docs/Metrics/CQIssueCount";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "center",
+        "orientation": "vertical",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "value",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  count(distinct ci.id)\nFROM \n  cq_issues ci\n  
join cq_issue_impacts cii on ci.id = cii.cq_issue_id\nWHERE\n  ci.project_key 
in (${project_id})\n  and cii.software_quality = 'MAINTAINABILITY'\n  and 
ci.severity in (${severity})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Maintainability",
+      "type": "stat"
+    },
+    {
+      "collapsed": false,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 10
+      },
+      "id": 21,
+      "panels": [],
+      "title": "Security Review",
+      "type": "row"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 0,
+        "y": 11
+      },
+      "id": 4,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Issue Count",
+          "url": "https://devlake.apache.org/docs/Metrics/CQIssueCount";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  COUNT(distinct id) AS 'Security Hotspots'\nFROM 
cq_issues\nWHERE\n  project_key in (${project_id})\n  and type = 'HOTSPOTS'\n  
and severity in (${severity})\n",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Security Hotspots",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 8,
+        "y": 11
+      },
+      "id": 13,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Issue Count",
+          "url": "https://devlake.apache.org/docs/Metrics/CQIssueCount";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  CONCAT(ROUND(COUNT(IF(status != 'TO_REVIEW', 
id, NULL)) / COUNT(distinct id) * 100, 2), '%') AS 'Reviewed'\nFROM 
cq_issues\nWHERE\n  project_key in (${project_id})\n  and type = 'HOTSPOTS'\n  
and severity in (${severity})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Hotspots Reviewed",
+      "type": "stat"
+    },
+    {
+      "collapsed": false,
+      "datasource": {
+        "type": "datasource",
+        "uid": "grafana"
+      },
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 16
+      },
+      "id": 12,
+      "panels": [],
+      "targets": [
+        {
+          "datasource": {
+            "type": "datasource",
+            "uid": "grafana"
+          },
+          "refId": "A"
+        }
+      ],
+      "title": "Test & Maintainability",
+      "type": "row"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 0,
+        "y": 17
+      },
+      "id": 8,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Test",
+          "url": "https://devlake.apache.org/docs/Metrics/CQTest";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "none",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  CONCAT(ROUND((sum(lines_to_cover) - 
sum(uncovered_lines)) / sum(lines_to_cover) * 100, 1), '% ', 'Coverage on ', 
ROUND(sum(lines_to_cover) / 1000, 0),'k Lines to cover')\nFROM 
cq_file_metrics\nWHERE\n  project_key in (${project_id})\n",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Test Coverage",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "code smells"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 8,
+        "y": 17
+      },
+      "id": 14,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Maintainability-Debt",
+          "url": 
"https://devlake.apache.org/docs/Metrics/CQMaintainability-Debt";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "value",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n\tCOUNT(distinct id) as 'Code Smells'\nFROM 
cq_issues\nWHERE\n  project_key in (${project_id})\n  and type = 'CODE_SMELL'\n 
 and severity in (${severity})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Maintainability - Code Smells",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "string"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 16,
+        "y": 17
+      },
+      "id": 7,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Maintainability-Debt",
+          "url": 
"https://devlake.apache.org/docs/Metrics/CQMaintainability-Debt";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "value",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  concat(FLOOR(SUM(debt)/8/60), \" day(s) \", 
FLOOR((SUM(debt)%480)/60), \" hour(s) \") AS 'Debt'\nFROM cq_issues\nWHERE\n  
project_key in (${project_id})\n  and type = 'CODE_SMELL'\n  and severity in 
(${severity})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Maintainability - Debt",
+      "type": "stat"
+    },
+    {
+      "collapsed": false,
+      "datasource": {
+        "type": "datasource",
+        "uid": "grafana"
+      },
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 22
+      },
+      "id": 6,
+      "panels": [],
+      "targets": [
+        {
+          "datasource": {
+            "type": "datasource",
+            "uid": "grafana"
+          },
+          "refId": "A"
+        }
+      ],
+      "title": "Duplications",
+      "type": "row"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 0,
+        "y": 23
+      },
+      "id": 10,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Duplicated Blocks",
+          "url": "https://devlake.apache.org/docs/Metrics/CQDuplicatedBlocks";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  sum(duplicated_blocks)\nFROM 
cq_file_metrics\nWHERE\n  project_key in (${project_id})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Duplicated Blocks",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 8,
+        "y": 23
+      },
+      "id": 9,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Duplicated Lines",
+          "url": "https://devlake.apache.org/docs/Metrics/CQDuplicatedLines";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "none",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  CONCAT(ROUND(sum(duplicated_lines) / 
sum(num_of_lines) * 100, 1), '% ', 'Duplications on ', ROUND(sum(ncloc) / 1000, 
0),'k Lines')\nFROM cq_file_metrics\nWHERE\n  project_key in (${project_id})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Duplicated Lines",
+      "type": "stat"
+    },
+    {
+      "collapsed": false,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 28
+      },
+      "id": 22,
+      "panels": [],
+      "title": "Size",
+      "type": "row"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "short"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 0,
+        "y": 29
+      },
+      "id": 23,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Duplicated Blocks",
+          "url": "https://devlake.apache.org/docs/Metrics/CQDuplicatedBlocks";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  sum(ncloc)\nFROM cq_file_metrics\nWHERE\n  
project_key in (${project_id})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Lines of Code",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "short"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 8,
+        "y": 29
+      },
+      "id": 24,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Duplicated Blocks",
+          "url": "https://devlake.apache.org/docs/Metrics/CQDuplicatedBlocks";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  sum(num_of_lines)\nFROM 
cq_file_metrics\nWHERE\n  project_key in (${project_id})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Lines",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "short"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 16,
+        "y": 29
+      },
+      "id": 25,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Duplicated Blocks",
+          "url": "https://devlake.apache.org/docs/Metrics/CQDuplicatedBlocks";
+        }
+      ],
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "horizontal",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/.*/",
+          "values": false
+        },
+        "showPercentChange": false,
+        "text": {},
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  count(distinct file_path)\nFROM 
cq_file_metrics\nWHERE\n  project_key in (${project_id})",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Files",
+      "type": "stat"
+    },
+    {
+      "collapsed": false,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 34
+      },
+      "id": 26,
+      "panels": [],
+      "title": "Overall Code Quality Metrics",
+      "type": "row"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "custom": {
+            "align": "auto",
+            "cellOptions": {
+              "type": "color-text"
+            },
+            "filterable": false,
+            "inspect": false
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 9,
+        "w": 24,
+        "x": 0,
+        "y": 35
+      },
+      "id": 17,
+      "links": [
+        {
+          "targetBlank": true,
+          "title": "Code Quality Issue Count",
+          "url": "https://devlake.apache.org/docs/Metrics/CQIssueCount";
+        }
+      ],
+      "options": {
+        "cellHeight": "sm",
+        "footer": {
+          "countRows": false,
+          "fields": "",
+          "reducer": [
+            "sum"
+          ],
+          "show": false
+        },
+        "showHeader": true
+      },
+      "pluginVersion": "11.2.0",
+      "targets": [
+        {
+          "dataset": "lake",
+          "datasource": "mysql",
+          "editorMode": "code",
+          "format": "table",
+          "rawQuery": true,
+          "rawSql": "SELECT\n\tfile_name, num_of_lines as 'Lines of Code', 
bugs as 'Bugs', vulnerabilities as 'Vulnerabilities', code_smells as 'Code 
Smells', \n\tsecurity_hotspots as 'Security Hotspots', CONCAT(ROUND(coverage, 
2), '%') as 'Coverage', CONCAT(ROUND(duplicated_lines_density, 2), '%') as 
'Duplications'\nFROM cq_file_metrics\nWHERE\n  project_key in 
(${project_id})\nORDER BY bugs desc\nlimit 20",
+          "refId": "A",
+          "sql": {
+            "columns": [
+              {
+                "parameters": [],
+                "type": "function"
+              }
+            ],
+            "groupBy": [
+              {
+                "property": {
+                  "type": "string"
+                },
+                "type": "groupBy"
+              }
+            ],
+            "limit": 50
+          }
+        }
+      ],
+      "title": "Code Quality Metrics by Files (Top 20 order by Bugs)",
+      "type": "table"
+    }
+  ],
+  "refresh": "",
+  "schemaVersion": 39,
+  "tags": [
+    "Data Source Dashboard",
+    "Stable Data Sources"
+  ],
+  "templating": {
+    "list": [
+      {
+        "current": {
+          "selected": true,
+          "text": [
+            "All"
+          ],
+          "value": [
+            "$__all"
+          ]
+        },
+        "datasource": "mysql",
+        "definition": "select concat(name, '--', id) as text from cq_projects",
+        "hide": 0,
+        "includeAll": true,
+        "label": "SonarQube Project",
+        "multi": true,
+        "name": "project_id",
+        "options": [],
+        "query": "select concat(name, '--', id) as text from cq_projects",
+        "refresh": 1,
+        "regex": "/^(?<text>.*)--(?<value>.*)$/",
+        "skipUrlSync": false,
+        "sort": 0,
+        "type": "query"
+      },
+      {
+        "current": {
+          "selected": true,
+          "text": [
+            "All"
+          ],
+          "value": [
+            "$__all"
+          ]
+        },
+        "datasource": "mysql",
+        "definition": "select distinct severity from cq_issues where id like 
'sonar%'",
+        "hide": 0,
+        "includeAll": true,
+        "label": "Severity",
+        "multi": true,
+        "name": "severity",
+        "options": [],
+        "query": "select distinct severity from cq_issues where id like 
'sonar%'",
+        "refresh": 1,
+        "regex": "",
+        "skipUrlSync": false,
+        "sort": 0,
+        "type": "query"
+      }
+    ]
+  },
+  "time": {
+    "from": "now",
+    "to": "now"
+  },
+  "timepicker": {},
+  "timezone": "utc",
+  "title": "SonarQube Cloud",
+  "uid": "WA0qbuJ4l",
+  "version": 1,
+  "weekStart": ""
+}
\ No newline at end of file

Reply via email to