Skip to content

Commit fc8dc41

Browse files
committed
feat: add implementation of variable set
1 parent 7dd6763 commit fc8dc41

31 files changed

+4369
-28
lines changed

api/openapispec/docs.go

+983-4
Large diffs are not rendered by default.

api/openapispec/swagger.json

+983-4
Large diffs are not rendered by default.

api/openapispec/swagger.yaml

+645-2
Large diffs are not rendered by default.

pkg/domain/constant/global.go

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
ResourcePageSizeLarge = 1000
2828
CommonPageDefault = 1
2929
CommonPageSizeDefault = 10
30+
CommonMaxResultLimit = 1000
3031
SortByCreateTimestamp = "createTimestamp"
3132
SortByModifiedTimestamp = "modifiedTimestamp"
3233
SortByName = "name"

pkg/domain/constant/variable.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package constant
2+
3+
import "errors"
4+
5+
var (
6+
ErrInvalidVariableName = errors.New("variable name can only have alphanumeric characters and underscores with [a-zA-Z0-9_]")
7+
ErrInvalidVariableType = errors.New("invalid variable type, only PlainText and CipherText supported")
8+
ErrEmptyVariableSet = errors.New("variable set should not be empty")
9+
)

pkg/domain/constant/variable_set.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package constant
2+
3+
import "errors"
4+
5+
var (
6+
ErrInvalidVariableSetName = errors.New("variable set name can only have alphanumeric characters and underscores with [a-zA-Z0-9_]")
7+
ErrEmptyVariableSetLabels = errors.New("variable set labels should not be empty")
8+
)

pkg/domain/entity/variable.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package entity
2+
3+
import "errors"
4+
5+
type VariableType string
6+
7+
const (
8+
PlainTextType VariableType = "PlainText"
9+
CipherTextType VariableType = "CipherText"
10+
)
11+
12+
// Variable represents a specific configuration code variable,
13+
// which usually includes the global configuration for Terraform providers like
14+
// api host, access key and secret key.
15+
type Variable struct {
16+
// Name is the name of the variable.
17+
Name string `yaml:"name,omitempty" json:"name,omitempty"`
18+
// Value is the value of the variable.
19+
Value string `yaml:"value,omitempty" json:"value,omitempty"`
20+
// Type is the text type of the variable.
21+
Type VariableType `yaml:"type,omitempty" json:"type,omitempty"`
22+
// VariableSet is the variable set to which the variable belongs.
23+
VariableSet string `yaml:"variableSet,omitempty" json:"variableSet,omitempty"`
24+
}
25+
26+
// VariableFilter represents the filter conditions to list variables.
27+
type VariableFilter struct {
28+
Name string
29+
VariableSet string
30+
Pagination *Pagination
31+
FetchAll bool
32+
}
33+
34+
// VariableListResult represents the result of listing variables.
35+
type VariableListResult struct {
36+
Variables []*Variable
37+
Total int
38+
}
39+
40+
// Validate checks if the variable is valid.
41+
func (v *Variable) Validate() error {
42+
if v == nil {
43+
return errors.New("variable is nil")
44+
}
45+
46+
if v.Name == "" {
47+
return errors.New("empty variable name")
48+
}
49+
50+
if v.Type != PlainTextType && v.Type != CipherTextType {
51+
return errors.New("invalid variable type")
52+
}
53+
54+
if v.VariableSet == "" {
55+
return errors.New("empty variable set name")
56+
}
57+
58+
return nil
59+
}

pkg/domain/entity/variable_set.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package entity
2+
3+
import "errors"
4+
5+
// VariableSet represents a set of the global configuration variables.
6+
type VariableSet struct {
7+
// Name is the name of the variable set.
8+
Name string `yaml:"name,omitempty" json:"name,omitempty"`
9+
// Labels clarifies the scope of the variable set.
10+
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
11+
}
12+
13+
// VariableSetFilter represents the filter conditions to list variable sets.
14+
type VariableSetFilter struct {
15+
Name string
16+
Pagination *Pagination
17+
FetchAll bool
18+
}
19+
20+
// VariableSetListResult represents the result of listing variable sets.
21+
type VariableSetListResult struct {
22+
VariableSets []*VariableSet
23+
Total int
24+
}
25+
26+
// Validate checks if the variable set is valid.
27+
func (vs *VariableSet) Validate() error {
28+
if vs == nil {
29+
return errors.New("variable set is nil")
30+
}
31+
32+
if vs.Name == "" {
33+
return errors.New("empty variable set name")
34+
}
35+
36+
if len(vs.Labels) == 0 {
37+
return errors.New("empty variable set labels")
38+
}
39+
40+
return nil
41+
}

