This is an automated email from the ASF dual-hosted git repository.
zhangliang2022 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 8a934843 info api and domain layer info (#2761)
8a934843 is described below
commit 8a934843b5f72f1fd81eeccc5c4f0231cbd8ee06
Author: mappjzc <[email protected]>
AuthorDate: Fri Aug 19 13:26:19 2022 +0800
info api and domain layer info (#2761)
* feat: get domain tables info
Add GetDomainTablesInfo for get the domain tables info.
Nddtfjiang <[email protected]>
* feat: api plugin info
Add api /plugininfo for get the infomation about domainlayer's tables and
plugininfos.
Nddtfjiang <[email protected]>
* feat: add dbname to field
Add dbname to field.
Nddtfjiang <[email protected]>
* style: change api struct of return
lowcase the api return json.
remove key of plugin and tables and field.
Nddtfjiang <[email protected]>
---
api/plugininfo/plugininifo.go | 179 ++++++++++++++++++++++++++++
api/router.go | 3 +
models/domainlayer/domaininfo/domaininfo.go | 79 ++++++++++++
plugins/core/hub.go | 12 ++
4 files changed, 273 insertions(+)
diff --git a/api/plugininfo/plugininifo.go b/api/plugininfo/plugininifo.go
new file mode 100644
index 00000000..f5261f1d
--- /dev/null
+++ b/api/plugininfo/plugininifo.go
@@ -0,0 +1,179 @@
+/*
+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 plugininfo
+
+import (
+ "net/http"
+ "reflect"
+ "sync"
+
+ "github.com/apache/incubator-devlake/api/shared"
+ "github.com/apache/incubator-devlake/models/domainlayer/domaininfo"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/utils"
+ "github.com/gin-gonic/gin"
+ "gorm.io/gorm/schema"
+)
+
+type SubTaskMeta struct {
+ Name string `json:"name"`
+ Required bool `json:"required"`
+ EnabledByDefault bool `json:"enabled_by_default"`
+ Description string `json:"description"`
+ DomainTypes []string `json:"domain_types"`
+}
+
+func CreateSubTaskMeta(subTaskMeta []core.SubTaskMeta) []SubTaskMeta {
+ ret := make([]SubTaskMeta, 0, len(subTaskMeta))
+ for _, meta := range subTaskMeta {
+ ret = append(ret, SubTaskMeta{
+ Name: meta.Name,
+ Required: meta.Required,
+ EnabledByDefault: meta.EnabledByDefault,
+ Description: meta.Description,
+ DomainTypes: meta.DomainTypes,
+ })
+ }
+ return ret
+}
+
+type TableInfo struct {
+ Name string `json:"name"`
+ Tags string `json:"tags"`
+ DbName string `json:"db_name"`
+ DataType string `json:"data_type"`
+ GORMDataType string `json:"gorm_data_type"`
+}
+
+type TableInfos struct {
+ TableName string `json:"table_name"`
+ Field []*TableInfo `json:"field"`
+ Error *string `json:"error"`
+}
+
+func NewTableInfos(table core.Tabler) *TableInfos {
+ tableInfos := &TableInfos{
+ TableName: table.TableName(),
+ Error: nil,
+ }
+
+ fieldInfos := utils.WalkFields(reflect.TypeOf(table), nil)
+ schema, err := schema.Parse(table, &sync.Map{}, schema.NamingStrategy{})
+ if err != nil {
+ errstr := err.Error()
+ tableInfos.Error = &errstr
+ }
+
+ tableInfos.Field = make([]*TableInfo, 0, len(fieldInfos))
+ for _, field := range fieldInfos {
+ dbName := ""
+ dataType := ""
+ gormDataType := ""
+ if schema != nil {
+ if dbfield, ok := schema.FieldsByName[field.Name]; ok {
+ dbName = dbfield.DBName
+ dataType = string(dbfield.DataType)
+ gormDataType = string(dbfield.GORMDataType)
+ }
+ }
+ tableInfos.Field = append(tableInfos.Field, &TableInfo{
+ Name: field.Name,
+ Tags: string(field.Tag),
+ DbName: dbName,
+ DataType: dataType,
+ GORMDataType: gormDataType,
+ })
+ }
+
+ return tableInfos
+}
+
+type PluginInfo struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Tables []*TableInfos `json:"tables"`
+ TaskMeta []SubTaskMeta `json:"task_mata"`
+}
+
+func NewPluginInfo() *PluginInfo {
+ return &PluginInfo{
+ Tables: make([]*TableInfos, 0),
+ }
+}
+
+type TotalInfo struct {
+ DomainInfos []*TableInfos
+ PluginInfos []*PluginInfo
+}
+
+func NewTotalInfo() *TotalInfo {
+ return &TotalInfo{
+ DomainInfos: make([]*TableInfos, 0),
+ PluginInfos: make([]*PluginInfo, 0),
+ }
+}
+
+// @Get detail info of plugins
+// @Description GET /plugininfo
+// @Description RETURN SAMPLE
+// @Tags framework/plugininfo
+// @Success 200
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Router /plugininfo [get]
+func Get(c *gin.Context) {
+ info := NewTotalInfo()
+
+ // set the domain layer tables info.
+ domaininfo := domaininfo.GetDomainTablesInfo()
+ for _, table := range domaininfo {
+ tableInfo := NewTableInfos(table)
+ info.DomainInfos = append(info.DomainInfos, tableInfo)
+ }
+
+ // plugin info
+ err := core.TraversalPlugin(func(name string, plugin core.PluginMeta)
error {
+ infoPlugin := NewPluginInfo()
+ info.PluginInfos = append(info.PluginInfos, infoPlugin)
+
+ // plugin name and description
+ infoPlugin.Name = name
+ infoPlugin.Description = plugin.Description()
+
+ // if this plugin has the plugin task info
+ if pt, ok := plugin.(core.PluginTask); ok {
+ infoPlugin.TaskMeta =
CreateSubTaskMeta(pt.SubTaskMetas())
+ }
+
+ // if this plugin has the plugin model info
+ if pm, ok := plugin.(core.PluginModel); ok {
+ tables := pm.GetTablesInfo()
+ for _, table := range tables {
+ TableInfos := NewTableInfos(table)
+ infoPlugin.Tables = append(infoPlugin.Tables,
TableInfos)
+ }
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ shared.ApiOutputError(c, err, http.StatusBadRequest)
+ }
+
+ shared.ApiOutputSuccess(c, info, http.StatusOK)
+}
diff --git a/api/router.go b/api/router.go
index 0d4eb08b..0972c6d2 100644
--- a/api/router.go
+++ b/api/router.go
@@ -26,6 +26,7 @@ import (
"github.com/apache/incubator-devlake/api/domainlayer"
"github.com/apache/incubator-devlake/api/ping"
"github.com/apache/incubator-devlake/api/pipelines"
+ "github.com/apache/incubator-devlake/api/plugininfo"
"github.com/apache/incubator-devlake/api/push"
"github.com/apache/incubator-devlake/api/shared"
"github.com/apache/incubator-devlake/api/task"
@@ -57,6 +58,8 @@ func RegisterRouter(r *gin.Engine) {
r.POST("/push/:tableName", push.Post)
r.GET("/domainlayer/repos", domainlayer.ReposIndex)
+ r.GET("/plugininfo", plugininfo.Get)
+
// mount all api resources for all plugins
pluginsApiResources, err := services.GetPluginsApiResources()
if err != nil {
diff --git a/models/domainlayer/domaininfo/domaininfo.go
b/models/domainlayer/domaininfo/domaininfo.go
new file mode 100644
index 00000000..4a8c5b30
--- /dev/null
+++ b/models/domainlayer/domaininfo/domaininfo.go
@@ -0,0 +1,79 @@
+/*
+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 domaininfo
+
+import (
+ "github.com/apache/incubator-devlake/models/domainlayer/code"
+ "github.com/apache/incubator-devlake/models/domainlayer/crossdomain"
+ "github.com/apache/incubator-devlake/models/domainlayer/devops"
+ "github.com/apache/incubator-devlake/models/domainlayer/ticket"
+)
+
+type Tabler interface {
+ TableName() string
+}
+
+func GetDomainTablesInfo() []Tabler {
+ return []Tabler{
+ // code
+ &code.Commit{},
+ &code.CommitFile{},
+ &code.CommitFileComponent{},
+ &code.CommitParent{},
+ &code.Component{},
+ &code.PullRequest{},
+ &code.PullRequestComment{},
+ &code.PullRequestCommit{},
+ &code.PullRequestLabel{},
+ &code.Ref{},
+ &code.RefsCommitsDiff{},
+ &code.RefsPrCherrypick{},
+ &code.Repo{},
+ &code.RepoCommit{},
+ &code.RepoLanguage{},
+ // crossdomain
+ &crossdomain.Account{},
+ &crossdomain.BoardRepo{},
+ &crossdomain.IssueCommit{},
+ &crossdomain.IssueRepoCommit{},
+ &crossdomain.ProjectMapping{},
+ &crossdomain.PullRequestIssue{},
+ &crossdomain.RefsIssuesDiffs{},
+ &crossdomain.Team{},
+ &crossdomain.TeamUser{},
+ &crossdomain.User{},
+ &crossdomain.UserAccount{},
+ // devops
+ &devops.Build{},
+ &devops.CICDPipeline{},
+ &devops.CICDTask{},
+ &devops.Job{},
+ // didgen no table
+ // ticket
+ &ticket.Board{},
+ &ticket.BoardIssue{},
+ &ticket.BoardSprint{},
+ &ticket.Issue{},
+ &ticket.IssueChangelogs{},
+ &ticket.IssueComment{},
+ &ticket.IssueLabel{},
+ &ticket.IssueWorklog{},
+ &ticket.Sprint{},
+ &ticket.SprintIssue{},
+ }
+}
diff --git a/plugins/core/hub.go b/plugins/core/hub.go
index 9d3416fc..6ce4c826 100644
--- a/plugins/core/hub.go
+++ b/plugins/core/hub.go
@@ -45,6 +45,18 @@ func GetPlugin(name string) (PluginMeta, error) {
return nil, fmt.Errorf("Plugin `%s` doesn't exist", name)
}
+type PluginCallBack func(name string, plugin PluginMeta) error
+
+func TraversalPlugin(handle PluginCallBack) error {
+ for name, plugin := range plugins {
+ err := handle(name, plugin)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
func AllPlugins() map[string]PluginMeta {
return plugins
}