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
979 changes: 979 additions & 0 deletions api/openapispec/docs.go

Large diffs are not rendered by default.

979 changes: 979 additions & 0 deletions api/openapispec/swagger.json

Large diffs are not rendered by default.

643 changes: 643 additions & 0 deletions api/openapispec/swagger.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pkg/domain/constant/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
ResourcePageSizeLarge = 1000
CommonPageDefault = 1
CommonPageSizeDefault = 10
CommonMaxResultLimit = 10000
SortByCreateTimestamp = "createTimestamp"
SortByModifiedTimestamp = "modifiedTimestamp"
SortByName = "name"
Expand Down
9 changes: 9 additions & 0 deletions pkg/domain/constant/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package constant

import "errors"

var (
ErrInvalidVariableName = errors.New("variable name can only have alphanumeric characters and underscores with [a-zA-Z0-9_]")
ErrInvalidVariableType = errors.New("invalid variable type, only PlainText and CipherText supported")
ErrEmptyVariableSet = errors.New("variable set should not be empty")
)
8 changes: 8 additions & 0 deletions pkg/domain/constant/variable_set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package constant

import "errors"

var (
ErrInvalidVariableSetName = errors.New("variable set name can only have alphanumeric characters and underscores with [a-zA-Z0-9_]")
ErrEmptyVariableSetLabels = errors.New("variable set labels should not be empty")
)
5 changes: 3 additions & 2 deletions pkg/domain/entity/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type Pagination struct {
}

type SortOptions struct {
Field string
Ascending bool
Field string
Ascending bool
Descending bool
}
59 changes: 59 additions & 0 deletions pkg/domain/entity/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package entity

import "errors"

type VariableType string

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

// Variable represents a specific configuration code variable,
// which usually includes the global configuration for Terraform providers like
// api host, access key and secret key.
type Variable struct {
// Name is the name of the variable.
Name string `yaml:"name,omitempty" json:"name,omitempty"`
// Value is the value of the variable.
Value string `yaml:"value,omitempty" json:"value,omitempty"`
// Type is the text type of the variable.
Type VariableType `yaml:"type,omitempty" json:"type,omitempty"`
// VariableSet is the variable set to which the variable belongs.
VariableSet string `yaml:"variableSet,omitempty" json:"variableSet,omitempty"`
}

// VariableFilter represents the filter conditions to list variables.
type VariableFilter struct {
Name string
VariableSet string
Pagination *Pagination
FetchAll bool
}

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

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

if v.Name == "" {
return errors.New("empty variable name")
}

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

if v.VariableSet == "" {
return errors.New("empty variable set name")
}

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

import "errors"

// VariableSet represents a set of the global configuration variables.
type VariableSet struct {
// Name is the name of the variable set.
Name string `yaml:"name,omitempty" json:"name,omitempty"`
// Labels clarifies the scope of the variable set.
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
}

// VariableSetFilter represents the filter conditions to list variable sets.
type VariableSetFilter struct {
Name string
Pagination *Pagination
FetchAll bool
}

// VariableSetListResult represents the result of listing variable sets.
type VariableSetListResult struct {
VariableSets []*VariableSet
Total int
}

