未验证 提交 e1a6d5f0 编写于 作者: Z zhatiai 提交者: GitHub

add project view function (#2972)

* add project view function
Signed-off-by: Nzhatiai <zhatiai@koderover.com>

* change view to group
Signed-off-by: Nzhatiai <zhatiai@koderover.com>

---------
Signed-off-by: Nzhatiai <zhatiai@koderover.com>
Co-authored-by: Nzhatiai <zhatiai@koderover.com>
上级 8fc37936
/*
Copyright 2023 The KodeRover Authors.
Licensed 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 "go.mongodb.org/mongo-driver/bson/primitive"
type ProjectGroup struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
Name string `bson:"name" json:"name"`
Projects []*ProjectDetail `bson:"projects" json:"projects"`
CreatedBy string `bson:"created_by" json:"created_by"`
CreatedTime int64 `bson:"created_time" json:"created_time"`
UpdateTime int64 `bson:"update_time" json:"update_time"`
UpdateBy string `bson:"update_by" json:"update_by,omitempty"`
}
type ProjectDetail struct {
ProjectKey string `bson:"project_key" json:"project_key"`
ProjectName string `bson:"project_name" json:"project_name"`
ProjectDeployType string `bson:"project_deploy_type" json:"project_deploy_type"`
}
func (ProjectGroup) TableName() string {
return "project_group"
}
......@@ -24,6 +24,7 @@ import (
)
type Product struct {
GroupName string `bson:"-" json:"view_name"`
ProjectName string `bson:"project_name" json:"project_name"`
ProjectNamePinyin string `bson:"project_name_pinyin" json:"project_name_pinyin"`
ProjectNamePinyinFirstLetter string `bson:"project_name_pinyin_first_letter" json:"project_name_pinyin_first_letter"`
......
/*
Copyright 2023 The KodeRover Authors.
Licensed 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 mongodb
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/koderover/zadig/pkg/microservice/aslan/config"
"github.com/koderover/zadig/pkg/microservice/aslan/core/common/repository/models"
mongotool "github.com/koderover/zadig/pkg/tool/mongo"
)
type ProjectGroupColl struct {
*mongo.Collection
coll string
}
func NewProjectGroupColl() *ProjectGroupColl {
name := models.ProjectGroup{}.TableName()
return &ProjectGroupColl{Collection: mongotool.Database(config.MongoDatabase()).Collection(name), coll: name}
}
func (c *ProjectGroupColl) GetCollectionName() string {
return c.coll
}
func (c *ProjectGroupColl) EnsureIndex(ctx context.Context) error {
mod := mongo.IndexModel{
Keys: bson.D{
bson.E{Key: "name", Value: 1},
},
Options: options.Index().SetUnique(true),
}
_, err := c.Indexes().CreateOne(ctx, mod)
return err
}
func (c *ProjectGroupColl) Create(args *models.ProjectGroup) error {
if args == nil {
return errors.New("nil project group args")
}
args.CreatedTime = time.Now().Unix()
args.UpdateTime = time.Now().Unix()
_, err := c.InsertOne(context.TODO(), args)
return err
}
func (c *ProjectGroupColl) Update(args *models.ProjectGroup) error {
if args == nil {
return errors.New("nil project group args")
}
filter := bson.M{"_id": args.ID}
update := bson.M{"$set": args}
_, err := c.UpdateOne(context.TODO(), filter, update)
return err
}
func (c *ProjectGroupColl) Delete(name string) error {
filter := bson.M{"name": name}
_, err := c.DeleteOne(context.Background(), filter)
return err
}
type ProjectGroupOpts struct {
Name string
ID string
}
func (c *ProjectGroupColl) Find(opts ProjectGroupOpts) (*models.ProjectGroup, error) {
res := &models.ProjectGroup{}
query := bson.M{}
if opts.Name != "" {
query["name"] = opts.Name
}
if opts.ID != "" {
ido, err := primitive.ObjectIDFromHex(opts.ID)
if err != nil {
return nil, errors.New("invalid group id")
}
query["_id"] = ido
}
err := c.FindOne(context.Background(), query).Decode(&res)
return res, err
}
func (c *ProjectGroupColl) List() ([]*models.ProjectGroup, error) {
var resp []*models.ProjectGroup
ctx := context.Background()
query := bson.M{}
cursor, err := c.Collection.Find(ctx, query)
if err != nil {
return nil, err
}
if err := cursor.All(ctx, &resp); err != nil {
return resp, err
}
return resp, nil
}
func (c *ProjectGroupColl) ListGroupNames() ([]string, error) {
var resp []string
ctx := context.Background()
query := bson.M{}
cursor, err := c.Collection.Find(ctx, query)
if err != nil {
return nil, err
}
for cursor.Next(ctx) {
var group models.ProjectGroup
if err := cursor.Decode(&group); err != nil {
return nil, err
}
resp = append(resp, group.Name)
}
return resp, nil
}
......@@ -19,6 +19,7 @@ package handler
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
......@@ -753,3 +754,142 @@ func GetProductionGlobalVariableCandidates(c *gin.Context) {
ctx.Resp, ctx.Err = projectservice.GetGlobalVariableCandidates(c.Param("name"), true, ctx.Logger)
}
func CreateProjectGroup(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
if err != nil {
ctx.Logger.Errorf("failed to generate authorization info for user: %s, error: %s", ctx.UserID, err)
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}
// authorization checks
if !ctx.Resources.IsSystemAdmin {
if !ctx.Resources.SystemActions.Project.Create {
ctx.UnAuthorized = true
return
}
}
args := new(projectservice.ProjectGroupArgs)
data, err := c.GetRawData()
if err != nil {
ctx.Logger.Errorf("failed to get raw data from request, error: %v", err)
ctx.Err = e.ErrCreateProjectGroup.AddDesc(err.Error())
return
}
if err = json.Unmarshal(data, args); err != nil {
ctx.Logger.Errorf("failed to unmarshal data, error: %v", err)
ctx.Err = e.ErrCreateProjectGroup.AddDesc(err.Error())
return
}
if err := args.Validate(); err != nil {
ctx.Err = e.ErrCreateProjectGroup.AddErr(err)
return
}
internalhandler.InsertOperationLog(c, ctx.UserName, "", "新增", "分组", args.GroupName, string(data), ctx.Logger)
ctx.Err = projectservice.CreateProjectGroup(args, ctx.UserName, ctx.Logger)
}
func UpdateProjectGroup(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
if err != nil {
ctx.Logger.Errorf("failed to generate authorization info for user: %s, error: %s", ctx.UserID, err)
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}
// authorization checks
if !ctx.Resources.IsSystemAdmin {
if !ctx.Resources.SystemActions.Project.Create {
ctx.UnAuthorized = true
return
}
}
args := new(projectservice.ProjectGroupArgs)
data, err := c.GetRawData()
if err != nil {
ctx.Logger.Errorf("failed to get raw data from request, error: %v", err)
ctx.Err = e.ErrUpdateProjectGroup.AddDesc(err.Error())
return
}
if err = json.Unmarshal(data, args); err != nil {
ctx.Logger.Errorf("failed to unmarshal data, error: %v", err)
ctx.Err = e.ErrUpdateProjectGroup.AddDesc(err.Error())
return
}
if err := args.Validate(); err != nil {
ctx.Err = e.ErrUpdateProjectGroup.AddErr(err)
return
}
internalhandler.InsertOperationLog(c, ctx.UserName, "", "编辑", "分组", args.GroupName, string(data), ctx.Logger)
ctx.Err = projectservice.UpdateProjectGroup(args, ctx.UserName, ctx.Logger)
}
func DeleteProjectGroup(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
if err != nil {
ctx.Logger.Errorf("failed to generate authorization info for user: %s, error: %s", ctx.UserID, err)
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}
// authorization checks
if !ctx.Resources.IsSystemAdmin {
if !ctx.Resources.SystemActions.Project.Create {
ctx.UnAuthorized = true
return
}
}
groupName := c.Query("viewName")
if groupName == "" {
ctx.Err = e.ErrDeleteProjectGroup.AddErr(errors.New("view name is empty"))
return
}
internalhandler.InsertOperationLog(c, ctx.UserName, "", "删除", "分组", groupName, groupName, ctx.Logger)
ctx.Err = projectservice.DeleteProjectGroup(groupName, ctx.Logger)
}
func ListProjectGroups(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
if err != nil {
ctx.Logger.Errorf("failed to generate authorization info for user: %s, error: %s", ctx.UserID, err)
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}
ctx.Resp, ctx.Err = projectservice.ListProjectGroupNames()
}
func GetPresetProjectGroup(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
if err != nil {
ctx.Logger.Errorf("failed to generate authorization info for user: %s, error: %s", ctx.UserID, err)
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}
ctx.Resp, ctx.Err = projectservice.GetProjectGroupRelation(c.Query("viewName"), ctx.Logger)
}
......@@ -34,6 +34,7 @@ type projectListArgs struct {
PageSize int64 `json:"page_size" form:"page_size,default=20"`
PageNum int64 `json:"page_num" form:"page_num,default=1"`
Filter string `json:"filter" form:"filter"`
GroupName string `json:"view_name" form:"view_name"`
}
type projectResp struct {
......@@ -88,6 +89,7 @@ func ListProjects(c *gin.Context) {
PageSize: args.PageSize,
PageNum: args.PageNum,
Filter: args.Filter,
GroupName: args.GroupName,
},
ctx.Logger,
)
......
......@@ -55,6 +55,15 @@ func (*Router) Inject(router *gin.RouterGroup) {
product.GET("/:name/productionGlobalVariableCandidates", GetProductionGlobalVariableCandidates)
}
view := router.Group("view")
{
view.POST("", CreateProjectGroup)
view.PUT("", UpdateProjectGroup)
view.DELETE("", DeleteProjectGroup)
view.GET("", ListProjectGroups)
view.GET("/preset", GetPresetProjectGroup)
}
production := router.Group("production/products")
{
production.PATCH("/:name", UpdateProductionServiceOrchestration)
......
......@@ -21,8 +21,10 @@ import (
"encoding/json"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
......@@ -140,6 +142,15 @@ func CreateProductTemplate(args *template.Product, log *zap.SugaredLogger) (err
log.Errorf("ProductTmpl.Create error: %v", err)
return e.ErrCreateProduct.AddDesc(err.Error())
}
// add project to current project group
if args.GroupName != "" {
err = AddProject2CurrentGroup(args.GroupName, args.ProductName, args.ProjectName, args.UpdateBy, args.ProductFeature.DeployType)
if err != nil {
log.Errorf("failed to add project to current group, error: %v", err)
return e.ErrCreateProduct.AddErr(fmt.Errorf("create project successfully, but failed to add project to current group, please add the project %s to group %s manually, error: %v", args.ProductName, args.GroupName, err))
}
}
return
}
......@@ -1254,3 +1265,257 @@ func GetGlobalVariableCandidates(productName string, production bool, log *zap.S
return ret, nil
}
func CreateProjectGroup(args *ProjectGroupArgs, user string, logger *zap.SugaredLogger) error {
groups, err := commonrepo.NewProjectGroupColl().List()
if err != nil {
errMsg := fmt.Errorf("failed to list project groups, error: %v", err)
logger.Errorf(errMsg.Error())
return e.ErrCreateProjectGroup.AddErr(errMsg)
}
// find all project keys that have been set
set := sets.NewString()
for _, group := range groups {
for _, project := range group.Projects {
set.Insert(project.ProjectKey)
}
}
projects, err := templaterepo.NewProductColl().List()
if err != nil {
errMsg := fmt.Errorf("failed to list projects, error: %v", err)
logger.Errorf(errMsg.Error())
return e.ErrCreateProjectGroup.AddErr(errMsg)
}
pm := make(map[string]*template.Product)
for _, project := range projects {
pm[project.ProductName] = project
}
group := &commonmodels.ProjectGroup{
Name: args.GroupName,
CreatedTime: time.Now().Unix(),
UpdateTime: time.Now().Unix(),
CreatedBy: user,
UpdateBy: user,
Projects: make([]*commonmodels.ProjectDetail, 0),
}
for _, project := range args.ProjectKeys {
if set.Has(project) {
return e.ErrCreateProjectGroup.AddErr(fmt.Errorf("failed to set project %s to group %s, project Key %s has been set in other groups", project, args.GroupName, project))
}
if p, ok := pm[project]; ok {
group.Projects = append(group.Projects, &commonmodels.ProjectDetail{
ProjectKey: p.ProductName,
ProjectName: p.ProjectName,
ProjectDeployType: p.ProductFeature.DeployType,
})
} else {
return e.ErrCreateProjectGroup.AddErr(fmt.Errorf("project Key %s not in current project list", project))
}
}
if err := commonrepo.NewProjectGroupColl().Create(group); err != nil {
errMsg := fmt.Errorf("failed to create project group, error: %v", err)
logger.Errorf(errMsg.Error())
return e.ErrCreateProjectGroup.AddErr(errMsg)
}
return nil
}
func UpdateProjectGroup(args *ProjectGroupArgs, user string, logger *zap.SugaredLogger) error {
if args.GroupID == "" {
return e.ErrUpdateProjectGroup.AddDesc("group id can not be empty")
}
groups, err := commonrepo.NewProjectGroupColl().List()
if err != nil {
errMsg := fmt.Errorf("failed to list project groups, error: %v", err)
logger.Errorf(errMsg.Error())
return e.ErrCreateProjectGroup.AddErr(errMsg)
}
// find all project keys that have been set
set := sets.NewString()
for _, group := range groups {
if group.Name != args.GroupName {
for _, project := range group.Projects {
set.Insert(project.ProjectKey)
}
}
}
projects, err := templaterepo.NewProductColl().List()
if err != nil {
errMsg := fmt.Errorf("failed to list projects, error: %v", err)
logger.Errorf(errMsg.Error())
return e.ErrUpdateProjectGroup.AddErr(errMsg)
}
pm := make(map[string]*template.Product)
for _, project := range projects {
pm[project.ProductName] = project
}
group := &commonmodels.ProjectGroup{
Name: args.GroupName,
UpdateTime: time.Now().Unix(),
UpdateBy: user,
Projects: make([]*commonmodels.ProjectDetail, 0),
}
for _, project := range args.ProjectKeys {
if set.Has(project) {
return e.ErrCreateProjectGroup.AddErr(fmt.Errorf("failed to set project %s to group %s, project Key %s has been set in other groups", project, args.GroupName, project))
}
if p, ok := pm[project]; ok {
group.Projects = append(group.Projects, &commonmodels.ProjectDetail{
ProjectKey: p.ProductName,
ProjectName: p.ProjectName,
ProjectDeployType: p.ProductFeature.DeployType,
})
} else {
return e.ErrUpdateProjectGroup.AddErr(fmt.Errorf("project Key %s not in current project list", project))
}
}
oldGroup, err := commonrepo.NewProjectGroupColl().Find(commonrepo.ProjectGroupOpts{ID: args.GroupID})
if err != nil {
return e.ErrUpdateProjectGroup.AddErr(fmt.Errorf("failed to find project group %s, error: %v", args.GroupName, err))
}
group.ID = oldGroup.ID
group.CreatedTime = oldGroup.CreatedTime
group.CreatedBy = oldGroup.CreatedBy
if err := commonrepo.NewProjectGroupColl().Update(group); err != nil {
errMsg := fmt.Errorf("failed to update project group, groupName:%s, error: %v", oldGroup.Name, err)
logger.Errorf(errMsg.Error())
return e.ErrUpdateProjectGroup.AddErr(errMsg)
}
return nil
}
func DeleteProjectGroup(name string, logger *zap.SugaredLogger) error {
if err := commonrepo.NewProjectGroupColl().Delete(name); err != nil {
return e.ErrDeleteProjectGroup.AddErr(fmt.Errorf("failed to delete project group %s, error: %v", name, err))
}
return nil
}
func ListProjectGroupNames() ([]string, error) {
groups, err := commonrepo.NewProjectGroupColl().ListGroupNames()
if err != nil {
return nil, fmt.Errorf("failed to list project groups, error: %v", err)
}
// create the default group ungrouped
// groups = append(groups, setting.UNGROUPED)
return groups, nil
}
func GetProjectGroupRelation(name string, logger *zap.SugaredLogger) (resp *ProjectGroupPreset, err error) {
var group *commonmodels.ProjectGroup
if name != "" {
group, err = commonrepo.NewProjectGroupColl().Find(commonrepo.ProjectGroupOpts{Name: name})
if err != nil {
return nil, fmt.Errorf("failed to find project group %s, error: %v", name, err)
}
}
resp = &ProjectGroupPreset{
Projects: make([]*ProjectGroupRelation, 0),
}
if group != nil {
resp.GroupName = group.Name
resp.GroupID = group.ID.Hex()
}
if group != nil {
for _, project := range group.Projects {
resp.Projects = append(resp.Projects, &ProjectGroupRelation{
ProjectKey: project.ProjectKey,
ProjectName: project.ProjectName,
DeployType: project.ProjectDeployType,
Enabled: true,
})
}
}
unGrouped, err := GetUnGroupedProjectKeys()
if err != nil {
return nil, fmt.Errorf("failed to list ungrouped projects, error: %v", err)
}
projects, err := templaterepo.NewProductColl().ListProjectBriefs(unGrouped)
if err != nil {
return nil, fmt.Errorf("failed to list projects, error: %v", err)
}
for _, project := range projects {
resp.Projects = append(resp.Projects, &ProjectGroupRelation{
ProjectKey: project.Name,
ProjectName: project.Alias,
DeployType: project.DeployType,
Enabled: false,
})
}
sort.Slice(resp.Projects, func(i, j int) bool {
return resp.Projects[i].ProjectKey < resp.Projects[j].ProjectKey
})
return resp, nil
}
func AddProject2CurrentGroup(groupName, projectKey, projectDisplayName, deployType, user string) error {
group, err := commonrepo.NewProjectGroupColl().Find(commonrepo.ProjectGroupOpts{Name: groupName})
if err != nil {
return fmt.Errorf("failed to find project group %s, error: %v", groupName, err)
}
for _, project := range group.Projects {
if project.ProjectKey == projectKey {
return nil
}
}
group.Projects = append(group.Projects, &commonmodels.ProjectDetail{
ProjectKey: projectKey,
ProjectName: projectDisplayName,
ProjectDeployType: deployType,
})
group.UpdateBy = user
group.UpdateTime = time.Now().Unix()
if err := commonrepo.NewProjectGroupColl().Update(group); err != nil {
return fmt.Errorf("failed to update project group %s, error: %v", groupName, err)
}
return nil
}
func GetUnGroupedProjectKeys() ([]string, error) {
groups, err := commonrepo.NewProjectGroupColl().List()
if err != nil {
return nil, fmt.Errorf("failed to list project groups, error: %v", err)
}
set := sets.NewString()
for _, group := range groups {
for _, project := range group.Projects {
set.Insert(project.ProjectKey)
}
}
projects, err := templaterepo.NewProductColl().ListAllName()
if err != nil {
return nil, fmt.Errorf("failed to list projects, error: %v", err)
}
unGroupedKeys := make([]string, 0)
for _, project := range projects {
if !set.Has(project) {
unGroupedKeys = append(unGroupedKeys, project)
}
}
return unGroupedKeys, nil
}
......@@ -17,6 +17,10 @@ limitations under the License.
package service
import (
"fmt"
"github.com/koderover/zadig/pkg/setting"
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/util/sets"
......@@ -40,6 +44,7 @@ type ProjectListOptions struct {
PageSize int64
PageNum int64
Filter string
GroupName string
}
type ProjectDetailedResponse struct {
ProjectDetailedRepresentation []*ProjectDetailedRepresentation `json:"projects"`
......@@ -72,6 +77,31 @@ type ProjectMinimalRepresentation struct {
}
func ListProjects(opts *ProjectListOptions, logger *zap.SugaredLogger) (interface{}, error) {
var err error
if opts.GroupName != "" {
if opts.GroupName == setting.UNGROUPED {
opts.Names, err = GetUnGroupedProjectKeys()
if err != nil {
msg := fmt.Errorf("failed to list ungrouped projects, err: %s", err)
logger.Error(msg)
return nil, msg
}
} else {
opts.Names = make([]string, 0)
group, err := mongodb.NewProjectGroupColl().Find(mongodb.ProjectGroupOpts{Name: opts.GroupName})
if err != nil && (err != mongo.ErrNoDocuments && err != mongo.ErrNilDocument) {
logger.Errorf("Failed to list projects, err: %s", err)
return nil, err
}
if group != nil && group.Projects != nil {
for _, project := range group.Projects {
opts.Names = append(opts.Names, project.ProjectKey)
}
}
}
}
switch opts.Verbosity {
case VerbosityDetailed:
return listDetailedProjectInfos(opts, logger)
......
......@@ -153,3 +153,34 @@ func (req OpenAPIInitializeProjectReq) Validate() error {
return nil
}
type ProjectGroupArgs struct {
GroupID string `json:"view_id"`
GroupName string `json:"view_name"`
ProjectKeys []string `json:"project_keys"`
}
func (args *ProjectGroupArgs) Validate() error {
if args.GroupName == "" {
return errors.New("view_name cannot be empty")
}
if len(args.ProjectKeys) == 0 {
return errors.New("project_keys cannot be empty")
}
return nil
}
type ProjectGroupPreset struct {
GroupID string `json:"view_id"`
GroupName string `json:"view_name"`
Projects []*ProjectGroupRelation `json:"projects"`
}
type ProjectGroupRelation struct {
ProjectName string `json:"project_name"`
ProjectKey string `json:"project_key"`
DeployType string `json:"deploy_type"`
Enabled bool `json:"enabled"`
}
......@@ -467,6 +467,9 @@ func initDatabase() {
// env AI analysis related db index
ai.NewEnvAIAnalysisColl(),
// project group related db index
commonrepo.NewProjectGroupColl(),
} {
wg.Add(1)
go func(r indexer) {
......
......@@ -792,3 +792,7 @@ const (
AIEnvAnalysisStatusSuccess = "success"
AIEnvAnalysisStatusFailed = "failed"
)
const (
UNGROUPED = "未分组"
)
......@@ -166,7 +166,10 @@ var (
// TODO: max error code reached, sharing error code with update env
ErrUpdateEnvConfigs = NewHTTPError(6076, "更新环境配置失败")
// TODO: max error code reached, sharing error code with update env
ErrEnvSleep = NewHTTPError(6076, "环境睡眠失败")
ErrEnvSleep = NewHTTPError(6076, "环境睡眠失败")
ErrCreateProjectGroup = NewHTTPError(6077, "创建项目分组失败")
ErrUpdateProjectGroup = NewHTTPError(6077, "更新项目分组失败")
ErrDeleteProjectGroup = NewHTTPError(6077, "删除项目分组失败")
//-----------------------------------------------------------------------------------------------
// Product Service APIs Range: 6080 - 6099 AND 6150 -6199
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册