Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add sonarqube scope and fix some models #4369

Merged
merged 3 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions backend/plugins/sonarqube/api/scope.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
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 api

import (
"net/http"
"strconv"

"github.com/apache/incubator-devlake/core/dal"
"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"

"github.com/mitchellh/mapstructure"
)

type req struct {
Data []*models.SonarqubeProject `json:"data"`
}

// PutScope create or update sonarqube project
// @Summary create or update sonarqube project
// @Description Create or update sonarqube project
// @Tags plugins/sonarqube
// @Accept application/json
// @Param connectionId path int false "connection ID"
// @Param scope body req true "json"
// @Success 200 {object} []models.SonarqubeProject
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes [PUT]
func PutScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connectionId, _ := extractParam(input.Params)
if connectionId == 0 {
return nil, errors.BadInput.New("invalid connectionId")
}
var projects req
err := errors.Convert(mapstructure.Decode(input.Body, &projects))
if err != nil {
return nil, errors.BadInput.Wrap(err, "decoding Sonarqube project error")
}
keeper := make(map[string]struct{})
for _, project := range projects.Data {
if _, ok := keeper[project.ProjectKey]; ok {
return nil, errors.BadInput.New("duplicated item")
} else {
keeper[project.ProjectKey] = struct{}{}
}
project.ConnectionId = connectionId
err = verifyProject(project)
if err != nil {
return nil, err
}
}
err = basicRes.GetDal().CreateOrUpdate(projects.Data)
if err != nil {
return nil, errors.Default.Wrap(err, "error on saving SonarqubeProject")
}
return &plugin.ApiResourceOutput{Body: projects.Data, Status: http.StatusOK}, nil
}

// UpdateScope patch to sonarqube project
// @Summary patch to sonarqube project
// @Description patch to sonarqube project
// @Tags plugins/sonarqube
// @Accept application/json
// @Param connectionId path int false "connection ID"
// @Param projectKey path string false "project Key"
// @Param scope body models.SonarqubeProject true "json"
// @Success 200 {object} models.SonarqubeProject
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{projectKey} [PATCH]
func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connectionId, projectKey := extractParam(input.Params)
if connectionId*uint64(len(projectKey)) == 0 {
return nil, errors.BadInput.New("invalid connectionId or projectKey")
}
var project models.SonarqubeProject
err := basicRes.GetDal().First(&project, dal.Where("connection_id = ? AND project_key = ?", connectionId, projectKey))
if err != nil {
return nil, errors.Default.Wrap(err, "getting SonarqubeProject error")
}
err = api.DecodeMapStruct(input.Body, &project)
if err != nil {
return nil, errors.Default.Wrap(err, "patch sonarqube project error")
}
err = verifyProject(&project)
if err != nil {
return nil, err
}
err = basicRes.GetDal().Update(project)
if err != nil {
return nil, errors.Default.Wrap(err, "error on saving SonarqubeProject")
}
return &plugin.ApiResourceOutput{Body: project, Status: http.StatusOK}, nil
}

// GetScopeList get Sonarqube projects
// @Summary get Sonarqube projects
// @Description get Sonarqube projects
// @Tags plugins/sonarqube
// @Param connectionId path int false "connection ID"
// @Success 200 {object} []apiProject
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/ [GET]
func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
var projects []models.SonarqubeProject
connectionId, _ := extractParam(input.Params)
if connectionId == 0 {
return nil, errors.BadInput.New("invalid path params")
}
limit, offset := api.GetLimitOffset(input.Query, "pageSize", "page")
err := basicRes.GetDal().All(&projects, dal.Where("connection_id = ?", connectionId), dal.Limit(limit), dal.Offset(offset))
if err != nil {
return nil, err
}

return &plugin.ApiResourceOutput{Body: projects, Status: http.StatusOK}, nil
}

