This is an automated email from the ASF dual-hosted git repository. warren pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 1980cb39b70c92e117b84d84e1801b3a39dc543c Author: Yingchu Chen <[email protected]> AuthorDate: Thu Jun 2 16:57:24 2022 +0800 minor fixes Signed-off-by: Yingchu Chen <[email protected]> --- .../pages/configure/connections/ConnectionForm.jsx | 4 +- config-ui/webpack.config.js | 18 ++- config-ui/webpack.production.config.js | 18 ++- plugins/gitlab/gitlab.go | 3 + plugins/helper/connection.go | 118 +++++++++------- plugins/helper/connection_test.go | 108 +++++++------- plugins/helper/worker_scheduler_test.go | 2 +- plugins/jira/api/connection.go | 155 ++------------------- plugins/jira/api/init.go | 4 - plugins/jira/api/proxy.go | 2 +- plugins/jira/jira.go | 9 -- plugins/jira/models/connection.go | 15 -- .../migrationscripts/updateSchemas20220601.go | 7 +- plugins/jira/tasks/api_client.go | 2 +- plugins/jira/tasks/apiv2models/issue.go | 12 +- plugins/jira/tasks/issue_extractor.go | 2 +- plugins/tapd/api/connection.go | 27 ---- plugins/tapd/tapd.go | 8 +- runner/directrun.go | 3 +- 19 files changed, 188 insertions(+), 329 deletions(-) diff --git a/config-ui/src/pages/configure/connections/ConnectionForm.jsx b/config-ui/src/pages/configure/connections/ConnectionForm.jsx index e5fe71d2..2e657c13 100644 --- a/config-ui/src/pages/configure/connections/ConnectionForm.jsx +++ b/config-ui/src/pages/configure/connections/ConnectionForm.jsx @@ -413,7 +413,7 @@ export default function ConnectionForm (props) { ? labels.username : ( <>Username</> - )} + )} <span className='requiredStar'>*</span> </Label> <InputGroup @@ -456,7 +456,7 @@ export default function ConnectionForm (props) { ? labels.password : ( <>Password</> - )} + )} <span className='requiredStar'>*</span> </Label> <InputGroup diff --git a/config-ui/webpack.config.js b/config-ui/webpack.config.js index 5a253b25..51bd6a5f 100644 --- a/config-ui/webpack.config.js +++ b/config-ui/webpack.config.js @@ -1,4 +1,20 @@ -// DEVELOPMENT ONLY WEBPACK CONFIG +/* + * 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. + * + */ const path = require('path') const webpack = require('webpack') const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin diff --git a/config-ui/webpack.production.config.js b/config-ui/webpack.production.config.js index a8c34ae9..6989bd41 100644 --- a/config-ui/webpack.production.config.js +++ b/config-ui/webpack.production.config.js @@ -1,4 +1,20 @@ -/* eslint-disable import/no-extraneous-dependencies */ +/* + * 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. + * + */ const path = require('path') const webpack = require('webpack') const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin diff --git a/plugins/gitlab/gitlab.go b/plugins/gitlab/gitlab.go index 7d2be2e5..e9a9f77d 100644 --- a/plugins/gitlab/gitlab.go +++ b/plugins/gitlab/gitlab.go @@ -41,6 +41,9 @@ func main() { } wsList := make([]*models.TapdWorkspace, 0) err = db.Find(&wsList, "parent_id = ?", 59169984).Error + if err != nil { + panic(err) + } projectList := []uint64{63281714, 34276182, 46319043, diff --git a/plugins/helper/connection.go b/plugins/helper/connection.go index 17933a5c..30e9ab0d 100644 --- a/plugins/helper/connection.go +++ b/plugins/helper/connection.go @@ -1,3 +1,20 @@ +/* +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 helper import ( @@ -21,7 +38,7 @@ type BaseConnection struct { type BasicAuth struct { Username string `mapstructure:"username" validate:"required" json:"username"` - Password string `mapstructure:"password" validate:"required" json:"password" encryptField:"yes"` + Password string `mapstructure:"password" validate:"required" json:"password" encrypt:"yes"` } func (ba BasicAuth) GetEncodedToken() string { @@ -29,7 +46,7 @@ func (ba BasicAuth) GetEncodedToken() string { } type AccessToken struct { - Token string `mapstructure:"token" validate:"required" json:"token" encryptField:"yes"` + Token string `mapstructure:"token" validate:"required" json:"token" encrypt:"yes"` } type RestConnection struct { @@ -39,55 +56,50 @@ type RestConnection struct { RateLimit int `comment:"api request rate limt per hour" json:"rateLimit"` } -// RefreshAndSaveConnection populate from request input into connection which come from REST functions to connection struct and save to DB +// CreateConnection populate from request input into connection which come from REST functions to connection struct and save to DB // and only change value which `data` has // mergeFieldsToConnection merges fields from data // `connection` is the pointer of a plugin connection // `data` is http request input param -func RefreshAndSaveConnection(connection interface{}, data map[string]interface{}, db *gorm.DB) error { +func CreateConnection(data map[string]interface{}, connection interface{}, db *gorm.DB) error { var err error // update fields from request body err = mergeFieldsToConnection(connection, data) if err != nil { return err } - err = saveToDb(connection, db) - if err != nil { return err } return nil } -func saveToDb(connection interface{}, db *gorm.DB) error { - dataVal := reflect.ValueOf(connection) - if dataVal.Kind() != reflect.Ptr { - panic("entityPtr is not a pointer") - } - encKey, err := getEncKey() +func PatchConnection(input *core.ApiResourceInput, connection interface{}, db *gorm.DB) error { + err := GetConnection(input.Params, connection, db) if err != nil { return err } - dataType := reflect.Indirect(dataVal).Type() - fieldName := firstFieldNameWithTag(dataType, "encryptField") - plainPwd := "" - err = encryptField(dataVal, fieldName, encKey) + + err = CreateConnection(input.Body, connection, db) if err != nil { return err } - err = db.Clauses(clause.OnConflict{UpdateAll: true}).Save(connection).Error + + return nil +} + +func saveToDb(connection interface{}, db *gorm.DB) error { + err := EncryptConnection(connection) if err != nil { return err } - - err = decryptField(dataVal, fieldName, encKey) + err = db.Clauses(clause.OnConflict{UpdateAll: true}).Save(connection).Error if err != nil { return err } - dataVal.Elem().FieldByName(fieldName).Set(reflect.ValueOf(plainPwd)) - return err + return DecryptConnection(connection) } // mergeFieldsToConnection will populate all value in map to connection struct and validate the struct @@ -110,7 +122,6 @@ func mergeFieldsToConnection(specificConnection interface{}, connections ...map[ } func getEncKey() (string, error) { - // encryptField v := config.GetConfig() encKey := v.GetString(core.EncodeKeyEnvStr) if encKey == "" { @@ -125,34 +136,44 @@ func getEncKey() (string, error) { return encKey, nil } -// FindConnectionByInput finds connection from db by parsing request input and decrypt it -func FindConnectionByInput(input *core.ApiResourceInput, connection interface{}, db *gorm.DB) error { - dataVal := reflect.ValueOf(connection) - if dataVal.Kind() != reflect.Ptr { - return fmt.Errorf("connection is not a pointer") - } - - id, err := GetConnectionIdByInputParam(input) +// GetConnection finds connection from db by parsing request input and decrypt it +func GetConnection(data map[string]string, connection interface{}, db *gorm.DB) error { + id, err := GetConnectionIdByInputParam(data) if err != nil { return fmt.Errorf("invalid connectionId") } err = db.First(connection, id).Error if err != nil { - fmt.Printf("--- %s", err.Error()) return err } - dataType := reflect.Indirect(dataVal).Type() + return DecryptConnection(connection) - fieldName := firstFieldNameWithTag(dataType, "encryptField") - return decryptField(dataVal, fieldName, "") +} +// ListConnections returns all connections with password/token decrypted +func ListConnections(connections interface{}, db *gorm.DB) error { + err := db.Find(connections).Error + connPtr := reflect.ValueOf(connections) + connVal := reflect.Indirect(connPtr) + if err != nil { + return err + } + for i := 0; i < connVal.Len(); i++ { + //connVal.Index(i) returns value of ith elem in connections, .Elem() reutrns the original elem + tmp := connVal.Index(i).Elem() + err = DecryptConnection(tmp.Addr().Interface()) + if err != nil { + return err + } + } + return nil } // GetConnectionIdByInputParam gets connectionId by parsing request input -func GetConnectionIdByInputParam(input *core.ApiResourceInput) (uint64, error) { - connectionId := input.Params["connectionId"] +func GetConnectionIdByInputParam(data map[string]string) (uint64, error) { + connectionId := data["connectionId"] if connectionId == "" { return 0, fmt.Errorf("missing connectionId") } @@ -175,7 +196,7 @@ func firstFieldNameWithTag(t reflect.Type, tag string) string { } // DecryptConnection decrypts password/token field for connection -func DecryptConnection(connection interface{}, fieldName string) error { +func DecryptConnection(connection interface{}) error { dataVal := reflect.ValueOf(connection) if dataVal.Kind() != reflect.Ptr { panic("connection is not a pointer") @@ -184,23 +205,26 @@ func DecryptConnection(connection interface{}, fieldName string) error { if err != nil { return nil } - if len(fieldName) == 0 { - dataType := reflect.Indirect(dataVal).Type() - fieldName = firstFieldNameWithTag(dataType, "encryptField") - } - return decryptField(dataVal, fieldName, encKey) -} - -func decryptField(dataVal reflect.Value, fieldName string, encKey string) error { + dataType := reflect.Indirect(dataVal).Type() + fieldName := firstFieldNameWithTag(dataType, "encrypt") if len(fieldName) > 0 { decryptStr, _ := core.Decrypt(encKey, dataVal.Elem().FieldByName(fieldName).String()) - dataVal.Elem().FieldByName(fieldName).Set(reflect.ValueOf(decryptStr)) } return nil } -func encryptField(dataVal reflect.Value, fieldName string, encKey string) error { +func EncryptConnection(connection interface{}) error { + dataVal := reflect.ValueOf(connection) + if dataVal.Kind() != reflect.Ptr { + panic("connection is not a pointer") + } + encKey, err := getEncKey() + if err != nil { + return err + } + dataType := reflect.Indirect(dataVal).Type() + fieldName := firstFieldNameWithTag(dataType, "encrypt") if len(fieldName) > 0 { plainPwd := dataVal.Elem().FieldByName(fieldName).String() encyptedStr, err := core.Encrypt(encKey, plainPwd) diff --git a/plugins/helper/connection_test.go b/plugins/helper/connection_test.go index 606730f3..bd1c7cc2 100644 --- a/plugins/helper/connection_test.go +++ b/plugins/helper/connection_test.go @@ -18,24 +18,24 @@ limitations under the License. package helper import ( - "github.com/apache/incubator-devlake/config" - "github.com/apache/incubator-devlake/plugins/core" + "github.com/stretchr/testify/assert" "reflect" "testing" - - "github.com/stretchr/testify/assert" ) -type TestConnection struct { +type MockConnection struct { RestConnection `mapstructure:",squash"` BasicAuth `mapstructure:",squash"` - EpicKeyField string `gorm:"type:varchar(50);" json:"epicKeyField"` StoryPointField string `gorm:"type:varchar(50);" json:"storyPointField"` RemotelinkCommitShaPattern string `gorm:"type:varchar(255);comment='golang regexp, the first group will be recognized as commit sha, ref https://github.com/google/re2/wiki/Syntax'" json:"remotelinkCommitShaPattern"` } +func (MockConnection) TableName() string { + return "_tool_jira_connections" +} + func TestMergeFieldsToConnection(t *testing.T) { - v := &TestConnection{ + v := &MockConnection{ RestConnection: RestConnection{ BaseConnection: BaseConnection{ Name: "1", @@ -48,8 +48,6 @@ func TestMergeFieldsToConnection(t *testing.T) { Username: "4", Password: "5", }, - EpicKeyField: "6", - StoryPointField: "7", RemotelinkCommitShaPattern: "8", } data := make(map[string]interface{}) @@ -58,9 +56,7 @@ func TestMergeFieldsToConnection(t *testing.T) { data["Password"] = "5-5" err := mergeFieldsToConnection(v, data) - if err != nil { - return - } + assert.Nil(t, err) assert.Equal(t, "4-4", v.Username) assert.Equal(t, "2-2", v.Endpoint) @@ -68,7 +64,7 @@ func TestMergeFieldsToConnection(t *testing.T) { } func TestDecryptAndEncrypt(t *testing.T) { - v := &TestConnection{ + v := &MockConnection{ RestConnection: RestConnection{ BaseConnection: BaseConnection{ Name: "1", @@ -81,28 +77,21 @@ func TestDecryptAndEncrypt(t *testing.T) { Username: "4", Password: "5", }, - EpicKeyField: "6", - StoryPointField: "7", RemotelinkCommitShaPattern: "8", } - dataVal := reflect.ValueOf(v) - encKey := "test" - err := encryptField(dataVal, "Password", encKey) - if err != nil { - return - } + err := EncryptConnection(v) + assert.Nil(t, err) + assert.NotEqual(t, "5", v.Password) - err = decryptField(dataVal, "Password", encKey) - if err != nil { - return - } + err = DecryptConnection(v) + assert.Nil(t, err) assert.Equal(t, "5", v.Password) } func TestDecryptConnection(t *testing.T) { - v := &TestConnection{ + v := &MockConnection{ RestConnection: RestConnection{ BaseConnection: BaseConnection{ Name: "1", @@ -115,46 +104,20 @@ func TestDecryptConnection(t *testing.T) { Username: "4", Password: "5", }, - EpicKeyField: "6", - StoryPointField: "7", RemotelinkCommitShaPattern: "8", } - encKey, err := getEncKey() - if err != nil { - return - } - dataVal := reflect.ValueOf(v) - err = encryptField(dataVal, "Password", encKey) - if err != nil { - return - } + err := EncryptConnection(v) + assert.Nil(t, err) + encryptedPwd := v.Password - err = DecryptConnection(v, "Password") - if err != nil { - return - } + err = DecryptConnection(v) + assert.Nil(t, err) assert.NotEqual(t, encryptedPwd, v.Password) assert.Equal(t, "5", v.Password) } -func TestGetEncKey(t *testing.T) { - // encryptField - v := config.GetConfig() - encKey := v.GetString(core.EncodeKeyEnvStr) - str, err := getEncKey() - if err != nil { - return - } - if len(encKey) > 0 { - assert.Equal(t, encKey, str) - } else { - assert.NotEqual(t, 0, len(str)) - } - -} - func TestFirstFieldNameWithTag(t *testing.T) { - v := &TestConnection{ + v := &MockConnection{ RestConnection: RestConnection{ BaseConnection: BaseConnection{ Name: "1", @@ -167,12 +130,37 @@ func TestFirstFieldNameWithTag(t *testing.T) { Username: "4", Password: "5", }, - EpicKeyField: "6", StoryPointField: "7", RemotelinkCommitShaPattern: "8", } dataVal := reflect.ValueOf(v) dataType := reflect.Indirect(dataVal).Type() - fieldName := firstFieldNameWithTag(dataType, "encryptField") + fieldName := firstFieldNameWithTag(dataType, "encrypt") assert.Equal(t, "Password", fieldName) } + +//func TestListConnections(t *testing.T) { +// jiraConnections := make([]*MockConnection, 0) +// cfg := config.GetConfig() +// dbUrl := cfg.GetString("DB_URL") +// u, err := url.Parse(dbUrl) +// dbUrl = fmt.Sprintf("%s@tcp(%s)%s?%s", u.User.String(), u.Host, u.Path, u.RawQuery) +// dbConfig := &gorm.Config{ +// Logger: gormLogger.New( +// log.Default(), +// gormLogger.Config{ +// SlowThreshold: time.Second, // Slow SQL threshold +// LogLevel: gormLogger.Error, // Log level +// IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger +// Colorful: true, // Disable color +// }, +// ), +// // most of our operation are in batch, this can improve performance +// PrepareStmt: true, +// } +// db, err := gorm.Open(mysql.Open(dbUrl), dbConfig) +// +// err = ListConnections(&jiraConnections, db) +// +// assert.Nil(t, err) +//} diff --git a/plugins/helper/worker_scheduler_test.go b/plugins/helper/worker_scheduler_test.go index a3de7adb..4f65e7a0 100644 --- a/plugins/helper/worker_scheduler_test.go +++ b/plugins/helper/worker_scheduler_test.go @@ -88,7 +88,7 @@ func TestNewWorkerSchedulerWithoutSecond(t *testing.T) { func TestNewWorkerSchedulerWithPanic(t *testing.T) { testChannel := make(chan int, 100) ctx, cancel := context.WithCancel(context.Background()) - s, _ := NewWorkerScheduler(1, 1, ctx) + s,_ := NewWorkerScheduler(1, 1, ctx) defer s.Release() _ = s.Submit(func() error { testChannel <- 1 diff --git a/plugins/jira/api/connection.go b/plugins/jira/api/connection.go index aa94537a..0c422bbe 100644 --- a/plugins/jira/api/connection.go +++ b/plugins/jira/api/connection.go @@ -21,7 +21,6 @@ import ( "fmt" "net/http" "net/url" - "strconv" "strings" "time" @@ -103,19 +102,8 @@ POST /plugins/jira/connections { "name": "jira data connection name", "endpoint": "jira api endpoint, i.e. https://merico.atlassian.net/rest", - "basicAuthEncoded": "generated by `echo -n <jira login email>:<jira token> | base64`", - "epicKeyField": "name of customfield of epic key", - "storyPointField": "name of customfield of story point", - "typeMappings": { // optional, send empty object to delete all typeMappings of the data connection - "userType": { - "standardType": "devlake standard type", - "statusMappings": { // optional, send empt object to delete all status mapping for the user type - "userStatus": { - "standardStatus": "devlake standard status" - } - } - } - } + "username": "username, usually should be email address", + "password": "jira api access token" } */ func PostConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { @@ -123,7 +111,7 @@ func PostConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, err jiraConnection := &models.JiraConnection{} // update from request and save to database - err := helper.RefreshAndSaveConnection(jiraConnection, input.Body, db) + err := helper.CreateConnection(input.Body, jiraConnection, db) if err != nil { return nil, err } @@ -136,31 +124,13 @@ PATCH /plugins/jira/connections/:connectionId { "name": "jira data connection name", "endpoint": "jira api endpoint, i.e. https://merico.atlassian.net/rest", - "basicAuthEncoded": "generated by `echo -n <jira login email>:<jira token> | base64`", - "epicKeyField": "name of customfield of epic key", - "storyPointField": "name of customfield of story point", - "typeMappings": { // optional, send empty object to delete all typeMappings of the data connection - "userType": { - "standardType": "devlake standard type", - "statusMappings": { // optional, send empt object to delete all status mapping for the user type - "userStatus": { - "standardStatus": "devlake standard status" - } - } - } - } + "username": "username, usually should be email address", + "password": "jira api access token" } */ func PatchConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { jiraConnection := &models.JiraConnection{} - // load from db - err := helper.FindConnectionByInput(input, jiraConnection, db) - if err != nil { - return nil, err - } - - // update from request and save to database - err = helper.RefreshAndSaveConnection(jiraConnection, input.Body, db) + err := helper.PatchConnection(input, jiraConnection, db) if err != nil { return nil, err } @@ -173,7 +143,7 @@ DELETE /plugins/jira/connections/:connectionId */ func DeleteConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { // load from db - jiraConnectionID, err := helper.GetConnectionIdByInputParam(input) + jiraConnectionID, err := helper.GetConnectionIdByInputParam(input.Params) if err != nil { return nil, err } @@ -182,15 +152,6 @@ func DeleteConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, er if err != nil { return nil, err } - err = db.Where("connection_id = ?", jiraConnectionID).Delete(&models.JiraIssueTypeMapping{}).Error - if err != nil { - return nil, err - } - err = db.Where("connection_id = ?", jiraConnectionID).Delete(&models.JiraIssueStatusMapping{}).Error - if err != nil { - return nil, err - } - return &core.ApiResourceOutput{Body: jiraConnectionID}, nil } @@ -199,17 +160,11 @@ GET /plugins/jira/connections */ func ListConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { jiraConnections := make([]*models.JiraConnection, 0) - err := db.Find(&jiraConnections).Error + + err := helper.ListConnections(&jiraConnections, db) if err != nil { return nil, err } - for i, _ := range jiraConnections { - err = helper.DecryptConnection(jiraConnections[i], "Password") - if err != nil { - return nil, err - } - } - return &core.ApiResourceOutput{Body: jiraConnections, Status: http.StatusOK}, nil } @@ -220,100 +175,16 @@ GET /plugins/jira/connections/:connectionId { "name": "jira data connection name", "endpoint": "jira api endpoint, i.e. https://merico.atlassian.net/rest", - "basicAuthEncoded": "generated by `echo -n <jira login email>:<jira token> | base64`", - "epicKeyField": "name of customfield of epic key", - "storyPointField": "name of customfield of story point", - "typeMappings": { // optional, send empty object to delete all typeMappings of the data connection - "userType": { - "standardType": "devlake standard type", - "statusMappings": { // optional, send empt object to delete all status mapping for the user type - "userStatus": { - "standardStatus": "devlake standard status" - } - } - } - } + "username": "username, usually should be email address", + "password": "jira api access token" } */ func GetConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { jiraConnection := &models.JiraConnection{} - err := helper.FindConnectionByInput(input, jiraConnection, db) + err := helper.GetConnection(input.Params, jiraConnection, db) if err != nil { return nil, err } - detail := &models.JiraConnectionDetail{ - JiraConnection: *jiraConnection, - } - - if err != nil { - return nil, err - } - - return &core.ApiResourceOutput{Body: detail}, nil -} - -// GET /plugins/jira/connections/:connectionId/epics -func GetEpicsByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { - jiraConnection := &models.JiraConnection{} - err := helper.FindConnectionByInput(input, jiraConnection, db) - if err != nil { - return nil, err - } - return &core.ApiResourceOutput{Body: [1]models.EpicResponse{{ - Id: 1, - Title: jiraConnection.EpicKeyField, - Value: jiraConnection.EpicKeyField, - }}}, nil -} - -// GET /plugins/jira/connections/:connectionId/granularities -type GranularitiesResponse struct { - Id int - Title string - Value string -} - -func GetGranularitiesByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { - jiraConnection := &models.JiraConnection{} - err := helper.FindConnectionByInput(input, jiraConnection, db) - if err != nil { - return nil, err - } - if err != nil { - return nil, err - } - return &core.ApiResourceOutput{Body: [1]GranularitiesResponse{ - { - Id: 1, - Title: "Story Point Field", - Value: jiraConnection.StoryPointField, - }, - }}, nil -} - -// GET /plugins/jira/connections/:connectionId/boards -func GetBoardsByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { - connectionId := input.Params["connectionId"] - if connectionId == "" { - return nil, fmt.Errorf("missing connectionid") - } - jiraConnectionId, err := strconv.ParseUint(connectionId, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid connectionId") - } - var jiraBoards []models.JiraBoard - err = db.Where("connection_Id = ?", jiraConnectionId).Find(&jiraBoards).Error - if err != nil { - return nil, err - } - var boardResponses []models.BoardResponse - for _, board := range jiraBoards { - boardResponses = append(boardResponses, models.BoardResponse{ - Id: int(board.BoardId), - Title: board.Name, - Value: fmt.Sprintf("%v", board.BoardId), - }) - } - return &core.ApiResourceOutput{Body: boardResponses}, nil + return &core.ApiResourceOutput{Body: jiraConnection}, nil } diff --git a/plugins/jira/api/init.go b/plugins/jira/api/init.go index 663d5033..acaa495e 100644 --- a/plugins/jira/api/init.go +++ b/plugins/jira/api/init.go @@ -24,11 +24,7 @@ import ( ) var db *gorm.DB -var cfg *viper.Viper -var log core.Logger func Init(config *viper.Viper, logger core.Logger, database *gorm.DB) { db = database - cfg = config - log = logger } diff --git a/plugins/jira/api/proxy.go b/plugins/jira/api/proxy.go index e4a3eb90..398f4f1f 100644 --- a/plugins/jira/api/proxy.go +++ b/plugins/jira/api/proxy.go @@ -35,7 +35,7 @@ const ( func Proxy(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { jiraConnection := &models.JiraConnection{} - err := helper.FindConnectionByInput(input, jiraConnection, db) + err := helper.GetConnection(input.Params, jiraConnection, db) if err != nil { return nil, err } diff --git a/plugins/jira/jira.go b/plugins/jira/jira.go index a36177da..37313972 100644 --- a/plugins/jira/jira.go +++ b/plugins/jira/jira.go @@ -176,15 +176,6 @@ func (plugin Jira) ApiResources() map[string]map[string]core.ApiResourceHandler "DELETE": api.DeleteConnection, "GET": api.GetConnection, }, - "connections/:connectionId/epics": { - "GET": api.GetEpicsByConnectionId, - }, - "connections/:connectionId/granularities": { - "GET": api.GetGranularitiesByConnectionId, - }, - "connections/:connectionId/boards": { - "GET": api.GetBoardsByConnectionId, - }, "connections/:connectionId/proxy/rest/*path": { "GET": api.Proxy, }, diff --git a/plugins/jira/models/connection.go b/plugins/jira/models/connection.go index f1ed2f8a..fa0664f6 100644 --- a/plugins/jira/models/connection.go +++ b/plugins/jira/models/connection.go @@ -42,8 +42,6 @@ type BoardResponse struct { type JiraConnection struct { helper.RestConnection `mapstructure:",squash"` helper.BasicAuth `mapstructure:",squash"` - EpicKeyField string `gorm:"type:varchar(50);" json:"epicKeyField"` - StoryPointField string `gorm:"type:varchar(50);" json:"storyPointField"` RemotelinkCommitShaPattern string `gorm:"type:varchar(255);comment='golang regexp, the first group will be recognized as commit sha, ref https://github.com/google/re2/wiki/Syntax'" json:"remotelinkCommitShaPattern"` } @@ -60,19 +58,6 @@ type JiraIssueStatusMapping struct { StandardStatus string `gorm:"type:varchar(50)" json:"standardStatus" validate:"required"` } -type JiraConnectionDetail struct { - JiraConnection - TypeMappings map[string]map[string]interface{} `json:"typeMappings"` -} - func (JiraConnection) TableName() string { return "_tool_jira_connections" } - -func (JiraIssueTypeMapping) TableName() string { - return "_tool_jira_issue_type_mappings" -} - -func (JiraIssueStatusMapping) TableName() string { - return "_tool_jira_issue_status_mappings" -} diff --git a/plugins/jira/models/migrationscripts/updateSchemas20220601.go b/plugins/jira/models/migrationscripts/updateSchemas20220601.go index ec528dcb..24d3786c 100644 --- a/plugins/jira/models/migrationscripts/updateSchemas20220601.go +++ b/plugins/jira/models/migrationscripts/updateSchemas20220601.go @@ -58,9 +58,12 @@ func (*UpdateSchemas20220601) Up(ctx context.Context, db *gorm.DB) error { if db.Migrator().HasColumn(&JiraConnection20220505{}, "basic_auth_encoded") { connections := make([]*JiraConnection20220505, 0) - db.Find(&connections) + err = db.Find(&connections).Error + if err != nil { + return err + } for i, _ := range connections { - err = helper.DecryptConnection(connections[i], "BasicAuthEncoded") + err = helper.DecryptConnection(connections[i]) if err != nil { return err } diff --git a/plugins/jira/tasks/api_client.go b/plugins/jira/tasks/api_client.go index 811c0b6a..b44b024b 100644 --- a/plugins/jira/tasks/api_client.go +++ b/plugins/jira/tasks/api_client.go @@ -28,7 +28,7 @@ import ( func NewJiraApiClient(taskCtx core.TaskContext, connection *models.JiraConnection) (*helper.ApiAsyncClient, error) { // decrypt connection first - err := helper.DecryptConnection(connection, "Password") + err := helper.DecryptConnection(connection) if err != nil { return nil, fmt.Errorf("Failed to decrypt Auth AccessToken: %w", err) } diff --git a/plugins/jira/tasks/apiv2models/issue.go b/plugins/jira/tasks/apiv2models/issue.go index 3544150e..591ff7b7 100644 --- a/plugins/jira/tasks/apiv2models/issue.go +++ b/plugins/jira/tasks/apiv2models/issue.go @@ -151,11 +151,8 @@ type Issue struct { } `json:"changelog"` } -func (i Issue) toToolLayer(connectionId uint64, epicField, storyPointField string) *models.JiraIssue { +func (i Issue) toToolLayer(connectionId uint64) *models.JiraIssue { var workload float64 - if storyPointField != "" { - workload, _ = i.Fields.AllFields[storyPointField].(float64) - } result := &models.JiraIssue{ ConnectionId: connectionId, IssueId: i.ID, @@ -177,9 +174,6 @@ func (i Issue) toToolLayer(connectionId uint64, epicField, storyPointField strin if i.Fields.Epic != nil { result.EpicKey = i.Fields.Epic.Key } - if epicField != "" { - result.EpicKey, _ = i.Fields.AllFields[epicField].(string) - } if i.Fields.Assignee != nil { result.AssigneeAccountId = i.Fields.Assignee.getAccountId() result.AssigneeDisplayName = i.Fields.Assignee.DisplayName @@ -227,8 +221,8 @@ func (i *Issue) SetAllFields(raw datatypes.JSON) error { return nil } -func (i Issue) ExtractEntities(connectionId uint64, epicField, storyPointField string) ([]uint64, *models.JiraIssue, bool, []*models.JiraWorklog, []*models.JiraChangelog, []*models.JiraChangelogItem, []*models.JiraUser) { - issue := i.toToolLayer(connectionId, epicField, storyPointField) +func (i Issue) ExtractEntities(connectionId uint64) ([]uint64, *models.JiraIssue, bool, []*models.JiraWorklog, []*models.JiraChangelog, []*models.JiraChangelogItem, []*models.JiraUser) { + issue := i.toToolLayer(connectionId) var worklogs []*models.JiraWorklog var changelogs []*models.JiraChangelog var changelogItems []*models.JiraChangelogItem diff --git a/plugins/jira/tasks/issue_extractor.go b/plugins/jira/tasks/issue_extractor.go index 17882df8..266be502 100644 --- a/plugins/jira/tasks/issue_extractor.go +++ b/plugins/jira/tasks/issue_extractor.go @@ -106,7 +106,7 @@ func ExtractIssues(taskCtx core.SubTaskContext) error { return nil, err } var results []interface{} - sprints, issue, _, worklogs, changelogs, changelogItems, users := apiIssue.ExtractEntities(data.Connection.ID, data.Connection.EpicKeyField, data.Connection.StoryPointField) + sprints, issue, _, worklogs, changelogs, changelogItems, users := apiIssue.ExtractEntities(data.Connection.ID) for _, sprintId := range sprints { sprintIssue := &models.JiraSprintIssue{ ConnectionId: data.Connection.ID, diff --git a/plugins/tapd/api/connection.go b/plugins/tapd/api/connection.go index 5065f096..96c6bbba 100644 --- a/plugins/tapd/api/connection.go +++ b/plugins/tapd/api/connection.go @@ -281,30 +281,3 @@ func GetConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error } return &core.ApiResourceOutput{Body: detail}, nil } - -// GET /plugins/tapd/connections/:connectionId/boards - -func GetBoardsByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) { - connectionId := input.Params["connectionId"] - if connectionId == "" { - return nil, fmt.Errorf("missing connectionId") - } - tapdConnectionId, err := strconv.ParseUint(connectionId, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid connectionId") - } - var tapdWorkspaces []models.TapdWorkspace - err = db.Where("connection_Id = ?", tapdConnectionId).Find(&tapdWorkspaces).Error - if err != nil { - return nil, err - } - var workSpaceResponses []models.WorkspaceResponse - for _, workSpace := range tapdWorkspaces { - workSpaceResponses = append(workSpaceResponses, models.WorkspaceResponse{ - Id: uint64(workSpace.ID), - Title: workSpace.Name, - Value: fmt.Sprintf("%v", workSpace.ID), - }) - } - return &core.ApiResourceOutput{Body: workSpaceResponses}, nil -} diff --git a/plugins/tapd/tapd.go b/plugins/tapd/tapd.go index ea556438..c74d278d 100644 --- a/plugins/tapd/tapd.go +++ b/plugins/tapd/tapd.go @@ -180,9 +180,6 @@ func (plugin Tapd) ApiResources() map[string]map[string]core.ApiResourceHandler "DELETE": api.DeleteConnection, "GET": api.GetConnection, }, - "connections/:connectionId/boards": { - "GET": api.GetBoardsByConnectionId, - }, "connections/:connectionId/proxy/rest/*path": { "GET": api.Proxy, }, @@ -220,7 +217,10 @@ func main() { panic(err) } wsList := make([]*models.TapdWorkspace, 0) - err = db.Find(&wsList, "parent_id = ?", 59169984).Error //nolint TODO: fix the unused err + err = db.Find(&wsList, "parent_id = ?", 59169984).Error + if err != nil { + panic(err) + } for _, v := range wsList { *workspaceId = v.ID runner.DirectRun(c, args, PluginEntry, []string{}, map[string]interface{}{ diff --git a/runner/directrun.go b/runner/directrun.go index 6ab5b83d..e2343cd4 100644 --- a/runner/directrun.go +++ b/runner/directrun.go @@ -47,7 +47,6 @@ func DirectRun(cmd *cobra.Command, args []string, pluginTask core.PluginTask, su if err != nil { panic(err) } - subtasks = tasks cfg := config.GetConfig() log := logger.Global.Nested(cmd.Use) db, err := NewGormDb(cfg, log) @@ -102,7 +101,7 @@ func DirectRun(cmd *cobra.Command, args []string, pluginTask core.PluginTask, su db, ctx, cmd.Use, - subtasks, + tasks, options, pluginTask, nil,