pkg/domain/repository/repository.go

+30
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,33 @@ type RunRepository interface {
152152
// List retrieves all existing run.
153153
List(ctx context.Context, filter *entity.RunFilter, sortOptions *entity.SortOptions) (*entity.RunListResult, error)
154154
}
155+
156+
// VariableSetRepository is an interface that defines the repository operations
157+
// for variable sets. It follows the principles of domain-driven design (DDD).
158+
type VariableSetRepository interface {
159+
// Create creates a new variable set.
160+
Create(ctx context.Context, vs *entity.VariableSet) error
161+
// Delete deletes a variable set by its name.
162+
Delete(ctx context.Context, name string) error
163+
// Update updates an existing variable set.
164+
Update(ctx context.Context, vs *entity.VariableSet) error
165+
// Get retrieves a variable set by its name.
166+
Get(ctx context.Context, name string) (*entity.VariableSet, error)
167+
// List retrieves existing variable sets with filter and sort options.
168+
List(ctx context.Context, filter *entity.VariableSetFilter, sortOptions *entity.SortOptions) (*entity.VariableSetListResult, error)
169+
}
170+
171+
// VariableRepository is an interface that defines the repository operations
172+
// for variables. It follows the principles of domain-driven design (DDD).
173+
type VariableRepository interface {
174+
// Create creates a new variable.
175+
Create(ctx context.Context, v *entity.Variable) error
176+
// Delete deletes a variable by its name and the variable set it belongs to.
177+
Delete(ctx context.Context, name, variableSet string) error
178+
// Update updates an existing variable.
179+
Update(ctx context.Context, v *entity.Variable) error
180+
// Get retrieves a variable by its name and the variable set it belogs to.
181+
Get(ctx context.Context, name, variableSet string) (*entity.Variable, error)
182+
// List retrieves existing variable with filter and sort options.
183+
List(ctx context.Context, filter *entity.VariableFilter, sortOptions *entity.SortOptions) (*entity.VariableListResult, error)
184+
}

pkg/domain/request/stack_request.go

-18
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"net/http"
55

66
"kusionstack.io/kusion/pkg/domain/constant"
7-
"kusionstack.io/kusion/pkg/domain/entity"
87
)
98

109
// CreateStackRequest represents the create request structure for
@@ -30,19 +29,6 @@ type CreateStackRequest struct {
3029
Owners []string `json:"owners"`
3130
}
3231