// GetScope get one Sonarqube project
// @Summary get one Sonarqube project
// @Description get one Sonarqube project
// @Tags plugins/sonarqube
// @Param connectionId path int false "connection ID"
// @Param projectKey path string false "project key"
// @Param pageSize query int false "page size, default 50"
// @Param page query int false "page size, default 1"
// @Success 200 {object} apiProject
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{projectKey} [GET]
func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
var project models.SonarqubeProject
connectionId, projectKey := extractParam(input.Params)
if connectionId*uint64(len(projectKey)) == 0 {
return nil, errors.BadInput.New("invalid path params")
}
db := basicRes.GetDal()
err := db.First(&project, dal.Where("connection_id = ? AND project_key = ?", connectionId, projectKey))
if db.IsErrorNotFound(err) {
return nil, errors.NotFound.New("record not found")
}
if err != nil {
return nil, err
}

return &plugin.ApiResourceOutput{Body: project, Status: http.StatusOK}, nil
}

func extractParam(params map[string]string) (uint64, string) {
connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
projectKey := params["projectKey"]
return connectionId, projectKey
}

func verifyProject(project *models.SonarqubeProject) errors.Error {
if project.ConnectionId == 0 {
return errors.BadInput.New("invalid connectionId")
}
if len(project.ProjectKey) == 0 {
return errors.BadInput.New("invalid project key")
}
return nil
}
2 changes: 1 addition & 1 deletion backend/plugins/sonarqube/api/swagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type SonarqubeBlueprintSetting []struct {
ConnectionID int `json:"connectionId"`
Scope []struct {
Options struct {
Id int `json:"id"`
ProjectKey string `json:"projectKey"`
} `json:"options"`
Entities []string `json:"entities"`
} `json:"scopes"`
Expand Down
11 changes: 10 additions & 1 deletion backend/plugins/sonarqube/impl/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ package impl

import (
"fmt"
"github.com/apache/incubator-devlake/core/dal"
"time"

"github.com/apache/incubator-devlake/core/dal"

"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
Expand Down Expand Up @@ -161,6 +162,14 @@ func (p Sonarqube) ApiResources() map[string]map[string]plugin.ApiResourceHandle
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
"connections/:connectionId/scopes/:projectKey": {
"GET": api.GetScope,
"PATCH": api.UpdateScope,
},
"connections/:connectionId/scopes": {
"GET": api.GetScopeList,
"PUT": api.PutScope,
},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (*addInitTables) Up(basicRes context.BasicRes) errors.Error {
}

func (*addInitTables) Version() uint64 {
return 20230207220025
return 20230208220025
}

func (*addInitTables) Name() string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,28 @@ import (
)

type SonarqubeFileMetrics struct {
ConnectionId uint64 `gorm:"primaryKey"`
FileMetricsKey string `json:"component_key" gorm:"primaryKey"`
ProjectKey string `json:"project" gorm:"index"`
BatchID string `json:"batch_id"`
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"`
Bugs int `json:"bugs"`
ReliabilityRating string `json:"reliability_rating"`
Vulnerabilities int `json:"vulnerabilities"`
SecurityRating string `json:"security_rating"`
SecurityHotspots int `json:"security_hotspots"`
SecurityHotspotsReviewed float64 `json:"security_hotspots_reviewed"`
SecurityReviewRating string `json:"security_review_rating"`
Ncloc int `json:"ncloc"`
Coverage float64 `json:"coverage"`
LinesToCover int `json:"lines_to_cover"`
DuplicatedLinesDensity float64 `json:"duplicated_lines_density"`
DuplicatedBlocks int `json:"duplicated_blocks"`
ConnectionId uint64 `gorm:"primaryKey"`
FileMetricsKey string `gorm:"primaryKey"`
ProjectKey string `gorm:"index"`
BatchID string
FileName string
FilePath string
FileLanguage string
CodeSmells int
SqaleIndex string
SqaleRating string
Bugs int
ReliabilityRating string
Vulnerabilities int
SecurityRating string
SecurityHotspots int
SecurityHotspotsReviewed float64
SecurityReviewRating string
Ncloc int
Coverage float64
LinesToCover int
DuplicatedLinesDensity float64
DuplicatedBlocks int
archived.NoPKModel
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@ import (
)

type SonarqubeHotspot struct {
ConnectionId uint64 `gorm:"primaryKey"`
HotspotKey string `json:"key" gorm:"primaryKey"`
RuleKey string `json:"ruleKey"`
Component string `json:"component" gorm:"index"`
ProjectKey string `json:"project" gorm:"index"`
BatchId string `json:"batchId" gorm:"type:varchar(100)"` // from collection time
Line int `json:"line"`
Status string `json:"status"`
Message string `json:"message"`
Author string `json:"author"`
Assignee string `json:"assignee"`
SecurityCategory string `json:"securityCategory"`
VulnerabilityProbability string `json:"vulnerabilityProbability"`
CreationDate *api.Iso8601Time `json:"creationDate"`
UpdateDate *api.Iso8601Time `json:"updateDate"`
ConnectionId uint64 `gorm:"primaryKey"`
HotspotKey string `gorm:"primaryKey"`
RuleKey string
Component string `gorm:"index"`
ProjectKey string `gorm:"index"`
BatchId string `gorm:"type:varchar(100)"` // from collection time
Line int
Status string
Message string
Author string
Assignee string
SecurityCategory string
VulnerabilityProbability string
CreationDate *api.Iso8601Time
UpdateDate *api.Iso8601Time
archived.NoPKModel
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,29 @@ import (
)

type SonarqubeIssue struct {
ConnectionId uint64 `gorm:"primaryKey"`
IssueKey string `json:"key" gorm:"primaryKey"`
Rule string `json:"rule" gorm:"type:varchar(255)"`
Severity string `json:"severity" gorm:"type:varchar(255)"`
Component string `json:"component" gorm:"type:varchar(255)"`
ProjectKey string `gorm:"index;type:varchar(255)"` //domain project key
BatchId string `json:"batchId" gorm:"type:varchar(100)"` // from collection time
Line int `json:"line"`
Status string `json:"status"`
Message string `json:"message"`
Debt string `json:"debt"`
Effort string `json:"effort"`
Author string `json:"author"`
Hash string `json:"hash"`
Tags string `json:"tags"`
Type string `json:"type"`
Scope string `json:"scope"`
StartLine int `json:"startLine"`
EndLine int `json:"endLine"`
StartOffset int `json:"startOffset"`
EndOffset int `json:"endOffset"`
CreationDate *api.Iso8601Time `json:"creationDate"`
UpdateDate *api.Iso8601Time `json:"updateDate"`
ConnectionId uint64 `gorm:"primaryKey"`
IssueKey string `gorm:"primaryKey"`
Rule string `gorm:"type:varchar(255)"`
Severity string `gorm:"type:varchar(255)"`
Component string `gorm:"type:varchar(255)"`
ProjectKey string `gorm:"index;type:varchar(255)"` //domain project key
BatchId string `gorm:"type:varchar(100)"` // from collection time
Line int
Status string
Message string
Debt string
Effort string
Author string
Hash string
Tags string
Type string
Scope string
StartLine int
EndLine int
StartOffset int
EndOffset int
CreationDate *api.Iso8601Time
UpdateDate *api.Iso8601Time
archived.NoPKModel
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import "github.com/apache/incubator-devlake/core/models/migrationscripts/archive
type SonarqubeIssueCodeBlock struct {
ConnectionId uint64 `gorm:"primaryKey"`
Id string `gorm:"primaryKey"`
IssueKey string `json:"key" gorm:"index"`
Component string `json:"component" gorm:"index"`
StartLine int `json:"startLine" `
EndLine int `json:"endLine" `
StartOffset int `json:"startOffset" `
EndOffset int `json:"endOffset" `
Msg string `json:"msg" `
IssueKey string `gorm:"index"`
Component string `gorm:"index"`
StartLine int
EndLine int
StartOffset int
EndOffset int
Msg string
archived.NoPKModel
}

Expand Down
Loading