mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-19 07:46:51 +00:00
* Feat: Add NotEmpty and NegativePattern constraints to StringParam; implement Closed for MapParam Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: add validation support for array and map parameters - Introduced validators for ArrayParam and MapParam, allowing for cross-field validation within structured parameters. - Added NonEmpty validation for ArrayParam to ensure arrays are not empty. - Implemented ConditionalStructOp for conditional struct generation based on specified conditions. - Created a new Validator type for defining validation rules with optional guard conditions. - Added tests for various validation scenarios, including mutual exclusion and conditional parameters. - Enhanced the CUE generation logic to incorporate new validation features and conditional struct handling. Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: extend fluent API with new scoped field conditions and improve validation checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance ArrayParam with NotEmpty constraint and update ScopedField documentation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: rename ScopedField to LocalField for improved clarity in condition building Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: refactor local field conditions to use RegexMatch and streamline condition building Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: simplify condition handling by removing unused comparison types and refactoring NotCondition usage Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove unused raw CUE block handling from baseDefinition and ComponentDefinition Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * test: update condition handling in parameter tests to use NotExpr and Cond methods Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove negative pattern handling from StringParam and related tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: add support for emitting raw header blocks in template generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove non-empty check from ArrayParam and update related tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: convert parameter constraint tests to use Ginkgo and Gomega for improved readability and maintainability Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: extend fluent APIs for OAM with new CUE generation tests and condition evaluations Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: clean up whitespace in component, cuegen, expr, param, and resource files Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance CUE generation by adding support for new expression types and iterator references Signed-off-by: Ayush Kumar <aykumar@guidewire.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove unnecessary whitespace in cuegen.go Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: rename LenOf to LenOfExpr for clarity in comparison methods Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance CUE generation and validation for string arrays in ArrayParam Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * ci: retrigger checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> --------- Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <aykumar@guidewire.com> Co-authored-by: Ayush Kumar <aykumar@guidewire.com>
299 lines
9.0 KiB
Go
299 lines
9.0 KiB
Go
/*
|
|
Copyright 2025 The KubeVela 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 defkit
|
|
|
|
import (
|
|
"github.com/oam-dev/kubevela/pkg/definition/defkit/placement"
|
|
)
|
|
|
|
// baseDefinition contains fields and methods common to all X-Definition types.
|
|
// This struct is embedded in TraitDefinition, ComponentDefinition, and other
|
|
// definition types to eliminate code duplication and ensure consistent behavior.
|
|
//
|
|
// Common fields include:
|
|
// - name: the definition name (e.g., "scaler", "webservice")
|
|
// - description: human-readable description
|
|
// - params: parameter schema definitions
|
|
// - template: template function for generating output
|
|
// - customStatus: CUE expression for custom status
|
|
// - healthPolicy: CUE expression for health checking
|
|
// - helperDefinitions: helper type definitions like #HealthProbe
|
|
// - rawCUE: escape hatch for complex CUE not expressible via fluent API
|
|
// - imports: CUE imports needed by the definition
|
|
type baseDefinition struct {
|
|
name string
|
|
description string
|
|
params []Param
|
|
template func(tpl *Template)
|
|
customStatus string
|
|
healthPolicy string
|
|
statusDetails string
|
|
annotations map[string]string
|
|
version string
|
|
helperDefinitions []HelperDefinition
|
|
rawCUE string
|
|
imports []string
|
|
// validators holds top-level parameter validators
|
|
validators []*Validator
|
|
// conditionalParamBlocks holds conditional parameter blocks
|
|
conditionalParamBlocks []*ConditionalParamBlock
|
|
// Placement constraints for cluster-aware definition deployment
|
|
runOn []placement.Condition
|
|
notRunOn []placement.Condition
|
|
}
|
|
|
|
// --- Builder methods (used by embedding types) ---
|
|
|
|
// setDescription sets the definition description.
|
|
func (b *baseDefinition) setDescription(desc string) {
|
|
b.description = desc
|
|
}
|
|
|
|
// addParams adds parameter definitions.
|
|
func (b *baseDefinition) addParams(params ...Param) {
|
|
b.params = append(b.params, params...)
|
|
}
|
|
|
|
// addValidators appends validators to the definition.
|
|
func (b *baseDefinition) addValidators(validators ...*Validator) {
|
|
b.validators = append(b.validators, validators...)
|
|
}
|
|
|
|
// GetValidators returns the top-level validators.
|
|
func (b *baseDefinition) GetValidators() []*Validator {
|
|
return b.validators
|
|
}
|
|
|
|
// addConditionalParamBlock appends a conditional parameter block.
|
|
func (b *baseDefinition) addConditionalParamBlock(block *ConditionalParamBlock) {
|
|
b.conditionalParamBlocks = append(b.conditionalParamBlocks, block)
|
|
}
|
|
|
|
// GetConditionalParamBlocks returns the conditional parameter blocks.
|
|
func (b *baseDefinition) GetConditionalParamBlocks() []*ConditionalParamBlock {
|
|
return b.conditionalParamBlocks
|
|
}
|
|
|
|
// setTemplate sets the template function.
|
|
func (b *baseDefinition) setTemplate(fn func(tpl *Template)) {
|
|
b.template = fn
|
|
}
|
|
|
|
// setCustomStatus sets the custom status CUE expression.
|
|
func (b *baseDefinition) setCustomStatus(expr string) {
|
|
b.customStatus = expr
|
|
}
|
|
|
|
// setHealthPolicy sets the health policy CUE expression.
|
|
func (b *baseDefinition) setHealthPolicy(expr string) {
|
|
b.healthPolicy = expr
|
|
}
|
|
|
|
// setHealthPolicyExpr sets the health policy using a composable HealthExpression.
|
|
func (b *baseDefinition) setHealthPolicyExpr(expr HealthExpression) {
|
|
b.healthPolicy = HealthPolicy(expr)
|
|
}
|
|
|
|
// setStatusDetails sets the status details CUE expression.
|
|
func (b *baseDefinition) setStatusDetails(details string) {
|
|
b.statusDetails = details
|
|
}
|
|
|
|
// setAnnotations sets the annotations map.
|
|
func (b *baseDefinition) setAnnotations(annotations map[string]string) {
|
|
b.annotations = annotations
|
|
}
|
|
|
|
// setVersion sets the version string.
|
|
func (b *baseDefinition) setVersion(v string) {
|
|
b.version = v
|
|
}
|
|
|
|
// addHelper adds a helper type definition using fluent API.
|
|
func (b *baseDefinition) addHelper(name string, param Param) {
|
|
b.helperDefinitions = append(b.helperDefinitions, HelperDefinition{name: name, param: param})
|
|
}
|
|
|
|
// setRawCUE sets raw CUE for complex definitions.
|
|
func (b *baseDefinition) setRawCUE(cue string) {
|
|
b.rawCUE = cue
|
|
}
|
|
|
|
// addImports adds CUE imports.
|
|
func (b *baseDefinition) addImports(imports ...string) {
|
|
b.imports = append(b.imports, imports...)
|
|
}
|
|
|
|
// addRunOn adds placement conditions specifying where this definition should run.
|
|
func (b *baseDefinition) addRunOn(conditions ...placement.Condition) {
|
|
b.runOn = append(b.runOn, conditions...)
|
|
}
|
|
|
|
// addNotRunOn adds placement conditions specifying where this definition should NOT run.
|
|
func (b *baseDefinition) addNotRunOn(conditions ...placement.Condition) {
|
|
b.notRunOn = append(b.notRunOn, conditions...)
|
|
}
|
|
|
|
// --- Getter methods (shared by all definition types) ---
|
|
|
|
// GetName returns the definition name.
|
|
func (b *baseDefinition) GetName() string {
|
|
return b.name
|
|
}
|
|
|
|
// GetDescription returns the definition description.
|
|
func (b *baseDefinition) GetDescription() string {
|
|
return b.description
|
|
}
|
|
|
|
// GetParams returns all parameter definitions.
|
|
func (b *baseDefinition) GetParams() []Param {
|
|
return b.params
|
|
}
|
|
|
|
// GetTemplate returns the template function.
|
|
func (b *baseDefinition) GetTemplate() func(tpl *Template) {
|
|
return b.template
|
|
}
|
|
|
|
// GetCustomStatus returns the custom status CUE expression.
|
|
func (b *baseDefinition) GetCustomStatus() string {
|
|
return b.customStatus
|
|
}
|
|
|
|
// GetHealthPolicy returns the health policy CUE expression.
|
|
func (b *baseDefinition) GetHealthPolicy() string {
|
|
return b.healthPolicy
|
|
}
|
|
|
|
// GetStatusDetails returns the status details CUE expression.
|
|
func (b *baseDefinition) GetStatusDetails() string {
|
|
return b.statusDetails
|
|
}
|
|
|
|
// GetAnnotations returns the annotations map.
|
|
func (b *baseDefinition) GetAnnotations() map[string]string {
|
|
return b.annotations
|
|
}
|
|
|
|
// GetVersion returns the version string.
|
|
func (b *baseDefinition) GetVersion() string {
|
|
return b.version
|
|
}
|
|
|
|
// GetHelperDefinitions returns all helper type definitions.
|
|
func (b *baseDefinition) GetHelperDefinitions() []HelperDefinition {
|
|
return b.helperDefinitions
|
|
}
|
|
|
|
// GetRawCUE returns the raw CUE template if set.
|
|
func (b *baseDefinition) GetRawCUE() string {
|
|
return b.rawCUE
|
|
}
|
|
|
|
// GetImports returns the CUE imports.
|
|
func (b *baseDefinition) GetImports() []string {
|
|
return b.imports
|
|
}
|
|
|
|
// HasTemplate returns true if the definition has a template function set.
|
|
func (b *baseDefinition) HasTemplate() bool {
|
|
return b.template != nil
|
|
}
|
|
|
|
// HasRawCUE returns true if raw CUE is set.
|
|
func (b *baseDefinition) HasRawCUE() bool {
|
|
return b.rawCUE != ""
|
|
}
|
|
|
|
// GetRunOn returns the RunOn placement conditions.
|
|
func (b *baseDefinition) GetRunOn() []placement.Condition {
|
|
return b.runOn
|
|
}
|
|
|
|
// GetNotRunOn returns the NotRunOn placement conditions.
|
|
func (b *baseDefinition) GetNotRunOn() []placement.Condition {
|
|
return b.notRunOn
|
|
}
|
|
|
|
// GetPlacement returns the complete placement spec for this definition.
|
|
func (b *baseDefinition) GetPlacement() placement.PlacementSpec {
|
|
return placement.PlacementSpec{
|
|
RunOn: b.runOn,
|
|
NotRunOn: b.notRunOn,
|
|
}
|
|
}
|
|
|
|
// HasPlacement returns true if the definition has any placement constraints.
|
|
func (b *baseDefinition) HasPlacement() bool {
|
|
return len(b.runOn) > 0 || len(b.notRunOn) > 0
|
|
}
|
|
|
|
// GetRawCUEWithName returns the raw CUE with the definition name rewritten
|
|
// to match the name set via NewComponent/NewTrait/etc.
|
|
// This ensures the name passed to the fluent builder takes precedence over
|
|
// any name embedded in the raw CUE string.
|
|
func (b *baseDefinition) GetRawCUEWithName() string {
|
|
return RewriteRawCUEName(b.rawCUE, b.name)
|
|
}
|
|
|
|
// RewriteRawCUEName rewrites the first definition name in a raw CUE string
|
|
// to use the specified name. This handles patterns like:
|
|
// - "old-name": { ... } -> "new-name": { ... }
|
|
// - "old-name.v1": { ... } -> "new-name": { ... }
|
|
//
|
|
// The function finds the first quoted string followed by a colon and replaces it.
|
|
func RewriteRawCUEName(rawCUE, newName string) string {
|
|
if rawCUE == "" || newName == "" {
|
|
return rawCUE
|
|
}
|
|
|
|
// Find the first quoted definition name pattern: "name": {
|
|
// We look for: optional whitespace, quote, name, quote, colon
|
|
inQuote := false
|
|
quoteStart := -1
|
|
|
|
for i, c := range rawCUE {
|
|
if c == '"' {
|
|
if !inQuote {
|
|
inQuote = true
|
|
quoteStart = i
|
|
} else {
|
|
quoteEnd := i
|
|
// Check if followed by colon (with optional whitespace)
|
|
rest := rawCUE[quoteEnd+1:]
|
|
for j, r := range rest {
|
|
if r == ' ' || r == '\t' || r == '\n' || r == '\r' {
|
|
continue
|
|
}
|
|
if r == ':' {
|
|
// Found the definition name pattern - replace it
|
|
return rawCUE[:quoteStart+1] + newName + rawCUE[quoteEnd:]
|
|
}
|
|
// Not followed by colon, keep looking
|
|
_ = j
|
|
break
|
|
}
|
|
inQuote = false
|
|
quoteStart = -1
|
|
}
|
|
}
|
|
}
|
|
|
|
return rawCUE
|
|
}
|