33-
type UpdateVariableRequest struct {
34-
// Project is the project related to stack
35-
Project string `json:"project,omitempty"`
36-
// Path is the relative path of the stack within the source.
37-
Path string `json:"path,omitempty"`
38-
IsSecret bool `json:"isSecret,omitempty"`
39-
// key is the unique index to use value in specific stack
40-
Key string `json:"key,omitempty"`
41-
// value is the plain value of no sensitive data
42-
Value string `json:"value,omitempty"`
43-
SecretValue *entity.SecretValue `json:"secretValue,omitempty"`
44-
}
45-
4632
// UpdateStackRequest represents the update request structure for
4733
// stack.
4834
type UpdateStackRequest struct {
@@ -76,10 +62,6 @@ func (payload *UpdateStackRequest) Decode(r *http.Request) error {
7662
return decode(r, payload)
7763
}
7864

79-
func (payload *UpdateVariableRequest) Decode(r *http.Request) error {
80-
return decode(r, payload)
81-
}
82-
8365
func (payload *CreateStackRequest) Validate() error {
8466
if payload.ProjectID == 0 && payload.ProjectName == "" {
8567
return constant.ErrProjectNameOrIDRequired
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package request
2+
3+
import (
4+
"net/http"
5+
6+
"kusionstack.io/kusion/pkg/domain/constant"
7+
"kusionstack.io/kusion/pkg/domain/entity"
8+
)
9+
10+
// CreateVariableRequest represents the create request structure
11+
// for a variable.
12+
type CreateVariableRequest struct {
13+
// Name is the name of the variable.
14+
Name string `json:"name" binding:"required"`
15+
// Value is the value of the variable.
16+
Value string `json:"value"`
17+
// Type is the type of the variable.
18+
Type entity.VariableType `json:"type"`
19+
// VariableSet is the variable set to which the variable belongs.
20+
VariableSet string `json:"variableSet" binding:"required"`
21+
}
22+
23+
// UpdateVariableRequest represents the update request structure
24+
// for a variable.
25+
type UpdateVariableRequest struct {
26+
// Name is the name of the variable.
27+
Name string `json:"name" binding:"required"`
28+
// Value is the value of the variable.
29+
Value string `json:"value"`
30+
// Type is the type of the variable.
31+
Type entity.VariableType `json:"type"`
32+
// VariableSet is the variable set to which the variable belongs.
33+
VariableSet string `json:"variableSet" binding:"required"`
34+
}
35+
36+
func (payload *CreateVariableRequest) Validate() error {
37+
// Validate variable name.
38+
if validName(payload.Name) {
39+
return constant.ErrInvalidVariableName
40+
}
41+
42+
// Validate variable set name. .
43+
if validName(payload.VariableSet) {
44+
return constant.ErrInvalidVariableSetName
45+
}
46+
47+
// Validate variable type.
48+
if payload.Type != "" &&
49+
payload.Type != entity.PlainTextType && payload.Type != entity.CipherTextType {
50+
return constant.ErrInvalidVariableType
51+
}
52+
53+
return nil
54+
}
55+
56+
func (payload *UpdateVariableRequest) Validate() error {
57+
// Validate variable name.
58+
if validName(payload.Name) {
59+
return constant.ErrInvalidVariableName
60+
}
61+
62+
// Validate variable set name. .
63+
if validName(payload.VariableSet) {
64+
return constant.ErrInvalidVariableSetName
65+
}
66+
67+
// Validate variable type.
68+
if payload.Type != "" &&
69+
payload.Type != entity.PlainTextType && payload.Type != entity.CipherTextType {
70+
return constant.ErrInvalidVariableType
71+
}
72+
73+
return nil
74+
}
75+
76+
func (payload *CreateVariableRequest) Decode(r *http.Request) error {
77+
return decode(r, payload)
78+
}
79+
80+
func (payload *UpdateVariableRequest) Decode(r *http.Request) error {
81+
return decode(r, payload)
82+
}
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package request
2+
3+
import (
4+
"net/http"
5+
6+
"kusionstack.io/kusion/pkg/domain/constant"
7+
)
8+
9+
// CreateVariableSetRequest represents the create request structure
10+
// for a variable set.
11+
type CreateVariableSetRequest struct {
12+
// Name is the name of the variable set.
13+
Name string `json:"name" binding:"required"`
14+
// Labels clarifies the scope of the variable set.
15+
Labels map[string]string `json:"labels" binding:"required"`
16+
}
17+
18+
// UpdateVariableSetRequest represents the update request structure
19+
// for a variable set.
20+
type UpdateVariableSetRequest struct {
21+
// Name is the name of the variable set.
22+
Name string `json:"name" binding:"required"`
23+
// Labels clarifies the scope of the variable set.
24+
Labels map[string]string `json:"labels" binding:"required"`
25+
}
26+
27+
func (payload *CreateVariableSetRequest) Validate() error {
28+
// Validate variable set name.
29+
if validName(payload.Name) {
30+
return constant.ErrInvalidVariableSetName
31+
}
32+
33+
if len(payload.Labels) == 0 {
34+
return constant.ErrEmptyVariableSetLabels
35+
}
36+
37+
return nil
38+
}
39+
40+
func (payload *UpdateVariableSetRequest) Validate() error {
41+
// Validate variable set name.
42+
if payload.Name != "" && validName(payload.Name) {
43+
return constant.ErrInvalidVariableSetName
44+
}
45+
46+
if len(payload.Labels) == 0 {
47+
return constant.ErrEmptyVariableSetLabels
48+
}
49+
50+
return nil
51+
}
52+
53+
func (payload *CreateVariableSetRequest) Decode(r *http.Request) error {
54+
return decode(r, payload)
55+
}
56+
57+
func (payload *UpdateVariableSetRequest) Decode(r *http.Request) error {
58+
return decode(r, payload)
59+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedVariableResponse struct {
6+
Variables []*entity.Variable `json:"variable"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedVariableSetResponse struct {
6+
VariableSets []*entity.VariableSet `json:"variableSets"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}
11+
12+
type SelectedVariableSetResponse struct {
13+
VariableSets []*entity.VariableSet `json:"variableSets"`
14+
Total int `json:"total"`
15+
}

pkg/infra/persistence/types.go

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ var (
2626
ErrResourceModelNil = errors.New("resource model can't be nil")
2727
ErrFailedToGetModuleDocRemote = errors.New("failed to parse module doc remote")
2828
ErrRunModelNil = errors.New("run model can't be nil")
29+
ErrVariableSetModelNil = errors.New("variable set model can't be nil")
30+
ErrVariableModelNil = errors.New("variable model can't be nil")
2931
ErrFailedToGetRunType = errors.New("failed to parse run type")
3032
ErrFailedToGetRunStatus = errors.New("failed to parse run status")
3133
)

0 commit comments

Comments
 (0)