Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement variable set #1344

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,637 changes: 1,690 additions & 947 deletions api/openapispec/docs.go

Large diffs are not rendered by default.

2,637 changes: 1,690 additions & 947 deletions api/openapispec/swagger.json

Large diffs are not rendered by default.

1,055 changes: 790 additions & 265 deletions api/openapispec/swagger.yaml

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions pkg/domain/entity/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package entity

import "errors"

const (
PlainTextType string = "PlainText"
CipherTextType string = "CipherText"
)

// Variable represents the specific configuration code variable,
// which usually includes the global configurations for Terraform providers like
// api host, ak and sk.
type Variable struct {
// VariableKey is the access path for the variable.
VariableKey string `yaml:"variableKey,omitempty" json:"variableKey,omitempty"`
// Value is the value of the variable.
Value string `yaml:"value,omitempty" json:"value,omitempty"`
// Type is the type of the variable.
Type string `yaml:"type,omitempty" json:"type,omitempty"`
// Labels clarifies the scope of the variable.
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
// Fqn is the fully qualified name of the variable.
Fqn string `yaml:"fqn,omitempty" json:"fqn,omitempty"`
}

// VariableFilter represents the filter conditions to list variables.
type VariableFilter struct {
Key string
Pagination *Pagination
}

// VariableListResult represents the result of listing variables.
type VariableListResult struct {
Variables []*Variable
Total int
}

// Validate checks if the variable is valid.
// It returns an error if the variable is not valid.
func (v *Variable) Validate() error {
if v == nil {
return errors.New("variable is nil")
}

if v.VariableKey == "" {
return errors.New("empty variable key")
}

if v.Type != PlainTextType && v.Type != CipherTextType {
return errors.New("invalid variable type")
}

if v.Fqn == "" {
return errors.New("empty fqn")
}

return nil
}
43 changes: 43 additions & 0 deletions pkg/domain/entity/variable_labels.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package entity

import "errors"

// VariableLabels records the labels of the specific configuration code variable,
// and the labels are sorted in ascending order of priority.
type VariableLabels struct {
// VariableKey is the access path for the variable.
VariableKey string `yaml:"variableKey,omitempty" json:"variableKey,omitempty"`
// Labels is the list of variable labels, which should be sorted
// in ascending order of priority.
Labels []string `yaml:"labels,omitempty" json:"labels,omitempty"`
}

// VariableLabelsFilter represents the filter conditions to list variable labels.
type VariableLabelsFilter struct {
Labels []string
Pagination *Pagination
}

// VariableLabelsListResult represents the result of listing variable labels.
type VariableLabelsListResult struct {
VariableLabels []*VariableLabels
Total int
}

// Validate checks if the variable labels are valid.
// It returns an error if the variable labels are not valid.
func (vl *VariableLabels) Validate() error {
if vl == nil {
return errors.New("nil variable labels")
}

if vl.VariableKey == "" {
return errors.New("empty key for variable labels")
}

if len(vl.Labels) == 0 {
return errors.New("empty variable labels")
}

return nil
}
30 changes: 30 additions & 0 deletions pkg/domain/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,33 @@ type RunRepository interface {
// List retrieves all existing run.
List(ctx context.Context, filter *entity.RunFilter) (*entity.RunListResult, error)
}

// VariableLabelsRepository is an interface that defines the repository
// for variable labels. It follows the principles of domain-driven design (DDD).
type VariableLabelsRepository interface {
// Create creates a new set of variable labels.
Create(ctx context.Context, vl *entity.VariableLabels) error
// Delete deletes a set of variable labels by its key.
Delete(ctx context.Context, key string) error
// Update updates an existing set of variable labels.
Update(ctx context.Context, vl *entity.VariableLabels) error
// GetByKey retrieves a set of variable labels by its key.
GetByKey(ctx context.Context, key string) (*entity.VariableLabels, error)
// List retrieves all existing variable labels.
List(ctx context.Context, filter *entity.VariableLabelsFilter) (*entity.VariableLabelsListResult, error)
}

// VariableRepository is an interface that defines the repository operations
// for variables. It follows the principles of domain-driven design (DDD).
type VariableRepository interface {
// Create creates a new variable.
Create(ctx context.Context, v *entity.Variable) error
// Delete deletes a variable by its fqn.
Delete(ctx context.Context, fqn string) error
// Update updates an existing variable.
Update(ctx context.Context, v *entity.Variable) error
// GetByFqn retrieves a variable by its fqn.
GetByFqn(ctx context.Context, fqn string) (*entity.Variable, error)
// List retrieves all existing variables.
List(ctx context.Context, filter *entity.VariableFilter) (*entity.VariableListResult, error)
}
31 changes: 31 additions & 0 deletions pkg/domain/request/variable_labels_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package request

import "net/http"

// CreateVariableLabelsRequest represents the create request structure
// for variable labels.
type CreateVariableLabelsRequest struct {
// VariableKey is the access path for the variable.
VariableKey string `json:"variableKey" binding:"required"`
// Labels is the list of variable labels, which should be sorted
// in ascending order of priority.
Labels []string `json:"labels" binding:"required"`
}

