You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by ab...@apache.org on 2023/02/22 10:38:35 UTC
[incubator-devlake] branch main updated: feat(sonarqube): change field type and add unit test (#4484)
This is an automated email from the ASF dual-hosted git repository.
abeizn 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 99bffed9a feat(sonarqube): change field type and add unit test (#4484)
99bffed9a is described below
commit 99bffed9a22f2c0b5aa0ebd038a3f0d46e15e8c9
Author: Warren Chen <yi...@merico.dev>
AuthorDate: Wed Feb 22 18:38:30 2023 +0800
feat(sonarqube): change field type and add unit test (#4484)
---
.../domainlayer/codequality/cq_file_metrics.go | 14 +--
.../models/domainlayer/codequality/cq_issues.go | 4 +-
.../migrationscripts/20230208_add_code_quality.go | 11 ++-
.../migrationscripts/archived/cq_file_metrics.go | 14 +--
.../models/migrationscripts/archived/cq_issues.go | 4 +-
.../_tool_sonarqube_filemetrics.csv | 16 ++--
.../e2e/snapshot_tables/_tool_sonarqube_issues.csv | 12 +--
.../sonarqube/e2e/snapshot_tables/filemetrics.csv | 12 +--
.../e2e/snapshot_tables/issue_hotspots.csv | 6 +-
.../sonarqube/e2e/snapshot_tables/issues.csv | 6 +-
.../migrationscripts/20230111_add_init_tables.go | 13 ++-
.../archived/sonarqube_file_metrics.go | 4 +-
.../migrationscripts/archived/sonarqube_issue.go | 4 +-
.../sonarqube/models/sonarqube_file_metrics.go | 4 +-
.../plugins/sonarqube/models/sonarqube_issue.go | 4 +-
.../sonarqube/tasks/filemetrics_extractor.go | 10 +-
.../plugins/sonarqube/tasks/issues_extractor.go | 23 ++---
backend/plugins/sonarqube/tasks/shared.go | 42 +++++++++
backend/plugins/sonarqube/tasks/shared_test.go | 105 +++++++++++++++++++++
19 files changed, 239 insertions(+), 69 deletions(-)
diff --git a/backend/core/models/domainlayer/codequality/cq_file_metrics.go b/backend/core/models/domainlayer/codequality/cq_file_metrics.go
index 7a2801c0a..97416c17b 100644
--- a/backend/core/models/domainlayer/codequality/cq_file_metrics.go
+++ b/backend/core/models/domainlayer/codequality/cq_file_metrics.go
@@ -23,13 +23,13 @@ import (
type CqFileMetrics struct {
domainlayer.DomainEntity
- ProjectKey string `gorm:"index;type:varchar(255)"` //domain project key
- FileName string `json:"file_name"`
- FilePath string `json:"file_path"`
- FileLanguage string `json:"file_language"`
- CodeSmells int `json:"code_smells"`
- SqaleIndex string `json:"sqale_index"`
- SqaleRating string `json:"sqale_rating"`
+ ProjectKey string `gorm:"index;type:varchar(255)"` //domain project key
+ FileName string `json:"file_name"`
+ FilePath string `json:"file_path"`
+ FileLanguage string `json:"file_language"`
+ CodeSmells int `json:"code_smells"`
+ SqaleIndex int
+ SqaleRating float64
Bugs int `json:"bugs"`
ReliabilityRating string `json:"reliability_rating"`
Vulnerabilities int `json:"vulnerabilities"`
diff --git a/backend/core/models/domainlayer/codequality/cq_issues.go b/backend/core/models/domainlayer/codequality/cq_issues.go
index 2d658e724..bdec07115 100644
--- a/backend/core/models/domainlayer/codequality/cq_issues.go
+++ b/backend/core/models/domainlayer/codequality/cq_issues.go
@@ -31,8 +31,8 @@ type CqIssue struct {
Line int `json:"line"`
Status string `json:"status" gorm:"type:varchar(255)"`
Message string `json:"message"`
- Debt string `json:"debt" gorm:"type:varchar(255)"`
- Effort string `json:"effort" gorm:"type:varchar(255)"`
+ Debt int `json:"debt"`
+ Effort int `json:"effort"`
CommitAuthorEmail string `json:"author" gorm:"type:varchar(255)"`
Assignee string `json:"assignee" gorm:"type:varchar(255)"`
Hash string `json:"hash" gorm:"type:varchar(255)"`
diff --git a/backend/core/models/migrationscripts/20230208_add_code_quality.go b/backend/core/models/migrationscripts/20230208_add_code_quality.go
index a1d23986b..a60e5bb42 100644
--- a/backend/core/models/migrationscripts/20230208_add_code_quality.go
+++ b/backend/core/models/migrationscripts/20230208_add_code_quality.go
@@ -27,6 +27,15 @@ import (
type addCodeQuality struct{}
func (u *addCodeQuality) Up(basicRes context.BasicRes) errors.Error {
+ err := basicRes.GetDal().DropTables(
+ &archived.CqProject{},
+ &archived.CqIssue{},
+ &archived.CqIssueCodeBlock{},
+ &archived.CqFileMetrics{},
+ )
+ if err != nil {
+ return err
+ }
return migrationhelper.AutoMigrateTables(
basicRes,
&archived.CqProject{},
@@ -37,7 +46,7 @@ func (u *addCodeQuality) Up(basicRes context.BasicRes) errors.Error {
}
func (*addCodeQuality) Version() uint64 {
- return 20230208000019
+ return 20230221000022
}
func (*addCodeQuality) Name() string {
diff --git a/backend/core/models/migrationscripts/archived/cq_file_metrics.go b/backend/core/models/migrationscripts/archived/cq_file_metrics.go
index de33a8b77..399311502 100644
--- a/backend/core/models/migrationscripts/archived/cq_file_metrics.go
+++ b/backend/core/models/migrationscripts/archived/cq_file_metrics.go
@@ -19,13 +19,13 @@ package archived
type CqFileMetrics struct {
DomainEntity
- ProjectKey string `gorm:"index;type:varchar(255)"` //domain project key
- FileName string `json:"file_name"`
- FilePath string `json:"file_path"`
- FileLanguage string `json:"file_language"`
- CodeSmells int `json:"code_smells"`
- SqaleIndex string `json:"sqale_index"`
- SqaleRating string `json:"sqale_rating"`
+ ProjectKey string `gorm:"index;type:varchar(255)"` //domain project key
+ FileName string `json:"file_name"`
+ FilePath string `json:"file_path"`
+ FileLanguage string `json:"file_language"`
+ CodeSmells int `json:"code_smells"`
+ SqaleIndex int
+ SqaleRating float64
Bugs int `json:"bugs"`
ReliabilityRating string `json:"reliability_rating"`
Vulnerabilities int `json:"vulnerabilities"`
diff --git a/backend/core/models/migrationscripts/archived/cq_issues.go b/backend/core/models/migrationscripts/archived/cq_issues.go
index e548ffb94..8652137eb 100644
--- a/backend/core/models/migrationscripts/archived/cq_issues.go
+++ b/backend/core/models/migrationscripts/archived/cq_issues.go
@@ -30,8 +30,8 @@ type CqIssue struct {
Line int `json:"line"`
Status string `json:"status" gorm:"type:varchar(255)"`
Message string `json:"message"`
- Debt string `json:"debt" gorm:"type:varchar(255)"`
- Effort string `json:"effort" gorm:"type:varchar(255)"`
+ Debt int `json:"debt"`
+ Effort int `json:"effort"`
CommitAuthorEmail string `json:"author" gorm:"type:varchar(255)"`
Assignee string `json:"assignee" gorm:"type:varchar(255)"`
Hash string `json:"hash" gorm:"type:varchar(255)"`
diff --git a/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_filemetrics.csv b/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_filemetrics.csv
index 7efe88a5f..9faef947d 100644
--- a/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_filemetrics.csv
+++ b/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_filemetrics.csv
@@ -1,9 +1,9 @@
connection_id,file_metrics_key,project_key,file_name,file_path,file_language,code_smells,sqale_index,sqale_rating,bugs,reliability_rating,vulnerabilities,security_rating,security_hotspots,security_hotspots_reviewed,security_review_rating,ncloc,coverage,lines_to_cover,duplicated_lines_density,duplicated_blocks
-1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170206220334_add_start_date_to_sponsors_and_paid.rb,db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,6,0,2,0,0
-1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170208152018_acts_as_follower_migration.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170208152018_acts_as_follower_migration.rb,db/migrate/20170208152018_acts_as_follower_migration.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,15,0,8,0,0
-1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170209164016_add_email_follower_notifications.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170209164016_add_email_follower_notifications.rb,db/migrate/20170209164016_add_email_follower_notifications.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,5,0,1,0,0
-1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170213183337_add_sign_up_information_to_users.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170213183337_add_sign_up_information_to_users.rb,db/migrate/20170213183337_add_sign_up_information_to_users.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,7,0,3,0,0
-1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170216145500_add_location_fields_etc_to_users.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170216145500_add_location_fields_etc_to_users.rb,db/migrate/20170216145500_add_location_fields_etc_to_users.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,20,0,16,0,0
-1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170228174838_add_identity_data_to_users.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170228174838_add_identity_data_to_users.rb,db/migrate/20170228174838_add_identity_data_to_users.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,9,0,5,0,0
-2,e2c6d5e9-a321-4e8c-b322-03d9599ef962:db/migrate/20170302152930_add_attributes_to_tags.rb,e2c6d5e9-a321-4e8c-b322-03d9599ef962,20170302152930_add_attributes_to_tags.rb,db/migrate/20170302152930_add_attributes_to_tags.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,16,0,12,0,0
-2,e2c6d5e9-a321-4e8c-b322-03d9599ef962:db/migrate/20170303171502_add_social_image_to_tags.rb,e2c6d5e9-a321-4e8c-b322-03d9599ef962,20170303171502_add_social_image_to_tags.rb,db/migrate/20170303171502_add_social_image_to_tags.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,5,0,1,0,0
+1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170206220334_add_start_date_to_sponsors_and_paid.rb,db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,ruby,0,0,1,0,A,0,A,0,0,A,6,0,2,0,0
+1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170208152018_acts_as_follower_migration.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170208152018_acts_as_follower_migration.rb,db/migrate/20170208152018_acts_as_follower_migration.rb,ruby,0,0,1,0,A,0,A,0,0,A,15,0,8,0,0
+1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170209164016_add_email_follower_notifications.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170209164016_add_email_follower_notifications.rb,db/migrate/20170209164016_add_email_follower_notifications.rb,ruby,0,0,1,0,A,0,A,0,0,A,5,0,1,0,0
+1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170213183337_add_sign_up_information_to_users.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170213183337_add_sign_up_information_to_users.rb,db/migrate/20170213183337_add_sign_up_information_to_users.rb,ruby,0,0,1,0,A,0,A,0,0,A,7,0,3,0,0
+1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170216145500_add_location_fields_etc_to_users.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170216145500_add_location_fields_etc_to_users.rb,db/migrate/20170216145500_add_location_fields_etc_to_users.rb,ruby,0,0,1,0,A,0,A,0,0,A,20,0,16,0,0
+1,02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170228174838_add_identity_data_to_users.rb,02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170228174838_add_identity_data_to_users.rb,db/migrate/20170228174838_add_identity_data_to_users.rb,ruby,0,0,1,0,A,0,A,0,0,A,9,0,5,0,0
+2,e2c6d5e9-a321-4e8c-b322-03d9599ef962:db/migrate/20170302152930_add_attributes_to_tags.rb,e2c6d5e9-a321-4e8c-b322-03d9599ef962,20170302152930_add_attributes_to_tags.rb,db/migrate/20170302152930_add_attributes_to_tags.rb,ruby,0,0,1,0,A,0,A,0,0,A,16,0,12,0,0
+2,e2c6d5e9-a321-4e8c-b322-03d9599ef962:db/migrate/20170303171502_add_social_image_to_tags.rb,e2c6d5e9-a321-4e8c-b322-03d9599ef962,20170303171502_add_social_image_to_tags.rb,db/migrate/20170303171502_add_social_image_to_tags.rb,ruby,0,0,1,0,A,0,A,0,0,A,5,0,1,0,0
diff --git a/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_issues.csv b/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_issues.csv
index 2b5680e4f..9eca2e89b 100644
--- a/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_issues.csv
+++ b/backend/plugins/sonarqube/e2e/snapshot_tables/_tool_sonarqube_issues.csv
@@ -1,7 +1,7 @@
connection_id,issue_key,rule,severity,component,project_key,line,status,message,debt,effort,author,hash,tags,type,scope,start_line,end_line,start_offset,end_offset,creation_date,update_date
-1,AYUwBbCC46XwcL-YZOTH,java:S5993,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/FeatureDictionary.java,f5a50c63-2e8f-4107-9014-853f6f467757,24,OPEN,"Change the visibility of this constructor to ""protected"".",2min,2min,hector.yee@airbnb.com,cb21cfee164b0548717edfe840aea8a2,design,CODE_SMELL,MAIN,24,24,2,8,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
-1,AYUwBbGD46XwcL-YZOUu,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,f5a50c63-2e8f-4107-9014-853f6f467757,171,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10min,10min,hector.yee@airbnb.com,136741d9bacea2c123cc5a81be33aa4b,java8,CODE_SMELL,MAIN,171,171,25,49,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
-1,AYUwBbGD46XwcL-YZOUv,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,f5a50c63-2e8f-4107-9014-853f6f467757,182,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10min,10min,hector.yee@airbnb.com,fbe0119b6af3a6db83bfd6fdb9a6833b,java8,CODE_SMELL,MAIN,182,182,33,56,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
-2,AYYrCDQwCVdTZLqEeJtw,go:S3776,CRITICAL,testWarrenEtcd:api/etcdserverpb/etcdserver.pb.go,testWarrenEtcd,174,OPEN,Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.,11min,11min,,4b568473b2815c6fdf0ed4a6d0083517,brain-overload,CODE_SMELL,MAIN,174,174,18,38,2023-02-07T08:39:18.000+00:00,2023-02-07T08:39:18.000+00:00
-2,AYYrCDQwCVdTZLqEeJtx,go:S3776,CRITICAL,testWarrenEtcd:api/etcdserverpb/etcdserver.pb.go,testWarrenEtcd,394,OPEN,Refactor this method to reduce its Cognitive Complexity from 371 to the 15 allowed.,6h1min,6h1min,,5757b656ecd68cade0c4ffbee99d2cf0,brain-overload,CODE_SMELL,MAIN,394,394,18,27,2023-02-07T08:39:18.000+00:00,2023-02-07T08:39:18.000+00:00
-2,AYYrCDQwCVdTZLqEeJty,go:S3776,CRITICAL,testWarrenEtcd:api/etcdserverpb/etcdserver.pb.go,testWarrenEtcd,830,OPEN,Refactor this method to reduce its Cognitive Complexity from 65 to the 15 allowed.,55min,55min,,cea1920565d72b55451cd8145aa6e6fb,brain-overload,CODE_SMELL,MAIN,830,830,19,28,2023-02-07T08:39:18.000+00:00,2023-02-07T08:39:18.000+00:00
+1,AYUwBbCC46XwcL-YZOTH,java:S5993,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/FeatureDictionary.java,f5a50c63-2e8f-4107-9014-853f6f467757,24,OPEN,"Change the visibility of this constructor to ""protected"".",2,2,hector.yee@airbnb.com,cb21cfee164b0548717edfe840aea8a2,design,CODE_SMELL,MAIN,24,24,2,8,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
+1,AYUwBbGD46XwcL-YZOUu,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,f5a50c63-2e8f-4107-9014-853f6f467757,171,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10,10,hector.yee@airbnb.com,136741d9bacea2c123cc5a81be33aa4b,java8,CODE_SMELL,MAIN,171,171,25,49,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
+1,AYUwBbGD46XwcL-YZOUv,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,f5a50c63-2e8f-4107-9014-853f6f467757,182,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10,10,hector.yee@airbnb.com,fbe0119b6af3a6db83bfd6fdb9a6833b,java8,CODE_SMELL,MAIN,182,182,33,56,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
+2,AYYrCDQwCVdTZLqEeJtw,go:S3776,CRITICAL,testWarrenEtcd:api/etcdserverpb/etcdserver.pb.go,testWarrenEtcd,174,OPEN,Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.,11,11,,4b568473b2815c6fdf0ed4a6d0083517,brain-overload,CODE_SMELL,MAIN,174,174,18,38,2023-02-07T08:39:18.000+00:00,2023-02-07T08:39:18.000+00:00
+2,AYYrCDQwCVdTZLqEeJtx,go:S3776,CRITICAL,testWarrenEtcd:api/etcdserverpb/etcdserver.pb.go,testWarrenEtcd,394,OPEN,Refactor this method to reduce its Cognitive Complexity from 371 to the 15 allowed.,361,361,,5757b656ecd68cade0c4ffbee99d2cf0,brain-overload,CODE_SMELL,MAIN,394,394,18,27,2023-02-07T08:39:18.000+00:00,2023-02-07T08:39:18.000+00:00
+2,AYYrCDQwCVdTZLqEeJty,go:S3776,CRITICAL,testWarrenEtcd:api/etcdserverpb/etcdserver.pb.go,testWarrenEtcd,830,OPEN,Refactor this method to reduce its Cognitive Complexity from 65 to the 15 allowed.,55,55,,cea1920565d72b55451cd8145aa6e6fb,brain-overload,CODE_SMELL,MAIN,830,830,19,28,2023-02-07T08:39:18.000+00:00,2023-02-07T08:39:18.000+00:00
diff --git a/backend/plugins/sonarqube/e2e/snapshot_tables/filemetrics.csv b/backend/plugins/sonarqube/e2e/snapshot_tables/filemetrics.csv
index b2390e3ab..82470bddb 100644
--- a/backend/plugins/sonarqube/e2e/snapshot_tables/filemetrics.csv
+++ b/backend/plugins/sonarqube/e2e/snapshot_tables/filemetrics.csv
@@ -1,7 +1,7 @@
id,project_key,file_name,file_path,file_language,code_smells,sqale_index,sqale_rating,bugs,reliability_rating,vulnerabilities,security_rating,security_hotspots,security_hotspots_reviewed,security_review_rating,ncloc,coverage,lines_to_cover,duplicated_lines_density,duplicated_blocks
-sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170206220334_add_start_date_to_sponsors_and_paid.rb,db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,6,0,2,0,0
-sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170208152018_acts_as_follower_migration.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170208152018_acts_as_follower_migration.rb,db/migrate/20170208152018_acts_as_follower_migration.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,15,0,8,0,0
-sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170209164016_add_email_follower_notifications.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170209164016_add_email_follower_notifications.rb,db/migrate/20170209164016_add_email_follower_notifications.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,5,0,1,0,0
-sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170213183337_add_sign_up_information_to_users.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170213183337_add_sign_up_information_to_users.rb,db/migrate/20170213183337_add_sign_up_information_to_users.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,7,0,3,0,0
-sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170216145500_add_location_fields_etc_to_users.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170216145500_add_location_fields_etc_to_users.rb,db/migrate/20170216145500_add_location_fields_etc_to_users.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,20,0,16,0,0
-sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170228174838_add_identity_data_to_users.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170228174838_add_identity_data_to_users.rb,db/migrate/20170228174838_add_identity_data_to_users.rb,ruby,0,0,1.0,0,A,0,A,0,0,A,9,0,5,0,0
+sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170206220334_add_start_date_to_sponsors_and_paid.rb,db/migrate/20170206220334_add_start_date_to_sponsors_and_paid.rb,ruby,0,0,1,0,A,0,A,0,0,A,6,0,2,0,0
+sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170208152018_acts_as_follower_migration.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170208152018_acts_as_follower_migration.rb,db/migrate/20170208152018_acts_as_follower_migration.rb,ruby,0,0,1,0,A,0,A,0,0,A,15,0,8,0,0
+sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170209164016_add_email_follower_notifications.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170209164016_add_email_follower_notifications.rb,db/migrate/20170209164016_add_email_follower_notifications.rb,ruby,0,0,1,0,A,0,A,0,0,A,5,0,1,0,0
+sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170213183337_add_sign_up_information_to_users.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170213183337_add_sign_up_information_to_users.rb,db/migrate/20170213183337_add_sign_up_information_to_users.rb,ruby,0,0,1,0,A,0,A,0,0,A,7,0,3,0,0
+sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170216145500_add_location_fields_etc_to_users.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170216145500_add_location_fields_etc_to_users.rb,db/migrate/20170216145500_add_location_fields_etc_to_users.rb,ruby,0,0,1,0,A,0,A,0,0,A,20,0,16,0,0
+sonarqube:SonarqubeFileMetrics:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f:db/migrate/20170228174838_add_identity_data_to_users.rb,sonarqube:SonarqubeProject:1:02c1047b-f87c-4c35-a6b5-76c6b607d37f,20170228174838_add_identity_data_to_users.rb,db/migrate/20170228174838_add_identity_data_to_users.rb,ruby,0,0,1,0,A,0,A,0,0,A,9,0,5,0,0
diff --git a/backend/plugins/sonarqube/e2e/snapshot_tables/issue_hotspots.csv b/backend/plugins/sonarqube/e2e/snapshot_tables/issue_hotspots.csv
index 5f7a7de85..1bf95e693 100644
--- a/backend/plugins/sonarqube/e2e/snapshot_tables/issue_hotspots.csv
+++ b/backend/plugins/sonarqube/e2e/snapshot_tables/issue_hotspots.csv
@@ -1,4 +1,4 @@
id,rule,severity,component,project_key,line,status,message,debt,effort,commit_author_email,assignee,hash,tags,type,scope,start_line,end_line,start_offset,end_offset,vulnerability_probability,security_category,creation_date,update_date
-sonarqube:SonarqubeHotspot:1:AYUwBajH46XwcL-YZONY,,weak-cryptography,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/models/MlpModel.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,143,TO_REVIEW,Make sure that using this pseudorandom number generator is safe here.,,,peng.ye@airbnb.com,,,,HOTSPOTS,,143,0,0,0,MEDIUM,,2016-02-26T22:41:48.000+00:00,2022-12-20T14:50:30.000+00:00
-sonarqube:SonarqubeHotspot:1:AYUwBajH46XwcL-YZONZ,,weak-cryptography,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/models/MlpModel.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,172,TO_REVIEW,Make sure that using this pseudorandom number generator is safe here.,,,peng.ye@airbnb.com,,,,HOTSPOTS,,172,0,0,0,MEDIUM,,2016-02-26T22:41:48.000+00:00,2022-12-20T14:50:30.000+00:00
-sonarqube:SonarqubeHotspot:1:AYUwBamj46XwcL-YZOPh,,weak-cryptography,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/function/MultiDimensionSpline.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,295,REVIEWED,Make sure that using this pseudorandom number generator is safe here.,,,julian.qian@airbnb.com,,,,HOTSPOTS,,295,0,0,0,MEDIUM,,2016-04-25T19:02:16.000+00:00,2022-12-21T08:30:43.000+00:00
+sonarqube:SonarqubeHotspot:1:AYUwBajH46XwcL-YZONY,,weak-cryptography,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/models/MlpModel.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,143,TO_REVIEW,Make sure that using this pseudorandom number generator is safe here.,0,0,peng.ye@airbnb.com,,,,HOTSPOTS,,143,0,0,0,MEDIUM,,2016-02-26T22:41:48.000+00:00,2022-12-20T14:50:30.000+00:00
+sonarqube:SonarqubeHotspot:1:AYUwBajH46XwcL-YZONZ,,weak-cryptography,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/models/MlpModel.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,172,TO_REVIEW,Make sure that using this pseudorandom number generator is safe here.,0,0,peng.ye@airbnb.com,,,,HOTSPOTS,,172,0,0,0,MEDIUM,,2016-02-26T22:41:48.000+00:00,2022-12-20T14:50:30.000+00:00
+sonarqube:SonarqubeHotspot:1:AYUwBamj46XwcL-YZOPh,,weak-cryptography,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/function/MultiDimensionSpline.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,295,REVIEWED,Make sure that using this pseudorandom number generator is safe here.,0,0,julian.qian@airbnb.com,,,,HOTSPOTS,,295,0,0,0,MEDIUM,,2016-04-25T19:02:16.000+00:00,2022-12-21T08:30:43.000+00:00
diff --git a/backend/plugins/sonarqube/e2e/snapshot_tables/issues.csv b/backend/plugins/sonarqube/e2e/snapshot_tables/issues.csv
index 1069cafb4..6da8c7405 100644
--- a/backend/plugins/sonarqube/e2e/snapshot_tables/issues.csv
+++ b/backend/plugins/sonarqube/e2e/snapshot_tables/issues.csv
@@ -1,4 +1,4 @@
id,rule,severity,component,project_key,line,status,message,debt,effort,commit_author_email,assignee,hash,tags,type,scope,start_line,end_line,start_offset,end_offset,vulnerability_probability,security_category,creation_date,update_date
-sonarqube:SonarqubeIssue:1:AYUwBbCC46XwcL-YZOTH,java:S5993,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/FeatureDictionary.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,24,OPEN,"Change the visibility of this constructor to ""protected"".",2min,2min,hector.yee@airbnb.com,,cb21cfee164b0548717edfe840aea8a2,design,CODE_SMELL,MAIN,24,24,2,8,,,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
-sonarqube:SonarqubeIssue:1:AYUwBbGD46XwcL-YZOUu,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,171,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10min,10min,hector.yee@airbnb.com,,136741d9bacea2c123cc5a81be33aa4b,java8,CODE_SMELL,MAIN,171,171,25,49,,,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
-sonarqube:SonarqubeIssue:1:AYUwBbGD46XwcL-YZOUv,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,182,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10min,10min,hector.yee@airbnb.com,,fbe0119b6af3a6db83bfd6fdb9a6833b,java8,CODE_SMELL,MAIN,182,182,33,56,,,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
+sonarqube:SonarqubeIssue:1:AYUwBbCC46XwcL-YZOTH,java:S5993,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/FeatureDictionary.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,24,OPEN,"Change the visibility of this constructor to ""protected"".",2,2,hector.yee@airbnb.com,,cb21cfee164b0548717edfe840aea8a2,design,CODE_SMELL,MAIN,24,24,2,8,,,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
+sonarqube:SonarqubeIssue:1:AYUwBbGD46XwcL-YZOUu,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,171,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10,10,hector.yee@airbnb.com,,136741d9bacea2c123cc5a81be33aa4b,java8,CODE_SMELL,MAIN,171,171,25,49,,,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
+sonarqube:SonarqubeIssue:1:AYUwBbGD46XwcL-YZOUv,java:S3824,MAJOR,f5a50c63-2e8f-4107-9014-853f6f467757:core/src/main/java/com/airbnb/aerosolve/core/util/Util.java,sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757,182,OPEN,"Replace this ""Map.get()"" and condition with a call to ""Map.computeIfAbsent()"".",10,10,hector.yee@airbnb.com,,fbe0119b6af3a6db83bfd6fdb9a6833b,java8,CODE_SMELL,MAIN,182,182,33,56,,,2015-05-12T19:22:15.000+00:00,2022-12-20T14:50:30.000+00:00
diff --git a/backend/plugins/sonarqube/models/migrationscripts/20230111_add_init_tables.go b/backend/plugins/sonarqube/models/migrationscripts/20230111_add_init_tables.go
index d61ee253a..e448a5a6e 100644
--- a/backend/plugins/sonarqube/models/migrationscripts/20230111_add_init_tables.go
+++ b/backend/plugins/sonarqube/models/migrationscripts/20230111_add_init_tables.go
@@ -27,6 +27,17 @@ import (
type addInitTables struct{}
func (*addInitTables) Up(basicRes context.BasicRes) errors.Error {
+ err := basicRes.GetDal().DropTables(
+ &archived.SonarqubeProject{},
+ &archived.SonarqubeHotspot{},
+ &archived.SonarqubeIssue{},
+ &archived.SonarqubeFileMetrics{},
+ &archived.SonarqubeIssueCodeBlock{},
+ &archived.SonarqubeAccount{},
+ )
+ if err != nil {
+ return err
+ }
return migrationhelper.AutoMigrateTables(
basicRes,
&archived.SonarqubeConnection{},
@@ -40,7 +51,7 @@ func (*addInitTables) Up(basicRes context.BasicRes) errors.Error {
}
func (*addInitTables) Version() uint64 {
- return 20230208220025
+ return 20230221220030
}
func (*addInitTables) Name() string {
diff --git a/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_file_metrics.go b/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_file_metrics.go
index 95a2fa746..a288de898 100644
--- a/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_file_metrics.go
+++ b/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_file_metrics.go
@@ -29,8 +29,8 @@ type SonarqubeFileMetrics struct {
FilePath string
FileLanguage string
CodeSmells int
- SqaleIndex string
- SqaleRating string
+ SqaleIndex int
+ SqaleRating float64
Bugs int
ReliabilityRating string
Vulnerabilities int
diff --git a/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_issue.go b/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_issue.go
index 66a470c49..f457d5570 100644
--- a/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_issue.go
+++ b/backend/plugins/sonarqube/models/migrationscripts/archived/sonarqube_issue.go
@@ -32,8 +32,8 @@ type SonarqubeIssue struct {
Line int
Status string
Message string
- Debt string
- Effort string
+ Debt int
+ Effort int
Author string
Hash string
Tags string
diff --git a/backend/plugins/sonarqube/models/sonarqube_file_metrics.go b/backend/plugins/sonarqube/models/sonarqube_file_metrics.go
index da647170f..c895e44f2 100644
--- a/backend/plugins/sonarqube/models/sonarqube_file_metrics.go
+++ b/backend/plugins/sonarqube/models/sonarqube_file_metrics.go
@@ -29,8 +29,8 @@ type SonarqubeFileMetrics struct {
FilePath string
FileLanguage string
CodeSmells int
- SqaleIndex string
- SqaleRating string
+ SqaleIndex int
+ SqaleRating float64
Bugs int
ReliabilityRating string
Vulnerabilities int
diff --git a/backend/plugins/sonarqube/models/sonarqube_issue.go b/backend/plugins/sonarqube/models/sonarqube_issue.go
index bbe327e22..343a7c639 100644
--- a/backend/plugins/sonarqube/models/sonarqube_issue.go
+++ b/backend/plugins/sonarqube/models/sonarqube_issue.go
@@ -32,8 +32,8 @@ type SonarqubeIssue struct {
Line int
Status string
Message string
- Debt string
- Effort string
+ Debt int
+ Effort int
Author string
Hash string
Tags string
diff --git a/backend/plugins/sonarqube/tasks/filemetrics_extractor.go b/backend/plugins/sonarqube/tasks/filemetrics_extractor.go
index eff31792b..d3392513e 100644
--- a/backend/plugins/sonarqube/tasks/filemetrics_extractor.go
+++ b/backend/plugins/sonarqube/tasks/filemetrics_extractor.go
@@ -58,9 +58,15 @@ func ExtractFilemetrics(taskCtx plugin.SubTaskContext) errors.Error {
for _, v := range body.Measures {
switch v.Metric {
case "sqale_index":
- fileMetrics.SqaleIndex = v.Value
+ fileMetrics.SqaleIndex, err = errors.Convert01(strconv.Atoi(v.Value))
+ if err != nil {
+ return nil, err
+ }
case "sqale_rating":
- fileMetrics.SqaleRating = v.Value
+ fileMetrics.SqaleRating, err = errors.Convert01(strconv.ParseFloat(v.Value, 32))
+ if err != nil {
+ return nil, err
+ }
case "reliability_rating":
fileMetrics.ReliabilityRating = alphabetMap[v.Value]
case "security_rating":
diff --git a/backend/plugins/sonarqube/tasks/issues_extractor.go b/backend/plugins/sonarqube/tasks/issues_extractor.go
index 3facf5ead..e0b008afc 100644
--- a/backend/plugins/sonarqube/tasks/issues_extractor.go
+++ b/backend/plugins/sonarqube/tasks/issues_extractor.go
@@ -19,23 +19,19 @@ package tasks
import (
"crypto/sha256"
- "encoding/hex"
"encoding/json"
- "fmt"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/apache/incubator-devlake/plugins/sonarqube/models"
- "hash"
"strings"
)
var _ plugin.SubTaskEntryPoint = ExtractIssues
-var hashCodeBlock hash.Hash
func ExtractIssues(taskCtx plugin.SubTaskContext) errors.Error {
rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, RAW_ISSUES_TABLE)
- hashCodeBlock = sha256.New()
+ hashCodeBlock := sha256.New()
extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
RawDataSubTaskArgs: *rawDataSubTaskArgs,
Extract: func(resData *helper.RawData) ([]interface{}, errors.Error) {
@@ -54,8 +50,6 @@ func ExtractIssues(taskCtx plugin.SubTaskContext) errors.Error {
Line: body.Line,
Status: body.Status,
Message: body.Message,
- Debt: body.Debt,
- Effort: body.Effort,
Author: body.Author,
Hash: body.Hash,
Type: body.Type,
@@ -67,6 +61,14 @@ func ExtractIssues(taskCtx plugin.SubTaskContext) errors.Error {
CreationDate: body.CreationDate,
UpdateDate: body.UpdateDate,
}
+ sonarqubeIssue.Debt = convertTimeToMinutes(body.Debt)
+ if err != nil {
+ return nil, err
+ }
+ sonarqubeIssue.Effort = convertTimeToMinutes(body.Effort)
+ if err != nil {
+ return nil, err
+ }
if len(body.Tags) > 0 {
sonarqubeIssue.Tags = strings.Join(body.Tags, ",")
}
@@ -85,7 +87,7 @@ func ExtractIssues(taskCtx plugin.SubTaskContext) errors.Error {
StartOffset: location.TextRange.StartOffset,
EndOffset: location.TextRange.EndOffset,
}
- generateId(codeBlock)
+ generateId(hashCodeBlock, codeBlock)
results = append(results, codeBlock)
}
}
@@ -149,8 +151,3 @@ type Location struct {
TextRange TextRange `json:"textRange"`
Msg string `json:"msg"`
}
-
-func generateId(entity *models.SonarqubeIssueCodeBlock) {
- hashCodeBlock.Write([]byte(fmt.Sprintf("%s-%s-%d-%d-%d-%d-%s", entity.IssueKey, entity.Component, entity.StartLine, entity.EndLine, entity.StartOffset, entity.EndOffset, entity.Msg)))
- entity.Id = hex.EncodeToString(hashCodeBlock.Sum(nil))
-}
diff --git a/backend/plugins/sonarqube/tasks/shared.go b/backend/plugins/sonarqube/tasks/shared.go
index 024cffcb7..43f7d3cdf 100644
--- a/backend/plugins/sonarqube/tasks/shared.go
+++ b/backend/plugins/sonarqube/tasks/shared.go
@@ -18,11 +18,15 @@ limitations under the License.
package tasks
import (
+ "encoding/hex"
+ "fmt"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/apache/incubator-devlake/plugins/sonarqube/models"
+ "hash"
"net/http"
+ "unicode"
)
func CreateRawDataSubTaskArgs(taskCtx plugin.SubTaskContext, rawTable string) (*api.RawDataSubTaskArgs, *SonarqubeTaskData) {
@@ -85,3 +89,41 @@ func ConvertProject(sonarqubeApiProject *SonarqubeApiProject) *models.SonarqubeP
}
return sonarqubeProject
}
+
+func generateId(hashCodeBlock hash.Hash, entity *models.SonarqubeIssueCodeBlock) {
+ hashCodeBlock.Write([]byte(fmt.Sprintf("%s-%s-%d-%d-%d-%d-%s", entity.IssueKey, entity.Component, entity.StartLine, entity.EndLine, entity.StartOffset, entity.EndOffset, entity.Msg)))
+ entity.Id = hex.EncodeToString(hashCodeBlock.Sum(nil))
+}
+
+func convertTimeToMinutes(timeStr string) int {
+ days := 0
+ hours := 0
+ minutes := 0
+
+ var currentNum int
+ var currentUnit string
+
+ for i := 0; i < len(timeStr); i++ {
+ c := timeStr[i]
+
+ if unicode.IsDigit(rune(c)) {
+ currentNum = currentNum*10 + int(c-'0')
+ } else {
+ currentUnit += string(c)
+ if currentUnit == "d" {
+ days = currentNum
+ } else if currentUnit == "h" {
+ hours = currentNum
+ } else if currentUnit == "min" {
+ minutes = currentNum
+ } else {
+ continue
+ }
+ currentNum = 0
+ currentUnit = ""
+ }
+ }
+
+ totalMinutes := days*24*60 + hours*60 + minutes
+ return totalMinutes
+}
diff --git a/backend/plugins/sonarqube/tasks/shared_test.go b/backend/plugins/sonarqube/tasks/shared_test.go
new file mode 100644
index 000000000..0cd211a9e
--- /dev/null
+++ b/backend/plugins/sonarqube/tasks/shared_test.go
@@ -0,0 +1,105 @@
+/*
+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 (
+ "crypto/sha256"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/sonarqube/models"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "testing"
+)
+
+func TestConvertTimeToMinutes(t *testing.T) {
+ testCases := []struct {
+ timeStr string
+ expectedMin int
+ }{
+ //{"1min", 1},
+ //{"30min", 30},
+ //{"1h30min", 90},
+ {"1d1h30min", 1530},
+ {"3d5h10min", 4630},
+ }
+
+ for _, tc := range testCases {
+ actualMin := convertTimeToMinutes(tc.timeStr)
+ if actualMin != tc.expectedMin {
+ t.Errorf("convertTimeToMinutes(%v) = %v; expected %v", tc.timeStr, actualMin, tc.expectedMin)
+ }
+ }
+}
+
+func TestGenerateId(t *testing.T) {
+ entity := &models.SonarqubeIssueCodeBlock{
+ IssueKey: "ISSUE-123",
+ Component: "com.example:example-project",
+ StartLine: 10,
+ EndLine: 20,
+ StartOffset: 5,
+ EndOffset: 10,
+ Msg: "Example message",
+ }
+ hashCodeBlock := sha256.New()
+ generateId(hashCodeBlock, entity)
+
+ expectedId := "c590f554324b82421b898723e51b4aa9217dc897aa79e5d55b1716df88a5af1e"
+ if entity.Id != expectedId {
+ t.Errorf("generateId did not generate the expected ID. Got %v, expected %v", entity.Id, expectedId)
+ }
+}
+
+func TestGetTotalPagesFromResponse(t *testing.T) {
+ // mock response body
+ responseBody := `{
+ "paging": {
+ "pageIndex": 1,
+ "pageSize": 10,
+ "total": 20
+ },
+ "results": [
+ {"id": 1, "name": "project 1"},
+ {"id": 2, "name": "project 2"}
+ ]
+ }`
+
+ // create a mock HTTP response with the above body
+ response := &http.Response{
+ StatusCode: http.StatusOK,
+ Body: ioutil.NopCloser(strings.NewReader(responseBody)),
+ }
+
+ // create mock ApiCollectorArgs
+ args := &api.ApiCollectorArgs{
+ PageSize: 10,
+ }
+
+ // call the function to get the total number of pages
+ totalPages, err := GetTotalPagesFromResponse(response, args)
+ if err != nil {
+ t.Fatalf("Error: %v", err)
+ }
+
+ // verify the result
+ expectedPages := 2
+ if totalPages != expectedPages {
+ t.Fatalf("Expected %v pages, but got %v", expectedPages, totalPages)
+ }
+}