// Validate checks if the variable set is valid.
func (vs *VariableSet) Validate() error {
if vs == nil {
return errors.New("variable set is nil")
}

if vs.Name == "" {
return errors.New("empty variable set name")
}

if len(vs.Labels) == 0 {
return errors.New("empty variable set 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, sortOptions *entity.SortOptions) (*entity.RunListResult, error)
}

// VariableSetRepository is an interface that defines the repository operations
// for variable sets. It follows the principles of domain-driven design (DDD).
type VariableSetRepository interface {
// Create creates a new variable set.
Create(ctx context.Context, vs *entity.VariableSet) error
// Delete deletes a variable set by its name.
Delete(ctx context.Context, name string) error
// Update updates an existing variable set.
Update(ctx context.Context, vs *entity.VariableSet) error
// Get retrieves a variable set by its name.
Get(ctx context.Context, name string) (*entity.VariableSet, error)
// List retrieves existing variable sets with filter and sort options.
List(ctx context.Context, filter *entity.VariableSetFilter, sortOptions *entity.SortOptions) (*entity.VariableSetListResult, 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 name and the variable set it belongs to.
Delete(ctx context.Context, name, variableSet string) error
// Update updates an existing variable.
Update(ctx context.Context, v *entity.Variable) error
// Get retrieves a variable by its name and the variable set it belogs to.
Get(ctx context.Context, name, variableSet string) (*entity.Variable, error)
// List retrieves existing variable with filter and sort options.
List(ctx context.Context, filter *entity.VariableFilter, sortOptions *entity.SortOptions) (*entity.VariableListResult, error)
}
18 changes: 0 additions & 18 deletions pkg/domain/request/stack_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"net/http"

"kusionstack.io/kusion/pkg/domain/constant"
"kusionstack.io/kusion/pkg/domain/entity"
)

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

type UpdateVariableRequest struct {
// Project is the project related to stack
Project string `json:"project,omitempty"`
// Path is the relative path of the stack within the source.
Path string `json:"path,omitempty"`
IsSecret bool `json:"isSecret,omitempty"`
// key is the unique index to use value in specific stack
Key string `json:"key,omitempty"`
// value is the plain value of no sensitive data
Value string `json:"value,omitempty"`
SecretValue *entity.SecretValue `json:"secretValue,omitempty"`
}

// UpdateStackRequest represents the update request structure for
// stack.
type UpdateStackRequest struct {
Expand Down Expand Up @@ -76,10 +62,6 @@ func (payload *UpdateStackRequest) Decode(r *http.Request) error {
return decode(r, payload)
}

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

func (payload *CreateStackRequest) Validate() error {
if payload.ProjectID == 0 && payload.ProjectName == "" {
return constant.ErrProjectNameOrIDRequired
Expand Down
82 changes: 82 additions & 0 deletions pkg/domain/request/variable_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package request

import (
"net/http"

"kusionstack.io/kusion/pkg/domain/constant"
"kusionstack.io/kusion/pkg/domain/entity"
)

// CreateVariableRequest represents the create request structure
// for a variable.
type CreateVariableRequest struct {
// Name is the name of the variable.
Name string `json:"name" binding:"required"`
// Value is the value of the variable.
Value string `json:"value"`
// Type is the type of the variable.
Type entity.VariableType `json:"type"`
// VariableSet is the variable set to which the variable belongs.
VariableSet string `json:"variableSet" binding:"required"`
}

// UpdateVariableRequest represents the update request structure
// for a variable.
type UpdateVariableRequest struct {
// Name is the name of the variable.
Name string `json:"name" binding:"required"`
// Value is the value of the variable.
Value string `json:"value"`
// Type is the type of the variable.
Type entity.VariableType `json:"type"`
// VariableSet is the variable set to which the variable belongs.
VariableSet string `json:"variableSet" binding:"required"`
}

func (payload *CreateVariableRequest) Validate() error {
// Validate variable name.
if validName(payload.Name) {
return constant.ErrInvalidVariableName
}

// Validate variable set name. .
if validName(payload.VariableSet) {
return constant.ErrInvalidVariableSetName
}

// Validate variable type.
if payload.Type != "" &&
payload.Type != entity.PlainTextType && payload.Type != entity.CipherTextType {
return constant.ErrInvalidVariableType
}

return nil
}

func (payload *UpdateVariableRequest) Validate() error {
// Validate variable name.
if validName(payload.Name) {
return constant.ErrInvalidVariableName
}

// Validate variable set name. .
if validName(payload.VariableSet) {
return constant.ErrInvalidVariableSetName
}

// Validate variable type.
if payload.Type != "" &&
payload.Type != entity.PlainTextType && payload.Type != entity.CipherTextType {
return constant.ErrInvalidVariableType
}

return nil
}

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

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

import (
"net/http"

"kusionstack.io/kusion/pkg/domain/constant"
)

// CreateVariableSetRequest represents the create request structure
// for a variable set.
type CreateVariableSetRequest struct {
// Name is the name of the variable set.
Name string `json:"name" binding:"required"`
// Labels clarifies the scope of the variable set.
Labels map[string]string `json:"labels" binding:"required"`
}

// UpdateVariableSetRequest represents the update request structure
// for a variable set.
type UpdateVariableSetRequest struct {
// Name is the name of the variable set.
Name string `json:"name" binding:"required"`
// Labels clarifies the scope of the variable set.
Labels map[string]string `json:"labels" binding:"required"`
}

func (payload *CreateVariableSetRequest) Validate() error {
// Validate variable set name.
if validName(payload.Name) {
return constant.ErrInvalidVariableSetName
}

if len(payload.Labels) == 0 {
return constant.ErrEmptyVariableSetLabels
}

return nil
}

func (payload *UpdateVariableSetRequest) Validate() error {
// Validate variable set name.
if payload.Name != "" && validName(payload.Name) {
return constant.ErrInvalidVariableSetName
}

if len(payload.Labels) == 0 {
return constant.ErrEmptyVariableSetLabels
}

return nil
}

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

func (payload *UpdateVariableSetRequest) Decode(r *http.Request) error {
return decode(r, payload)
}
10 changes: 10 additions & 0 deletions pkg/domain/response/variable_response.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:"variable"`
Total int `json:"total"`
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
}
15 changes: 15 additions & 0 deletions pkg/domain/response/variable_set_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package response

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

type PaginatedVariableSetResponse struct {
VariableSets []*entity.VariableSet `json:"variableSets"`
Total int `json:"total"`
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
}

type SelectedVariableSetResponse struct {
VariableSets []*entity.VariableSet `json:"variableSets"`
Total int `json:"total"`
}
2 changes: 2 additions & 0 deletions pkg/infra/persistence/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ var (
ErrResourceModelNil = errors.New("resource model can't be nil")
ErrFailedToGetModuleDocRemote = errors.New("failed to parse module doc remote")
ErrRunModelNil = errors.New("run model can't be nil")
ErrVariableSetModelNil = errors.New("variable set model can't be nil")
ErrVariableModelNil = errors.New("variable model can't be nil")
ErrFailedToGetRunType = errors.New("failed to parse run type")
ErrFailedToGetRunStatus = errors.New("failed to parse run status")
)
Loading
Loading