This is an automated email from the ASF dual-hosted git repository.

klesh 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 a7dbf425 feat: add `mode` to blueprint entity (#2228)
a7dbf425 is described below

commit a7dbf4253fc1d8b7af2908e2af78b5f7312da29f
Author: Klesh Wong <[email protected]>
AuthorDate: Mon Jun 20 14:52:20 2022 +0800

    feat: add `mode` to blueprint entity (#2228)
    
    * feat: add `mode` to blueprint entity
    
    * feat: schedule blueprints with cron_config != MANUAL
    
    * feat: disable NORMAL mode
    
    * feat: separate Manual option from cronConfig
---
 api/blueprints/blueprints.go                       | 10 +--
 models/blueprint.go                                |  9 +-
 models/migrationscripts/register.go                |  2 +-
 .../updateSchemas20220616.go}                      | 36 +++++---
 services/blueprint.go                              | 99 ++++++++++------------
 services/init.go                                   |  3 +
 6 files changed, 84 insertions(+), 75 deletions(-)

diff --git a/api/blueprints/blueprints.go b/api/blueprints/blueprints.go
index 28463cb3..4bd5bb93 100644
--- a/api/blueprints/blueprints.go
+++ b/api/blueprints/blueprints.go
@@ -164,17 +164,13 @@ func Patch(c *gin.Context) {
                shared.ApiOutputError(c, err, http.StatusBadRequest)
                return
        }
-       blueprint, err := services.GetBlueprint(id)
-       if err != nil {
-               shared.ApiOutputError(c, err, http.StatusBadRequest)
-               return
-       }
-       err = c.ShouldBind(blueprint)
+       var body map[string]interface{}
+       err = c.ShouldBind(&body)
        if err != nil {
                shared.ApiOutputError(c, err, http.StatusBadRequest)
                return
        }
-       err = services.UpdateBlueprint(blueprint)
+       blueprint, err := services.PatchBlueprint(id, body)
        if err != nil {
                shared.ApiOutputError(c, err, http.StatusBadRequest)
                return
diff --git a/models/blueprint.go b/models/blueprint.go
index 1368645b..9ae9052e 100644
--- a/models/blueprint.go
+++ b/models/blueprint.go
@@ -22,11 +22,16 @@ import (
        "gorm.io/datatypes"
 )
 
+const BLUEPRINT_MODE_NORMAL = "NORMAL"
+const BLUEPRINT_MODE_ADVANCED = "ADVANCED"
+
 type Blueprint struct {
        Name       string         `json:"name" validate:"required"`
-       Tasks      datatypes.JSON `json:"tasks" validate:"required"`
+       Mode       string         `json:"mode" gorm:"varchar(20)" 
validate:"required,oneof=NORMAL ADVANCED"`
+       Tasks      datatypes.JSON `json:"tasks"`
        Enable     bool           `json:"enable"`
-       CronConfig string         `json:"cronConfig" validate:"required"`
+       CronConfig string         `json:"cronConfig"`
+       IsManual   bool           `json:"isManual"`
        common.Model
 }
 
diff --git a/models/migrationscripts/register.go 
b/models/migrationscripts/register.go
index d9adfcbb..3f1c1dec 100644
--- a/models/migrationscripts/register.go
+++ b/models/migrationscripts/register.go
@@ -27,6 +27,6 @@ func All() []migration.Script {
                new(updateSchemas20220513), new(updateSchemas20220524), 
new(updateSchemas20220526),
                new(updateSchemas20220527), new(updateSchemas20220528), 
new(updateSchemas20220601),
                new(updateSchemas20220602), new(updateSchemas20220612), 
new(updateSchemas20220613),
-               new(updateSchemas20220614), new(updateSchemas2022061402),
+               new(updateSchemas20220614), new(updateSchemas2022061402), 
new(updateSchemas20220616),
        }
 }
diff --git a/models/blueprint.go 
b/models/migrationscripts/updateSchemas20220616.go
similarity index 56%
copy from models/blueprint.go
copy to models/migrationscripts/updateSchemas20220616.go
index 1368645b..dcb84c32 100644
--- a/models/blueprint.go
+++ b/models/migrationscripts/updateSchemas20220616.go
@@ -15,21 +15,37 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package models
+package migrationscripts
 
 import (
-       "github.com/apache/incubator-devlake/models/common"
-       "gorm.io/datatypes"
+       "context"
+
+       "gorm.io/gorm"
 )
 
-type Blueprint struct {
-       Name       string         `json:"name" validate:"required"`
-       Tasks      datatypes.JSON `json:"tasks" validate:"required"`
-       Enable     bool           `json:"enable"`
-       CronConfig string         `json:"cronConfig" validate:"required"`
-       common.Model
+type Blueprint20220616 struct {
+       Mode     string `json:"mode" gorm:"varchar(20)" 
validate:"required,oneof=NORMAL ADVANCED"`
+       IsManual bool   `json:"isManual"`
 }
 
-func (Blueprint) TableName() string {
+func (Blueprint20220616) TableName() string {
        return "_devlake_blueprints"
 }
+
+type updateSchemas20220616 struct{}
+
+func (*updateSchemas20220616) Up(ctx context.Context, db *gorm.DB) error {
+       err := db.Migrator().AutoMigrate(&Blueprint20220616{})
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+func (*updateSchemas20220616) Version() uint64 {
+       return 20220616110537
+}
+
+func (*updateSchemas20220616) Name() string {
+       return "add mode field to blueprint"
+}
diff --git a/services/blueprint.go b/services/blueprint.go
index 561a4b72..4055c739 100644
--- a/services/blueprint.go
+++ b/services/blueprint.go
@@ -25,6 +25,7 @@ import (
        "github.com/apache/incubator-devlake/logger"
        "github.com/apache/incubator-devlake/models"
        "github.com/go-playground/validator/v10"
+       "github.com/mitchellh/mapstructure"
        "github.com/robfig/cron/v3"
        "gorm.io/gorm"
 )
@@ -89,86 +90,71 @@ func GetBlueprint(blueprintId uint64) (*models.Blueprint, 
error) {
        return blueprint, nil
 }
 
-/*
-func ModifyBlueprint(newBlueprint *models.EditBlueprint) (*models.Blueprint, 
error) {
-       _, err := cron.ParseStandard(newBlueprint.CronConfig)
-       if err != nil {
-               return nil, fmt.Errorf("invalid cronConfig: %w", err)
+func validateBlueprint(blueprint *models.Blueprint) error {
+       // TODO: implement NORMAL mode
+       if blueprint.Mode == models.BLUEPRINT_MODE_NORMAL {
+               return fmt.Errorf("NORMAL mode is yet to be implemented")
        }
-
-       blueprint := models.Blueprint{}
-       err = db.Model(&models.Blueprint{}).
-               Where("id = ?", 
newBlueprint.BlueprintId).Limit(1).Find(&blueprint).Error
+       // validation
+       err := vld.Struct(blueprint)
        if err != nil {
-               return nil, err
-       }
-       // update cronConfig
-       if newBlueprint.CronConfig != "" {
-               blueprint.CronConfig = newBlueprint.CronConfig
+               return err
        }
-       // update tasks
-       if newBlueprint.Tasks != nil {
-               blueprint.Tasks, err = json.Marshal(newBlueprint.Tasks)
+       if blueprint.CronConfig != "" {
+               _, err = cron.ParseStandard(blueprint.CronConfig)
                if err != nil {
-                       return nil, err
+                       return fmt.Errorf("invalid cronConfig: %w", err)
                }
+       } else if blueprint.IsManual == false {
+               return fmt.Errorf("cronConfig is required for Automated 
blueprint")
        }
-       blueprint.Enable = newBlueprint.Enable
-
-       err = db.Model(&models.Blueprint{}).
-               Clauses(clause.OnConflict{UpdateAll: 
true}).Create(&blueprint).Error
-       if err != nil {
-               return nil, errors.InternalError
-       }
-       err = ReloadBlueprints(cronManager)
-       if err != nil {
-               return nil, errors.InternalError
+       if blueprint.Mode == models.BLUEPRINT_MODE_ADVANCED {
+               tasks := make([][]models.NewTask, 0)
+               err = json.Unmarshal(blueprint.Tasks, &tasks)
+               if err != nil {
+                       return fmt.Errorf("invalid tasks: %w", err)
+               }
+               // tasks should not be empty
+               if len(tasks) == 0 || len(tasks[0]) == 0 {
+                       return fmt.Errorf("empty tasks")
+               }
        }
-       return &blueprint, nil
+       // TODO: validate each of every task object
+       return nil
 }
-*/
 
-func validateBlueprint(blueprint *models.Blueprint) error {
-       // validation
-       err := vld.Struct(blueprint)
-       if err != nil {
-               return err
-       }
-       _, err = cron.ParseStandard(blueprint.CronConfig)
+func PatchBlueprint(id uint64, body map[string]interface{}) 
(*models.Blueprint, error) {
+       // load record from db
+       blueprint, err := GetBlueprint(id)
        if err != nil {
-               return fmt.Errorf("invalid cronConfig: %w", err)
+               return nil, err
        }
-       tasks := make([][]models.NewTask, 0)
-       err = json.Unmarshal(blueprint.Tasks, &tasks)
+       originMode := blueprint.Mode
+       err = mapstructure.Decode(body, blueprint)
        if err != nil {
-               return fmt.Errorf("invalid tasks: %w", err)
+               return nil, err
        }
-       // tasks should not be empty
-       if len(tasks) == 0 || len(tasks[0]) == 0 {
-               return fmt.Errorf("empty tasks")
+       // make sure mode is not being update
+       if originMode != blueprint.Mode {
+               return nil, fmt.Errorf("mode is not updatable")
        }
-       // TODO: validate each of every task object
-       return nil
-}
-
-func UpdateBlueprint(blueprint *models.Blueprint) error {
        // validation
-       err := validateBlueprint(blueprint)
+       err = validateBlueprint(blueprint)
        if err != nil {
-               return err
+               return nil, err
        }
        // save
        err = db.Save(blueprint).Error
        if err != nil {
-               return errors.InternalError
+               return nil, errors.InternalError
        }
        // reload schedule
        err = ReloadBlueprints(cronManager)
        if err != nil {
-               return errors.InternalError
+               return nil, errors.InternalError
        }
        // done
-       return nil
+       return blueprint, nil
 }
 
 func DeleteBlueprint(id uint64) error {
@@ -185,7 +171,9 @@ func DeleteBlueprint(id uint64) error {
 
 func ReloadBlueprints(c *cron.Cron) error {
        blueprints := make([]*models.Blueprint, 0)
-       err := db.Model(&models.Blueprint{}).Where("enable = ?", 
true).Find(&blueprints).Error
+       err := db.Model(&models.Blueprint{}).
+               Where("enable = ? AND is_manual = ?", true, false).
+               Find(&blueprints).Error
        if err != nil {
                panic(err)
        }
@@ -227,5 +215,6 @@ func ReloadBlueprints(c *cron.Cron) error {
        if len(blueprints) > 0 {
                c.Start()
        }
+       log.Info("total %d blueprints were scheduled", len(blueprints))
        return nil
 }
diff --git a/services/init.go b/services/init.go
index 4843e887..dd70c17b 100644
--- a/services/init.go
+++ b/services/init.go
@@ -21,6 +21,7 @@ import (
        "context"
 
        "github.com/apache/incubator-devlake/models/migrationscripts"
+       "github.com/apache/incubator-devlake/plugins/core"
 
        "time"
 
@@ -36,10 +37,12 @@ import (
 var cfg *viper.Viper
 var db *gorm.DB
 var cronManager *cron.Cron
+var log core.Logger
 
 func init() {
        var err error
        cfg = config.GetConfig()
+       log = logger.Global
        db, err = runner.NewGormDb(cfg, logger.Global.Nested("db"))
        location := cron.WithLocation(time.UTC)
        cronManager = cron.New(location)

Reply via email to