You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by GitBox <gi...@apache.org> on 2022/11/04 12:03:34 UTC

[GitHub] [incubator-devlake] mappjzc opened a new pull request, #3679: feat: add project api and tables

mappjzc opened a new pull request, #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679

   # Summary
   Add GET POST PATCH Project
   Add GET POST PATCH ProjectMetric
   Add tables
   
   <!--
   Thanks for submitting a pull request!
   
   We appreciate you spending the time to work on these changes.
   Please fill out as many sections below as possible.
   -->
   
   ### Does this close any open issues?
   Closes xx
   
   ### Screenshots
   Include any relevant screenshots here.
   
   ### Other Information
   Any other information that is important to this PR.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] mappjzc commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
mappjzc commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1016541177


##########
services/project.go:
##########
@@ -0,0 +1,146 @@
+/*
+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 services
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ProjectQuery struct {
+	Page     int `form:"page"`
+	PageSize int `form:"pageSize"`
+}
+
+// CreateProject accepts a project instance and insert it to database
+func CreateProject(project *models.Project) errors.Error {
+	enProject, err := encryptProject(project)
+	if err != nil {
+		return err
+	}
+	err = CreateDbProject(enProject)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// CreateProjectMetric accepts a ProjectMetric instance and insert it to database
+func CreateProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	enProjectMetric, err := encryptProjectMetric(projectMetric)
+	if err != nil {
+		return err
+	}
+	err = CreateDbProjectMetric(enProjectMetric)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// GetProject returns a Project
+func GetProject(name string) (*models.Project, errors.Error) {
+	project, err := GetDbProject(name)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	project, err = decryptProject(project)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	return project, nil
+}
+
+// GetProjectMetric returns a ProjectMetric
+func GetProjectMetric(projectName string, pluginName string) (*models.ProjectMetric, errors.Error) {
+	projectMetric, err := GetDbProjectMetric(projectName, pluginName)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	projectMetric, err = decryptProjectMetric(projectMetric)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	return projectMetric, nil
+}
+
+// GetProjects returns a paginated list of Projects based on `query`
+func GetProjects(query *ProjectQuery) ([]*models.Project, int64, errors.Error) {
+	projects, count, err := GetDbProjects(query)
+	if err != nil {
+		return nil, 0, errors.Convert(err)
+	}
+	for i, project := range projects {
+		projects[i], err = decryptProject(project)

Review Comment:
   pipeline and blueprint has decryptProject it. so do I.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] warren830 commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
warren830 commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1015353620


##########
models/project.go:
##########
@@ -0,0 +1,54 @@
+/*
+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 models
+
+import "github.com/apache/incubator-devlake/models/common"
+
+type Project struct {
+	Name     string `gorm:"primaryKey;type:varchar(255)"`
+	Describe string `gorm:"type:text"`
+
+	common.NoPKModel
+}
+
+func (Project) TableName() string {
+	return "_devlake_projects"
+}
+
+type ProjectMetric struct {
+	ProjectName  string `gorm:"primaryKey;type:varchar(255)"`
+	PluginName   string `gorm:"primaryKey;type:varchar(255)"`
+	PluginOption string `gorm:"type:text"`
+
+	common.NoPKModel
+}
+
+func (ProjectMetric) TableName() string {
+	return "_devlake_project_metrics"
+}
+
+type ProjectMapping struct {

Review Comment:
   @mindlesscloud already created this table in July



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] warren830 commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
warren830 commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1015357181


##########
services/project_helper.go:
##########
@@ -0,0 +1,166 @@
+/*
+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 services
+
+import (
+	goerror "errors"
+
+	"github.com/apache/incubator-devlake/config"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/core"
+	"gorm.io/gorm"
+)
+
+// CreateDbProject accepts a project instance and insert it to database
+func CreateDbProject(project *models.Project) errors.Error {
+	err := db.Create(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project")
+	}
+	return nil
+}
+
+// CreateDbProjectMetric accepts a project metric instance and insert it to database
+func CreateDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Create(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project metric")
+	}
+	return nil
+}
+
+// SaveDbProject save a project instance and update it to database
+func SaveDbProject(project *models.Project) errors.Error {
+	err := db.Save(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project")
+	}
+	return nil
+}
+
+// SaveDbProjectMetric save a project instance and update it to database
+func SaveDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Save(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project metric")
+	}
+	return nil
+}
+
+// GetDbProjects returns a paginated list of Project based on `query`
+func GetDbProjects(query *ProjectQuery) ([]*models.Project, int64, errors.Error) {
+	projects := make([]*models.Project, 0)
+	db := db.Model(projects).Order("created_at desc")
+
+	var count int64
+	err := db.Count(&count).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error getting DB count of project")
+	}
+	db = processDbClausesWithPager(db, query.PageSize, query.Page)
+
+	err = db.Find(&projects).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error finding DB project")
+	}
+
+	return projects, count, nil
+}
+
+// GetDbProject returns the detail of a given project name
+func GetDbProject(name string) (*models.Project, errors.Error) {
+	project := &models.Project{}
+
+	err := db.First(project, name).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, "could not find project in DB")
+		}
+		return nil, errors.Default.Wrap(err, "error getting project from DB")
+	}
+
+	return project, nil
+}
+
+// GetDbProjectMetric returns the detail of a given project name
+func GetDbProjectMetric(projectName string, pluginName string) (*models.ProjectMetric, errors.Error) {
+	projectMetric := &models.ProjectMetric{}
+
+	err := db.First(projectMetric, projectName, pluginName).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, "could not find project metric in DB")
+		}
+		return nil, errors.Default.Wrap(err, "error getting project metric from DB")
+	}
+
+	return projectMetric, nil
+}
+
+// encryptProject
+func encryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describeEncrypt, err := core.Encrypt(encKey, project.Describe)
+	if err != nil {
+		return nil, err
+	}
+	project.Describe = describeEncrypt
+
+	return project, nil
+}
+
+// encryptProjectMetric
+func encryptProjectMetric(projectMetric *models.ProjectMetric) (*models.ProjectMetric, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	pluginOption, err := core.Encrypt(encKey, projectMetric.PluginOption)
+	if err != nil {
+		return nil, err
+	}
+	projectMetric.PluginOption = pluginOption
+
+	return projectMetric, nil
+}
+
+// decryptProject
+func decryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describe, err := core.Decrypt(encKey, project.Describe)
+	if err != nil {
+		return nil, err
+	}
+	project.Describe = describe
+
+	return project, nil
+}
+
+// decryptProjectMetric
+func decryptProjectMetric(projectMetric *models.ProjectMetric) (*models.ProjectMetric, errors.Error) {

Review Comment:
   same here, why do we need to decrypt this entity?



##########
services/project_helper.go:
##########
@@ -0,0 +1,166 @@
+/*
+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 services
+
+import (
+	goerror "errors"
+
+	"github.com/apache/incubator-devlake/config"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/core"
+	"gorm.io/gorm"
+)
+
+// CreateDbProject accepts a project instance and insert it to database
+func CreateDbProject(project *models.Project) errors.Error {
+	err := db.Create(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project")
+	}
+	return nil
+}
+
+// CreateDbProjectMetric accepts a project metric instance and insert it to database
+func CreateDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Create(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project metric")
+	}
+	return nil
+}
+
+// SaveDbProject save a project instance and update it to database
+func SaveDbProject(project *models.Project) errors.Error {
+	err := db.Save(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project")
+	}
+	return nil
+}
+
+// SaveDbProjectMetric save a project instance and update it to database
+func SaveDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Save(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project metric")
+	}
+	return nil
+}
+
+// GetDbProjects returns a paginated list of Project based on `query`
+func GetDbProjects(query *ProjectQuery) ([]*models.Project, int64, errors.Error) {
+	projects := make([]*models.Project, 0)
+	db := db.Model(projects).Order("created_at desc")
+
+	var count int64
+	err := db.Count(&count).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error getting DB count of project")
+	}
+	db = processDbClausesWithPager(db, query.PageSize, query.Page)
+
+	err = db.Find(&projects).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error finding DB project")
+	}
+
+	return projects, count, nil
+}
+
+// GetDbProject returns the detail of a given project name
+func GetDbProject(name string) (*models.Project, errors.Error) {
+	project := &models.Project{}
+
+	err := db.First(project, name).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, "could not find project in DB")
+		}
+		return nil, errors.Default.Wrap(err, "error getting project from DB")
+	}
+
+	return project, nil
+}
+
+// GetDbProjectMetric returns the detail of a given project name
+func GetDbProjectMetric(projectName string, pluginName string) (*models.ProjectMetric, errors.Error) {
+	projectMetric := &models.ProjectMetric{}
+
+	err := db.First(projectMetric, projectName, pluginName).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, "could not find project metric in DB")
+		}
+		return nil, errors.Default.Wrap(err, "error getting project metric from DB")
+	}
+
+	return projectMetric, nil
+}
+
+// encryptProject
+func encryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describeEncrypt, err := core.Encrypt(encKey, project.Describe)
+	if err != nil {
+		return nil, err
+	}
+	project.Describe = describeEncrypt
+
+	return project, nil
+}
+
+// encryptProjectMetric
+func encryptProjectMetric(projectMetric *models.ProjectMetric) (*models.ProjectMetric, errors.Error) {

Review Comment:
   Also, we don't need to encrypt this entity



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] warren830 commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
warren830 commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1015355944


##########
models/project.go:
##########
@@ -0,0 +1,54 @@
+/*
+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 models
+
+import "github.com/apache/incubator-devlake/models/common"
+
+type Project struct {
+	Name     string `gorm:"primaryKey;type:varchar(255)"`
+	Describe string `gorm:"type:text"`

Review Comment:
   what about description?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] warren830 commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
warren830 commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1015356459


##########
models/project.go:
##########
@@ -0,0 +1,54 @@
+/*
+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 models
+
+import "github.com/apache/incubator-devlake/models/common"
+
+type Project struct {
+	Name     string `gorm:"primaryKey;type:varchar(255)"`
+	Describe string `gorm:"type:text"`
+
+	common.NoPKModel
+}
+
+func (Project) TableName() string {
+	return "_devlake_projects"
+}
+
+type ProjectMetric struct {
+	ProjectName  string `gorm:"primaryKey;type:varchar(255)"`
+	PluginName   string `gorm:"primaryKey;type:varchar(255)"`
+	PluginOption string `gorm:"type:text"`

Review Comment:
   Not quite sure about the type of this field



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] warren830 commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
warren830 commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1015354957


##########
services/project.go:
##########
@@ -0,0 +1,146 @@
+/*
+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 services
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ProjectQuery struct {
+	Page     int `form:"page"`
+	PageSize int `form:"pageSize"`
+}
+
+// CreateProject accepts a project instance and insert it to database
+func CreateProject(project *models.Project) errors.Error {
+	enProject, err := encryptProject(project)
+	if err != nil {
+		return err
+	}
+	err = CreateDbProject(enProject)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// CreateProjectMetric accepts a ProjectMetric instance and insert it to database
+func CreateProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	enProjectMetric, err := encryptProjectMetric(projectMetric)
+	if err != nil {
+		return err
+	}
+	err = CreateDbProjectMetric(enProjectMetric)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// GetProject returns a Project
+func GetProject(name string) (*models.Project, errors.Error) {
+	project, err := GetDbProject(name)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	project, err = decryptProject(project)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	return project, nil
+}
+
+// GetProjectMetric returns a ProjectMetric
+func GetProjectMetric(projectName string, pluginName string) (*models.ProjectMetric, errors.Error) {
+	projectMetric, err := GetDbProjectMetric(projectName, pluginName)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	projectMetric, err = decryptProjectMetric(projectMetric)
+	if err != nil {
+		return nil, errors.Convert(err)
+	}
+
+	return projectMetric, nil
+}
+
+// GetProjects returns a paginated list of Projects based on `query`
+func GetProjects(query *ProjectQuery) ([]*models.Project, int64, errors.Error) {
+	projects, count, err := GetDbProjects(query)
+	if err != nil {
+		return nil, 0, errors.Convert(err)
+	}
+	for i, project := range projects {
+		projects[i], err = decryptProject(project)

Review Comment:
   why do you decrypt and encrypt Project?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] mappjzc commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
mappjzc commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1017339791


##########
models/project.go:
##########
@@ -0,0 +1,54 @@
+/*
+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 models
+
+import "github.com/apache/incubator-devlake/models/common"
+
+type Project struct {
+	Name     string `gorm:"primaryKey;type:varchar(255)"`
+	Describe string `gorm:"type:text"`
+
+	common.NoPKModel
+}
+
+func (Project) TableName() string {
+	return "_devlake_projects"
+}
+
+type ProjectMetric struct {
+	ProjectName  string `gorm:"primaryKey;type:varchar(255)"`
+	PluginName   string `gorm:"primaryKey;type:varchar(255)"`
+	PluginOption string `gorm:"type:text"`

Review Comment:
   as klesh's mind, it is used for future.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3679: feat: add project to support resource classification

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1022467000


##########
plugins/tapd/impl/impl.go:
##########
@@ -37,6 +37,8 @@ var _ core.PluginMeta = (*Tapd)(nil)
 var _ core.PluginInit = (*Tapd)(nil)
 var _ core.PluginTask = (*Tapd)(nil)
 var _ core.PluginApi = (*Tapd)(nil)
+var _ core.PluginModel = (*Tapd)(nil)
+var _ core.PluginMetric = (*Tapd)(nil)

Review Comment:
   no



##########
plugins/webhook/impl/impl.go:
##########
@@ -43,6 +45,35 @@ func (plugin Webhook) Init(config *viper.Viper, logger core.Logger, db *gorm.DB)
 	return nil
 }
 
+func (plugin Webhook) RequiredDataEntities() (data []map[string]interface{}, err errors.Error) {
+	return []map[string]interface{}{

Review Comment:
   No, this is not a metric plugin



##########
plugins/refdiff/refdiff.go:
##########
@@ -44,10 +46,31 @@ func (plugin RefDiff) Description() string {
 	return "Calculate commits diff for specified ref pairs based on `commits` and `commit_parents` tables"
 }
 
+func (plugin RefDiff) RequiredDataEntities() (data []map[string]interface{}, err errors.Error) {
+	return []map[string]interface{}{}, nil
+}
+
 func (plugin RefDiff) GetTablesInfo() []core.Tabler {
 	return []core.Tabler{}
 }
 
+func (plugin RefDiff) IsProjectMetric() bool {
+	return false
+}
+
+func (plugin RefDiff) RunAfter() ([]string, errors.Error) {
+	return []string{

Review Comment:
   no, let it empty at this point



##########
plugins/starrocks/starrocks.go:
##########
@@ -27,6 +27,12 @@ import (
 
 type StarRocks string
 
+// make sure interface is implemented
+var _ core.PluginMeta = (*StarRocks)(nil)
+var _ core.PluginTask = (*StarRocks)(nil)
+var _ core.PluginModel = (*StarRocks)(nil)
+var _ core.PluginMetric = (*StarRocks)(nil)

Review Comment:
   no



##########
plugins/jira/impl/impl.go:
##########
@@ -37,6 +38,8 @@ var _ core.PluginMeta = (*Jira)(nil)
 var _ core.PluginInit = (*Jira)(nil)
 var _ core.PluginTask = (*Jira)(nil)
 var _ core.PluginApi = (*Jira)(nil)
+var _ core.PluginModel = (*Jira)(nil)
+var _ core.PluginMetric = (*Jira)(nil)

Review Comment:
   no



##########
plugins/jenkins/impl/impl.go:
##########
@@ -36,6 +36,8 @@ var _ core.PluginMeta = (*Jenkins)(nil)
 var _ core.PluginInit = (*Jenkins)(nil)
 var _ core.PluginTask = (*Jenkins)(nil)
 var _ core.PluginApi = (*Jenkins)(nil)
+var _ core.PluginModel = (*Jenkins)(nil)
+var _ core.PluginMetric = (*Jenkins)(nil)

Review Comment:
   no



##########
plugins/org/impl/impl.go:
##########
@@ -31,6 +31,8 @@ import (
 var _ core.PluginMeta = (*Org)(nil)
 var _ core.PluginInit = (*Org)(nil)
 var _ core.PluginTask = (*Org)(nil)
+var _ core.PluginModel = (*Org)(nil)
+var _ core.PluginMetric = (*Org)(nil)

Review Comment:
   no



##########
plugins/icla/plugin_main.go:
##########
@@ -37,6 +37,8 @@ var _ core.PluginMeta = (*Icla)(nil)
 var _ core.PluginInit = (*Icla)(nil)
 var _ core.PluginTask = (*Icla)(nil)
 var _ core.PluginApi = (*Icla)(nil)
+var _ core.PluginModel = (*Icla)(nil)
+var _ core.PluginMetric = (*Icla)(nil)

Review Comment:
   no



##########
plugins/github_graphql/plugin_main.go:
##########
@@ -32,16 +36,15 @@ import (
 	"github.com/spf13/viper"
 	"golang.org/x/oauth2"
 	"gorm.io/gorm"
-	"reflect"
-	"strings"
-	"time"
 )
 
 // make sure interface is implemented
 var _ core.PluginMeta = (*GithubGraphql)(nil)
 var _ core.PluginInit = (*GithubGraphql)(nil)
 var _ core.PluginTask = (*GithubGraphql)(nil)
 var _ core.PluginApi = (*GithubGraphql)(nil)
+var _ core.PluginModel = (*GithubGraphql)(nil)
+var _ core.PluginMetric = (*GithubGraphql)(nil)

Review Comment:
   no



##########
plugins/gitlab/impl/impl.go:
##########
@@ -34,9 +34,10 @@ import (
 
 var _ core.PluginMeta = (*Gitlab)(nil)
 var _ core.PluginInit = (*Gitlab)(nil)
-var _ core.PluginModel = (*Gitlab)(nil)
 var _ core.PluginTask = (*Gitlab)(nil)
 var _ core.PluginApi = (*Gitlab)(nil)
+var _ core.PluginModel = (*Gitlab)(nil)
+var _ core.PluginMetric = (*Gitlab)(nil)

Review Comment:
   no



##########
plugins/gitextractor/gitextractor.go:
##########
@@ -31,13 +31,31 @@ import (
 
 var _ core.PluginMeta = (*GitExtractor)(nil)
 var _ core.PluginTask = (*GitExtractor)(nil)
+var _ core.PluginModel = (*GitExtractor)(nil)
+var _ core.PluginMetric = (*GitExtractor)(nil)

Review Comment:
   no



##########
plugins/feishu/impl/impl.go:
##########
@@ -37,6 +37,8 @@ var _ core.PluginMeta = (*Feishu)(nil)
 var _ core.PluginInit = (*Feishu)(nil)
 var _ core.PluginTask = (*Feishu)(nil)
 var _ core.PluginApi = (*Feishu)(nil)
+var _ core.PluginModel = (*Feishu)(nil)
+var _ core.PluginMetric = (*Feishu)(nil)

Review Comment:
   no



##########
plugins/gitee/impl/impl.go:
##########
@@ -36,6 +36,8 @@ var _ core.PluginMeta = (*Gitee)(nil)
 var _ core.PluginInit = (*Gitee)(nil)
 var _ core.PluginTask = (*Gitee)(nil)
 var _ core.PluginApi = (*Gitee)(nil)
+var _ core.PluginModel = (*Gitee)(nil)
+var _ core.PluginMetric = (*Gitee)(nil)

Review Comment:
   no



##########
plugins/dbt/dbt.go:
##########
@@ -28,8 +28,10 @@ import (
 )
 
 var (
-	_ core.PluginMeta = (*Dbt)(nil)
-	_ core.PluginTask = (*Dbt)(nil)
+	_ core.PluginMeta   = (*Dbt)(nil)
+	_ core.PluginTask   = (*Dbt)(nil)
+	_ core.PluginModel  = (*Dbt)(nil)
+	_ core.PluginMetric = (*Dbt)(nil)

Review Comment:
   no



##########
plugins/bitbucket/impl/impl.go:
##########
@@ -35,6 +35,8 @@ var _ core.PluginMeta = (*Bitbucket)(nil)
 var _ core.PluginInit = (*Bitbucket)(nil)
 var _ core.PluginTask = (*Bitbucket)(nil)
 var _ core.PluginApi = (*Bitbucket)(nil)
+var _ core.PluginModel = (*Bitbucket)(nil)
+var _ core.PluginMetric = (*Bitbucket)(nil)

Review Comment:
   no



##########
plugins/customize/impl/impl.go:
##########
@@ -32,6 +32,8 @@ import (
 var _ core.PluginMeta = (*Customize)(nil)
 var _ core.PluginInit = (*Customize)(nil)
 var _ core.PluginApi = (*Customize)(nil)
+var _ core.PluginModel = (*Customize)(nil)
+var _ core.PluginMetric = (*Customize)(nil)

Review Comment:
   no



##########
plugins/azure/impl/impl.go:
##########
@@ -36,6 +36,8 @@ var _ core.PluginMeta = (*Azure)(nil)
 var _ core.PluginInit = (*Azure)(nil)
 var _ core.PluginTask = (*Azure)(nil)
 var _ core.PluginApi = (*Azure)(nil)
+var _ core.PluginModel = (*Azure)(nil)
+var _ core.PluginMetric = (*Azure)(nil)

Review Comment:
   no



##########
plugins/core/plugin_metric.go:
##########
@@ -0,0 +1,46 @@
+/*
+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 core
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+)
+
+/*
+ */
+type Tabler interface {

Review Comment:
   move it back to `plugin_model.go`



##########
plugins/ae/impl/impl.go:
##########
@@ -35,6 +35,8 @@ var _ core.PluginMeta = (*AE)(nil)
 var _ core.PluginInit = (*AE)(nil)
 var _ core.PluginTask = (*AE)(nil)
 var _ core.PluginApi = (*AE)(nil)
+var _ core.PluginModel = (*AE)(nil)
+var _ core.PluginMetric = (*AE)(nil)

Review Comment:
   no



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1019875460


##########
api/project/project.go:
##########
@@ -0,0 +1,226 @@
+/*
+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 project
+
+import (
+	"net/http"
+
+	"github.com/apache/incubator-devlake/api/shared"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/services"
+	"github.com/gin-gonic/gin"
+)
+
+// @Summary Create and run a new project
+// @Description Create and run a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [get]
+func GetProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	project, err := services.GetProject(projectName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusOK)
+}
+
+// @Summary Get list of projects
+// @Description GET /projects?page=1&pagesize=10
+// @Tags framework/projects
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} gin.H
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects [get]
+func GetProjects(c *gin.Context) {
+	var query services.ProjectQuery
+	err := c.ShouldBindQuery(&query)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+	projects, count, err := services.GetProjects(&query)
+	if err != nil {
+		shared.ApiOutputAbort(c, errors.Default.Wrap(err, "error getting projects"))
+		return
+	}
+	shared.ApiOutputSuccess(c, gin.H{"project": projects, "count": count}, http.StatusOK)
+}
+
+// @Summary Create a new project
+// @Description Create a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects [post]
+func PostProject(c *gin.Context) {
+	project := &models.Project{}
+
+	err := c.ShouldBind(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	err = services.CreateProject(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error creating project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Summary Patch a project
+// @Description Patch a project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [patch]
+func PatchProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	var body map[string]interface{}
+	err := c.ShouldBind(&body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	project, err := services.PatchProject(projectName, body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error patch project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Cancel a project
+// @Description Cancel a project
+// @Tags framework/projects
+// @Success 200
+// @Failure 400  {string} er2rcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects/:projectName [delete]
+//func DeleteProject(c *gin.Context) {
+//}
+
+// @Summary Get a ProjectMetrics
+// @Description Get a ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /project_metrics/:projectName/:pluginName [get]
+func GetProjectMetric(c *gin.Context) {
+	projectName := c.Param("projectName")
+	pluginName := c.Param("pluginName")
+
+	projectMetric, err := services.GetProjectMetric(projectName, pluginName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project metric"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, projectMetric, http.StatusOK)
+}
+
+// @Summary Create a new ProjectMetrics
+// @Description Create  a new ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /project_metrics [post]
+func PostProjectMetrics(c *gin.Context) {

Review Comment:
   Same as above, it can work, but not standard way of RESTful API



##########
api/project/project.go:
##########
@@ -0,0 +1,226 @@
+/*
+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 project
+
+import (
+	"net/http"
+
+	"github.com/apache/incubator-devlake/api/shared"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/services"
+	"github.com/gin-gonic/gin"
+)
+
+// @Summary Create and run a new project
+// @Description Create and run a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [get]
+func GetProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	project, err := services.GetProject(projectName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusOK)
+}
+
+// @Summary Get list of projects
+// @Description GET /projects?page=1&pagesize=10
+// @Tags framework/projects
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} gin.H
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects [get]
+func GetProjects(c *gin.Context) {
+	var query services.ProjectQuery
+	err := c.ShouldBindQuery(&query)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+	projects, count, err := services.GetProjects(&query)
+	if err != nil {
+		shared.ApiOutputAbort(c, errors.Default.Wrap(err, "error getting projects"))
+		return
+	}
+	shared.ApiOutputSuccess(c, gin.H{"project": projects, "count": count}, http.StatusOK)
+}
+
+// @Summary Create a new project
+// @Description Create a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects [post]
+func PostProject(c *gin.Context) {
+	project := &models.Project{}
+
+	err := c.ShouldBind(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	err = services.CreateProject(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error creating project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Summary Patch a project
+// @Description Patch a project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [patch]
+func PatchProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	var body map[string]interface{}
+	err := c.ShouldBind(&body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	project, err := services.PatchProject(projectName, body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error patch project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Cancel a project
+// @Description Cancel a project
+// @Tags framework/projects
+// @Success 200
+// @Failure 400  {string} er2rcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects/:projectName [delete]
+//func DeleteProject(c *gin.Context) {
+//}
+
+// @Summary Get a ProjectMetrics
+// @Description Get a ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /project_metrics/:projectName/:pluginName [get]
+func GetProjectMetric(c *gin.Context) {
+	projectName := c.Param("projectName")
+	pluginName := c.Param("pluginName")
+
+	projectMetric, err := services.GetProjectMetric(projectName, pluginName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project metric"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, projectMetric, http.StatusOK)
+}
+
+// @Summary Create a new ProjectMetrics
+// @Description Create  a new ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /project_metrics [post]
+func PostProjectMetrics(c *gin.Context) {
+	projectMetric := &models.ProjectMetric{}
+
+	err := c.ShouldBind(projectMetric)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	err = services.CreateProjectMetric(projectMetric)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error creating project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, projectMetric, http.StatusCreated)
+}
+
+// @Summary Patch a ProjectMetrics
+// @Description Patch a ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Accept application/json
+// @Param ProjectMetrics body models.ProjectMetric true "json"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /project_metrics/:projectName/:pluginName  [patch]
+func PatchProjectMetrics(c *gin.Context) {

Review Comment:
   same as above



##########
api/router.go:
##########
@@ -58,7 +59,22 @@ func RegisterRouter(r *gin.Engine) {
 	r.POST("/push/:tableName", push.Post)
 	r.GET("/domainlayer/repos", domainlayer.ReposIndex)
 
+	// plugin api
 	r.GET("/plugininfo", plugininfo.Get)
+	r.GET("/plugins", plugininfo.GetPluginNames)
+
+	// project api
+	r.GET("/projects/:projectName", project.GetProject)
+	r.PATCH("/projects/:projectName", project.PatchProject)
+	//r.DELETE("/projects/:projectName", project.DeleteProject)
+	r.POST("/projects", project.PostProject)
+	r.GET("/projects", project.GetProjects)
+
+	// project metric api
+	r.GET("/project_metrics/:projectName/:pluginName", project.GetProjectMetric)
+	r.PATCH("/project_metrics/:projectName/:pluginName", project.PatchProjectMetrics)
+	//r.DELETE("/project_metrics/:projectName/:pluginName", project.DeleteProjectMetrics)
+	r.POST("/project_metrics", project.PostProjectMetrics)

Review Comment:
   Same as above



##########
plugins/core/plugin_metric.go:
##########
@@ -0,0 +1,49 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package core
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+)
+
+/*
+ */
+type Tabler interface {
+	TableName() string
+}
+
+type PluginMetric interface {
+	// returns a list of required data entities and expected features.
+	// [{ "model": "cicd_tasks", "requiredFields": {"column": "type", "execptedValue": "Deployment"}}, ...]
+	RequiredDataEntities() (data []map[string]interface{}, err errors.Error)
+
+	// This method returns all models of the current plugin

Review Comment:
   This belongs to another interface I believe...
   It is for another purpose, we don't need it here.



##########
api/plugininfo/plugininifo.go:
##########
@@ -178,3 +179,24 @@ func Get(c *gin.Context) {
 
 	shared.ApiOutputSuccess(c, info, http.StatusOK)
 }
+
+// @Get name list of plugins
+// @Description GET /plugins
+// @Description RETURN SAMPLE
+// @Tags framework/plugins
+// @Success 200
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Router /plugins [get]

Review Comment:
   This is not enough, we should output more to help `config-ui` renders interfaces.
   Please check the prototype, config-ui obviously need to know whether a plugin is `Data Source` plugin or `Metric` plugin.
   So, we should output an object array instead of plain names.
   
   if a plugin implemented `PlugMetric` interface, it should contains a field named `metric`
   ![image](https://user-images.githubusercontent.com/61080/201276367-a1e4881a-e3a1-4185-9c90-dc2b2b9b850d.png)
   
   



##########
api/router.go:
##########
@@ -58,7 +59,22 @@ func RegisterRouter(r *gin.Engine) {
 	r.POST("/push/:tableName", push.Post)
 	r.GET("/domainlayer/repos", domainlayer.ReposIndex)
 
+	// plugin api
 	r.GET("/plugininfo", plugininfo.Get)
+	r.GET("/plugins", plugininfo.GetPluginNames)
+
+	// project api
+	r.GET("/projects/:projectName", project.GetProject)
+	r.PATCH("/projects/:projectName", project.PatchProject)
+	//r.DELETE("/projects/:projectName", project.DeleteProject)
+	r.POST("/projects", project.PostProject)
+	r.GET("/projects", project.GetProjects)
+
+	// project metric api
+	r.GET("/project_metrics/:projectName/:pluginName", project.GetProjectMetric)
+	r.PATCH("/project_metrics/:projectName/:pluginName", project.PatchProjectMetrics)

Review Comment:
   Same as above



##########
api/project/project.go:
##########
@@ -0,0 +1,226 @@
+/*
+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 project
+
+import (
+	"net/http"
+
+	"github.com/apache/incubator-devlake/api/shared"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/services"
+	"github.com/gin-gonic/gin"
+)
+
+// @Summary Create and run a new project
+// @Description Create and run a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [get]
+func GetProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	project, err := services.GetProject(projectName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusOK)
+}
+
+// @Summary Get list of projects
+// @Description GET /projects?page=1&pagesize=10
+// @Tags framework/projects
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} gin.H
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects [get]
+func GetProjects(c *gin.Context) {
+	var query services.ProjectQuery
+	err := c.ShouldBindQuery(&query)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+	projects, count, err := services.GetProjects(&query)
+	if err != nil {
+		shared.ApiOutputAbort(c, errors.Default.Wrap(err, "error getting projects"))
+		return
+	}
+	shared.ApiOutputSuccess(c, gin.H{"project": projects, "count": count}, http.StatusOK)
+}
+
+// @Summary Create a new project
+// @Description Create a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects [post]
+func PostProject(c *gin.Context) {
+	project := &models.Project{}
+
+	err := c.ShouldBind(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	err = services.CreateProject(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error creating project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Summary Patch a project
+// @Description Patch a project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [patch]
+func PatchProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	var body map[string]interface{}
+	err := c.ShouldBind(&body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	project, err := services.PatchProject(projectName, body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error patch project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Cancel a project
+// @Description Cancel a project
+// @Tags framework/projects
+// @Success 200
+// @Failure 400  {string} er2rcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects/:projectName [delete]
+//func DeleteProject(c *gin.Context) {
+//}
+
+// @Summary Get a ProjectMetrics
+// @Description Get a ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /project_metrics/:projectName/:pluginName [get]

Review Comment:
   According to RESTful spec, it should be `/projects/:projectName/metrics`



##########
api/router.go:
##########
@@ -58,7 +59,22 @@ func RegisterRouter(r *gin.Engine) {
 	r.POST("/push/:tableName", push.Post)
 	r.GET("/domainlayer/repos", domainlayer.ReposIndex)
 
+	// plugin api
 	r.GET("/plugininfo", plugininfo.Get)
+	r.GET("/plugins", plugininfo.GetPluginNames)
+
+	// project api
+	r.GET("/projects/:projectName", project.GetProject)
+	r.PATCH("/projects/:projectName", project.PatchProject)
+	//r.DELETE("/projects/:projectName", project.DeleteProject)
+	r.POST("/projects", project.PostProject)
+	r.GET("/projects", project.GetProjects)
+
+	// project metric api
+	r.GET("/project_metrics/:projectName/:pluginName", project.GetProjectMetric)

Review Comment:
   Same as above



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3679: feat: add project to support resource classification

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1023470327


##########
api/plugininfo/plugininifo.go:
##########
@@ -178,3 +180,47 @@ func Get(c *gin.Context) {
 
 	shared.ApiOutputSuccess(c, info, http.StatusOK)
 }
+
+// @Get name list of plugins
+// @Description GET /plugins
+// @Description RETURN SAMPLE
+// @Tags framework/plugins
+// @Success 200

Review Comment:
   We should define a struct for the API Response and append it to the 200 response



##########
services/project.go:
##########
@@ -0,0 +1,157 @@
+/*
+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 services
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/helper"
+)
+
+// ProjectQuery used to query projects as the api project input
+type ProjectQuery struct {
+	Page     int `form:"page"`
+	PageSize int `form:"pageSize"`
+}
+
+// CreateProject accepts a project instance and insert it to database
+func CreateProject(project *models.Project) errors.Error {
+	enProject, err := encryptProject(project)

Review Comment:
   Why? does a project have any encrypted field? If not, the `xxxxDbProject` functions are also unnecessary.



##########
api/plugininfo/plugininifo.go:
##########
@@ -178,3 +180,47 @@ func Get(c *gin.Context) {
 
 	shared.ApiOutputSuccess(c, info, http.StatusOK)
 }
+
+// @Get name list of plugins
+// @Description GET /plugins
+// @Description RETURN SAMPLE
+// @Tags framework/plugins
+// @Success 200
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Router /plugins [get]
+func GetPluginNames(c *gin.Context) {

Review Comment:
   The function name is not accurate, maybe `GetPluginMetas`?



##########
services/project_helper.go:
##########
@@ -0,0 +1,170 @@
+/*
+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 services
+
+import (
+	goerror "errors"
+	"fmt"
+
+	"github.com/apache/incubator-devlake/config"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/core"
+	"gorm.io/gorm"
+)
+
+// CreateDbProject accepts a project instance and insert it to database
+func CreateDbProject(project *models.Project) errors.Error {
+	err := db.Create(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project")
+	}
+	return nil
+}
+
+// CreateDbProjectMetric accepts a project metric instance and insert it to database
+func CreateDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Create(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project metric")
+	}
+	return nil
+}
+
+// SaveDbProject save a project instance and update it to database
+func SaveDbProject(project *models.Project) errors.Error {
+	err := db.Save(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project")
+	}
+	return nil
+}
+
+// SaveDbProjectMetric save a project instance and update it to database
+func SaveDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Save(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project metric")
+	}
+	return nil
+}
+
+// GetDbProjects returns a paginated list of Project based on `query`
+func GetDbProjects(query *ProjectQuery) ([]*models.Project, int64, errors.Error) {
+	projects := make([]*models.Project, 0)
+	db := db.Model(projects).Order("created_at desc")
+
+	var count int64
+	err := db.Count(&count).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error getting DB count of project")
+	}
+	db = processDbClausesWithPager(db, query.PageSize, query.Page)
+
+	err = db.Find(&projects).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error finding DB project")
+	}
+
+	return projects, count, nil
+}
+
+// GetDbProject returns the detail of a given project name
+func GetDbProject(name string) (*models.Project, errors.Error) {
+	project := &models.Project{}
+	project.Name = name
+
+	err := db.First(project).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, fmt.Sprintf("could not find project [%s] in DB", name))
+		}
+		return nil, errors.Default.Wrap(err, "error getting project from DB")
+	}
+
+	return project, nil
+}
+
+// GetDbProjectMetric returns the detail of a given project name
+func GetDbProjectMetric(projectName string, pluginName string) (*models.ProjectMetric, errors.Error) {
+	projectMetric := &models.ProjectMetric{}
+	projectMetric.ProjectName = projectName
+	projectMetric.PluginName = pluginName
+
+	err := db.First(projectMetric).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, fmt.Sprintf("could not find project metric [%s][%s] in DB", projectName, pluginName))
+		}
+		return nil, errors.Default.Wrap(err, "error getting project metric from DB")
+	}
+
+	return projectMetric, nil
+}
+
+// encryptProject
+func encryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describeEncrypt, err := core.Encrypt(encKey, project.Description)
+	if err != nil {
+		return nil, err
+	}
+	project.Description = describeEncrypt
+
+	return project, nil
+}
+
+// encryptProjectMetric
+func encryptProjectMetric(projectMetric *models.ProjectMetric) (*models.ProjectMetric, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	pluginOption, err := core.Encrypt(encKey, projectMetric.PluginOption)
+	if err != nil {
+		return nil, err
+	}
+	projectMetric.PluginOption = pluginOption
+
+	return projectMetric, nil
+}
+
+// decryptProject
+func decryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describe, err := core.Decrypt(encKey, project.Description)

Review Comment:
   No... I don't think it needs to be encrypted either.



##########
models/migrationscripts/20221109_add_project_tables.go:
##########
@@ -0,0 +1,69 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/helpers/migrationhelper"
+	"github.com/apache/incubator-devlake/models/migrationscripts/archived"
+	"github.com/apache/incubator-devlake/plugins/core"
+)
+
+var _ core.MigrationScript = (*addProjectTables)(nil)
+
+type addProjectTables struct{}
+
+type Project struct {
+	Name        string `gorm:"primaryKey;type:varchar(255)"`
+	Description string `gorm:"type:text"`
+
+	archived.NoPKModel
+}
+
+func (Project) TableName() string {
+	return "_devlake_projects"

Review Comment:
   No, it is `projects`, belongs to Domain Layer



##########
services/project_helper.go:
##########
@@ -0,0 +1,170 @@
+/*
+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 services
+
+import (
+	goerror "errors"
+	"fmt"
+
+	"github.com/apache/incubator-devlake/config"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/core"
+	"gorm.io/gorm"
+)
+
+// CreateDbProject accepts a project instance and insert it to database
+func CreateDbProject(project *models.Project) errors.Error {
+	err := db.Create(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project")
+	}
+	return nil
+}
+
+// CreateDbProjectMetric accepts a project metric instance and insert it to database
+func CreateDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Create(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error creating DB project metric")
+	}
+	return nil
+}
+
+// SaveDbProject save a project instance and update it to database
+func SaveDbProject(project *models.Project) errors.Error {
+	err := db.Save(project).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project")
+	}
+	return nil
+}
+
+// SaveDbProjectMetric save a project instance and update it to database
+func SaveDbProjectMetric(projectMetric *models.ProjectMetric) errors.Error {
+	err := db.Save(projectMetric).Error
+	if err != nil {
+		return errors.Default.Wrap(err, "error saving DB project metric")
+	}
+	return nil
+}
+
+// GetDbProjects returns a paginated list of Project based on `query`
+func GetDbProjects(query *ProjectQuery) ([]*models.Project, int64, errors.Error) {
+	projects := make([]*models.Project, 0)
+	db := db.Model(projects).Order("created_at desc")
+
+	var count int64
+	err := db.Count(&count).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error getting DB count of project")
+	}
+	db = processDbClausesWithPager(db, query.PageSize, query.Page)
+
+	err = db.Find(&projects).Error
+	if err != nil {
+		return nil, 0, errors.Default.Wrap(err, "error finding DB project")
+	}
+
+	return projects, count, nil
+}
+
+// GetDbProject returns the detail of a given project name
+func GetDbProject(name string) (*models.Project, errors.Error) {
+	project := &models.Project{}
+	project.Name = name
+
+	err := db.First(project).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, fmt.Sprintf("could not find project [%s] in DB", name))
+		}
+		return nil, errors.Default.Wrap(err, "error getting project from DB")
+	}
+
+	return project, nil
+}
+
+// GetDbProjectMetric returns the detail of a given project name
+func GetDbProjectMetric(projectName string, pluginName string) (*models.ProjectMetric, errors.Error) {
+	projectMetric := &models.ProjectMetric{}
+	projectMetric.ProjectName = projectName
+	projectMetric.PluginName = pluginName
+
+	err := db.First(projectMetric).Error
+	if err != nil {
+		if goerror.Is(err, gorm.ErrRecordNotFound) {
+			return nil, errors.NotFound.Wrap(err, fmt.Sprintf("could not find project metric [%s][%s] in DB", projectName, pluginName))
+		}
+		return nil, errors.Default.Wrap(err, "error getting project metric from DB")
+	}
+
+	return projectMetric, nil
+}
+
+// encryptProject
+func encryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describeEncrypt, err := core.Encrypt(encKey, project.Description)
+	if err != nil {
+		return nil, err
+	}
+	project.Description = describeEncrypt
+
+	return project, nil
+}
+
+// encryptProjectMetric
+func encryptProjectMetric(projectMetric *models.ProjectMetric) (*models.ProjectMetric, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	pluginOption, err := core.Encrypt(encKey, projectMetric.PluginOption)
+	if err != nil {
+		return nil, err
+	}
+	projectMetric.PluginOption = pluginOption
+
+	return projectMetric, nil
+}
+
+// decryptProject
+func decryptProject(project *models.Project) (*models.Project, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	describe, err := core.Decrypt(encKey, project.Description)
+	if err != nil {
+		return nil, err
+	}
+	project.Description = describe
+
+	return project, nil
+}
+
+// decryptProjectMetric
+func decryptProjectMetric(projectMetric *models.ProjectMetric) (*models.ProjectMetric, errors.Error) {
+	encKey := config.GetConfig().GetString(core.EncodeKeyEnvStr)
+
+	pluginOption, err := core.Decrypt(encKey, projectMetric.PluginOption)

Review Comment:
   I don't think this field would contain sensitive information.



##########
services/project_helper.go:
##########
@@ -0,0 +1,170 @@
+/*
+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 services

Review Comment:
   Not necessary



##########
models/migrationscripts/20221109_add_project_tables.go:
##########
@@ -0,0 +1,69 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/helpers/migrationhelper"
+	"github.com/apache/incubator-devlake/models/migrationscripts/archived"
+	"github.com/apache/incubator-devlake/plugins/core"
+)
+
+var _ core.MigrationScript = (*addProjectTables)(nil)
+
+type addProjectTables struct{}
+
+type Project struct {
+	Name        string `gorm:"primaryKey;type:varchar(255)"`
+	Description string `gorm:"type:text"`
+
+	archived.NoPKModel
+}
+
+func (Project) TableName() string {
+	return "_devlake_projects"
+}
+
+type ProjectMetric struct {
+	ProjectName  string `gorm:"primaryKey;type:varchar(255)"`
+	PluginName   string `gorm:"primaryKey;type:varchar(255)"`
+	PluginOption string `gorm:"type:text"`
+
+	archived.NoPKModel
+}
+
+func (ProjectMetric) TableName() string {
+	return "_devlake_project_metrics"

Review Comment:
   Same as above



##########
api/project/project.go:
##########
@@ -0,0 +1,235 @@
+/*
+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 project
+
+import (
+	"net/http"
+
+	"github.com/apache/incubator-devlake/api/shared"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/services"
+	"github.com/gin-gonic/gin"
+)
+
+// @Summary Create and run a new project
+// @Description Create and run a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [get]
+func GetProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	project, err := services.GetProject(projectName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusOK)
+}
+
+// @Summary Get list of projects
+// @Description GET /projects?page=1&pagesize=10
+// @Tags framework/projects
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} gin.H

Review Comment:
   No, define a struct for that, make sure the swag web page could show the correct response example.  `git.H` is obviously incorrect. 



##########
services/project.go:
##########
@@ -0,0 +1,157 @@
+/*
+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 services
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/helper"
+)
+
+// ProjectQuery used to query projects as the api project input
+type ProjectQuery struct {
+	Page     int `form:"page"`
+	PageSize int `form:"pageSize"`
+}
+
+// CreateProject accepts a project instance and insert it to database
+func CreateProject(project *models.Project) errors.Error {
+	enProject, err := encryptProject(project)

Review Comment:
   Same to the below APIs



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh merged pull request #3679: feat: add project to support resource classification

Posted by GitBox <gi...@apache.org>.
klesh merged PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3679: feat: add project to support resource classification

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1023901820


##########
api/project/project.go:
##########
@@ -0,0 +1,243 @@
+/*
+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 project
+
+import (
+	"net/http"
+
+	"github.com/apache/incubator-devlake/api/shared"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/services"
+	"github.com/gin-gonic/gin"
+)
+
+type ProjectCount struct {
+	Projects []*models.Project
+	Count    int64
+}
+
+// @Summary Create and run a new project
+// @Description Create and run a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [get]
+func GetProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	project, err := services.GetProject(projectName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusOK)
+}
+
+// @Summary Get list of projects
+// @Description GET /projects?page=1&pagesize=10
+// @Tags framework/projects
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} ProjectCount
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects [get]
+func GetProjects(c *gin.Context) {
+	var query services.ProjectQuery
+	err := c.ShouldBindQuery(&query)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+	projects, count, err := services.GetProjects(&query)
+	if err != nil {
+		shared.ApiOutputAbort(c, errors.Default.Wrap(err, "error getting projects"))
+		return
+	}
+	shared.ApiOutputSuccess(c, ProjectCount{
+		Projects: projects,
+		Count:    count,
+	}, http.StatusOK)
+}
+
+// @Summary Create a new project
+// @Description Create a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects [post]
+func PostProject(c *gin.Context) {
+	project := &models.Project{}
+
+	err := c.ShouldBind(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	err = services.CreateProject(project)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error creating project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Summary Patch a project
+// @Description Patch a project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [patch]
+func PatchProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	var body map[string]interface{}
+	err := c.ShouldBind(&body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.BadInput.Wrap(err, shared.BadRequestBody))
+		return
+	}
+
+	project, err := services.PatchProject(projectName, body)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error patch project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusCreated)
+}
+
+// @Cancel a project
+// @Description Cancel a project
+// @Tags framework/projects
+// @Success 200
+// @Failure 400  {string} er2rcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects/:projectName [delete]
+//func DeleteProject(c *gin.Context) {
+//}
+
+// @Summary Get a ProjectMetrics
+// @Description Get a ProjectMetrics
+// @Tags framework/ProjectMetrics
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} models.ProjectMetric
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internel Error"
+// @Router /projects/:projectName/metrics/:pluginName [get]
+func GetProjectMetric(c *gin.Context) {

Review Comment:
   `GetProjectMetrics`



##########
api/project/project.go:
##########
@@ -0,0 +1,243 @@
+/*
+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 project
+
+import (
+	"net/http"
+
+	"github.com/apache/incubator-devlake/api/shared"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/services"
+	"github.com/gin-gonic/gin"
+)
+
+type ProjectCount struct {
+	Projects []*models.Project
+	Count    int64
+}
+
+// @Summary Create and run a new project
+// @Description Create and run a new project
+// @Tags framework/projects
+// @Accept application/json
+// @Param project body models.Project true "json"
+// @Success 200  {object} models.Project
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /projects/:projectName [get]
+func GetProject(c *gin.Context) {
+	projectName := c.Param("projectName")
+
+	project, err := services.GetProject(projectName)
+	if err != nil {
+		shared.ApiOutputError(c, errors.Default.Wrap(err, "error getting project"))
+		return
+	}
+
+	shared.ApiOutputSuccess(c, project, http.StatusOK)
+}
+
+// @Summary Get list of projects
+// @Description GET /projects?page=1&pagesize=10
+// @Tags framework/projects
+// @Param page query int true "query"
+// @Param pagesize query int true "query"
+// @Success 200  {object} ProjectCount

Review Comment:
   Not very descriptive, maybe `PaginatedProjects`?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] warren830 commented on a diff in pull request #3679: feat: add project api and tables

Posted by GitBox <gi...@apache.org>.
warren830 commented on code in PR #3679:
URL: https://github.com/apache/incubator-devlake/pull/3679#discussion_r1015354095


##########
services/project.go:
##########
@@ -0,0 +1,146 @@
+/*
+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 services
+
+import (
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models"
+	"github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ProjectQuery struct {

Review Comment:
   please add annotation



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org