// UpdateVariableLabelsRequest represents the update request structure
// for variable labels.
type UpdateVariableLabelsRequest struct {
// VariableKey is the access path for the variable.
VariableKey string `json:"variableKey" binding:"required"`
// Labels is the list of variable labels, which should be sorted
// in ascending order of priority.
Labels []string `json:"labels" binding:"required"`
}

func (payload *CreateVariableLabelsRequest) Decode(r *http.Request) error {
return decode(r, payload)
}

func (payload *UpdateVariableLabelsRequest) Decode(r *http.Request) error {
return decode(r, payload)
}
50 changes: 50 additions & 0 deletions pkg/domain/request/variable_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package request

import "net/http"

// CreateVariableSetRequest represents the create request structure
// for a variable in the variable set.
type CreateVariableSetRequest struct {
// VariableKey is the access path for the variable.
VariableKey string `json:"variableKey" binding:"required"`
// Value is the value of the variable.
Value string `json:"value" binding:"required"`
// Type is the type of the variable.
Type string `json:"type" binding:"required"`
// Labels clarifies the scope of the variable.
Labels map[string]string `json:"labels,omitempty"`
}

// UpdateVariableSetRequest represents the update request structure
// for a variable in the variable set.
type UpdateVariableSetRequest struct {
// VariableKey is the access path for the variable.
VariableKey string `json:"variableKey" binding:"required"`
// Value is the value of the variable.
Value string `json:"value" binding:"required"`
// Type is the type of the variable.
Type string `json:"type" binding:"required"`
// Labels clarifies the scope of the variable.
Labels map[string]string `json:"labels" binding:"required"`
// Fqn is the fully qualified name of the variable.
Fqn string `json:"fqn" binding:"required"`
}

// ListVariableSetRequest represents the list request structure
// for variables matched to the labels in the variable set.
type ListVariableSetRequest struct {
// Labels clarifies the scope of the variables.
Labels map[string]string `json:"labels" binding:"required"`
}

func (payload *CreateVariableSetRequest) Decode(r *http.Request) error {
return decode(r, payload)
}

func (payload *UpdateVariableSetRequest) Decode(r *http.Request) error {
return decode(r, payload)
}

func (payload *ListVariableSetRequest) Decode(r *http.Request) error {
return decode(r, payload)
}
10 changes: 10 additions & 0 deletions pkg/domain/response/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package response

import "kusionstack.io/kusion/pkg/domain/entity"

type PaginatedVariableResponse struct {
Variables []*entity.Variable `json:"variables"`
Total int `json:"total"`
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
}
10 changes: 10 additions & 0 deletions pkg/domain/response/variable_labels.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package response

import "kusionstack.io/kusion/pkg/domain/entity"

type PaginatedVariableLabelsResponse struct {
VariableLabels []*entity.VariableLabels `json:"variableLabels"`
Total int `json:"total"`
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
}
2 changes: 2 additions & 0 deletions pkg/infra/persistence/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ var (
ErrAppConfigModelNil = errors.New("appconfig model can't be nil")
ErrFailedToGetModuleRemote = errors.New("failed to parse module remote")
ErrResourceModelNil = errors.New("resource model can't be nil")
ErrVariableLabelsModelNil = errors.New("variable labels model can't be nil")
ErrVariableModelNil = errors.New("variable model can't be nil")
ErrFailedToGetModuleDocRemote = errors.New("failed to parse module doc remote")
ErrRunModelNil = errors.New("run model can't be nil")
ErrFailedToGetRunType = errors.New("failed to parse run type")
Expand Down
34 changes: 34 additions & 0 deletions pkg/infra/persistence/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,34 @@ func GetRunQuery(filter *entity.RunFilter) (string, []interface{}) {
return CombineQueryParts(pattern), args
}

func GetVariableLabelsQuery(filter *entity.VariableLabelsFilter) (string, []interface{}) {
pattern := make([]string, 0)
args := make([]interface{}, 0)

if len(filter.Labels) != 0 {
var labelsPattern []string
for _, label := range filter.Labels {
labelsPattern = append(labelsPattern, "labels LIKE ?")
args = append(args, "%"+label+"%")
}
pattern = append(pattern, "("+strings.Join(labelsPattern, " OR ")+")")
}

return CombineQueryParts(pattern), args
}

func GetVariableQuery(filter *entity.VariableFilter) (string, []interface{}) {
pattern := make([]string, 0)
args := make([]interface{}, 0)

if filter.Key != "" {
pattern = append(pattern, "variable_key = ?")
args = append(args, fmt.Sprintf(filter.Key))
}

return CombineQueryParts(pattern), args
}

func CombineQueryParts(queryParts []string) string {
queryString := ""
if len(queryParts) > 0 {
Expand Down Expand Up @@ -218,5 +246,11 @@ func AutoMigrate(db *gorm.DB) error {
if err := db.AutoMigrate(&RunModel{}); err != nil {
return err
}
if err := db.AutoMigrate(&VariableLabelsModel{}); err != nil {
return err
}
if err := db.AutoMigrate(&VariableModel{}); err != nil {
return err
}
return nil
}
Loading
Loading