diff --git a/.github/workflows/sdk-test.yml b/.github/workflows/sdk-test.yml new file mode 100644 index 000000000..a1529f0da --- /dev/null +++ b/.github/workflows/sdk-test.yml @@ -0,0 +1,49 @@ +name: SDK Test + +on: + push: + tags: + - v* + workflow_dispatch: {} + pull_request: + paths: + - "vela-templates/definitions/**" + - "pkg/definition/gen_sdk/**" + branches: + - master + - release-* + +permissions: + contents: read + +env: + # Common versions + GO_VERSION: '1.19' + +jobs: + sdk-tests: + runs-on: ubuntu-20.04 + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c + + - name: Setup Go + uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Build CLI + run: make vela-cli + + - name: Build SDK + run: bin/vela def gen-api -f vela-templates/definitions/internal/ -o ./kubevela-go-sdk --package=github.com/kubevela-contrib/kubevela-go-sdk + + - name: Validate SDK + uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # v3.4.0 + working-directory: ./kubevela-go-sdk + with: + args: --timeout 5m diff --git a/pkg/definition/gen_sdk/_scaffold/go/go.mod_ b/pkg/definition/gen_sdk/_scaffold/go/go.mod_ index ba95726a4..99468113b 100644 --- a/pkg/definition/gen_sdk/_scaffold/go/go.mod_ +++ b/pkg/definition/gen_sdk/_scaffold/go/go.mod_ @@ -8,6 +8,7 @@ require ( k8s.io/apimachinery v0.23.6 k8s.io/client-go v0.23.6 sigs.k8s.io/controller-runtime v0.11.2 + sigs.k8s.io/yaml v1.3.0 ) require ( @@ -108,7 +109,6 @@ require ( sigs.k8s.io/apiserver-runtime v1.1.1 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( diff --git a/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/common/application.go b/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/common/application.go index c6d0478c6..204714dd4 100644 --- a/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/common/application.go +++ b/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/common/application.go @@ -17,10 +17,9 @@ limitations under the License. package common import ( - "encoding/json" - "github.com/pkg/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" . "github.com/kubevela/vela-go-sdk/pkg/apis" @@ -41,36 +40,55 @@ type ApplicationBuilder struct { workflowMode v1beta1.WorkflowExecuteMode } -// AddComponent set component to application, use component name to match -// TODO: behavior when component not found? -// 1. return error -// 2. ignore -// 3. add a new one to application -func (a *ApplicationBuilder) AddComponent(component Component) TypedApplication { - for i, c := range a.components { - if c.ComponentName() == component.ComponentName() { - a.components[i] = component - return a +// SetComponents set components to application, use component name to match, if component name not found, append it +func (a *ApplicationBuilder) SetComponents(components ...Component) TypedApplication { + for _, addComp := range components { + found := false + for i, c := range a.components { + if c.ComponentName() == addComp.ComponentName() { + a.components[i] = addComp + found = true + break + } + } + if !found { + a.components = append(a.components, addComp) } } return a } -func (a *ApplicationBuilder) AddWorkflowStep(step WorkflowStep) TypedApplication { - for i, s := range a.steps { - if s.WorkflowStepName() == step.WorkflowStepName() { - a.steps[i] = step - return a +// SetWorkflowSteps set workflow steps to application, use step name to match, if step name not found, append it +func (a *ApplicationBuilder) SetWorkflowSteps(steps ...WorkflowStep) TypedApplication { + for _, addStep := range steps { + found := false + for i, s := range a.steps { + if s.WorkflowStepName() == addStep.WorkflowStepName() { + a.steps[i] = addStep + found = true + break + } + } + if !found { + a.steps = append(a.steps, addStep) } } return a } -func (a *ApplicationBuilder) AddPolicy(policy Policy) TypedApplication { - for i, p := range a.policies { - if p.PolicyName() == policy.PolicyName() { - a.policies[i] = policy - return a +// SetPolicies set policies to application, use policy name to match, if policy name not found, append it +func (a *ApplicationBuilder) SetPolicies(policies ...Policy) TypedApplication { + for _, addPolicy := range policies { + found := false + for i, p := range a.policies { + if p.PolicyName() == addPolicy.PolicyName() { + a.policies[i] = addPolicy + found = true + break + } + } + if !found { + a.policies = append(a.policies, addPolicy) } } return a @@ -133,25 +151,8 @@ func (a *ApplicationBuilder) GetPoliciesByType(typ string) []Policy { return result } -func (a *ApplicationBuilder) WithWorkflowSteps(step ...WorkflowStep) TypedApplication { - a.steps = append(a.steps, step...) - return a -} - -// WithComponents append components to application -func (a *ApplicationBuilder) WithComponents(component ...Component) TypedApplication { - a.components = append(a.components, component...) - return a -} - -// WithPolicies append policies to application -func (a *ApplicationBuilder) WithPolicies(policy ...Policy) TypedApplication { - a.policies = append(a.policies, policy...) - return a -} - -// WithWorkflowMode set the workflow mode of application -func (a *ApplicationBuilder) WithWorkflowMode(steps, subSteps common.WorkflowMode) TypedApplication { +// SetWorkflowMode set the workflow mode of application +func (a *ApplicationBuilder) SetWorkflowMode(steps, subSteps common.WorkflowMode) TypedApplication { a.workflowMode.Steps = steps a.workflowMode.SubSteps = subSteps return a @@ -240,13 +241,40 @@ func (a *ApplicationBuilder) Build() v1beta1.Application { func (a *ApplicationBuilder) ToYAML() (string, error) { app := a.Build() - marshal, err := json.Marshal(app) + marshal, err := yaml.Marshal(app) if err != nil { return "", err } return string(marshal), nil } +// Validate validates the application name/namespace/component/step/policy. +// For component/step/policy, it will validate if the required fields are set. +func (a *ApplicationBuilder) Validate() error { + if a.name == "" { + return errors.New("name is required") + } + if a.namespace == "" { + return errors.New("namespace is required") + } + for _, c := range a.components { + if err := c.Validate(); err != nil { + return err + } + } + for _, s := range a.steps { + if err := s.Validate(); err != nil { + return err + } + } + for _, p := range a.policies { + if err := p.Validate(); err != nil { + return err + } + } + return nil +} + func FromK8sObject(app *v1beta1.Application) (TypedApplication, error) { a := &ApplicationBuilder{} a.Name(app.Name) @@ -258,7 +286,7 @@ func FromK8sObject(app *v1beta1.Application) (TypedApplication, error) { if err != nil { return nil, errors.Wrap(err, "convert component from k8s object") } - a.WithComponents(c) + a.SetComponents(c) } if app.Spec.Workflow != nil { for _, step := range app.Spec.Workflow.Steps { @@ -266,7 +294,7 @@ func FromK8sObject(app *v1beta1.Application) (TypedApplication, error) { if err != nil { return nil, errors.Wrap(err, "convert workflow step from k8s object") } - a.WithWorkflowSteps(s) + a.SetWorkflowSteps(s) } } for _, policy := range app.Spec.Policies { @@ -274,7 +302,7 @@ func FromK8sObject(app *v1beta1.Application) (TypedApplication, error) { if err != nil { return nil, errors.Wrap(err, "convert policy from k8s object") } - a.WithPolicies(p) + a.SetPolicies(p) } return a, nil } diff --git a/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/types.go b/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/types.go index 16db8c95b..ebd2aa1fa 100644 --- a/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/types.go +++ b/pkg/definition/gen_sdk/_scaffold/go/pkg/apis/types.go @@ -27,16 +27,11 @@ type TypedApplication interface { Labels(labels map[string]string) TypedApplication Annotations(annotations map[string]string) TypedApplication - WithComponents(component ...Component) TypedApplication - WithWorkflowSteps(step ...WorkflowStep) TypedApplication - WithPolicies(policy ...Policy) TypedApplication - WithWorkflowMode(steps, subSteps common.WorkflowMode) TypedApplication + SetWorkflowMode(steps, subSteps common.WorkflowMode) TypedApplication + SetComponents(components ...Component) TypedApplication + SetWorkflowSteps(steps ...WorkflowStep) TypedApplication + SetPolicies(policies ...Policy) TypedApplication - AddComponent(component Component) TypedApplication - AddWorkflowStep(step WorkflowStep) TypedApplication - AddPolicy(policy Policy) TypedApplication - - GetName() string GetNamespace() string GetLabels() map[string]string GetAnnotations() map[string]string @@ -49,6 +44,7 @@ type TypedApplication interface { Build() v1beta1.Application ToYAML() (string, error) + Validate() error } type Component interface { @@ -56,23 +52,28 @@ type Component interface { DefType() string Build() common.ApplicationComponent GetTrait(typ string) Trait + GetAllTraits() []Trait + Validate() error } type Trait interface { DefType() string Build() common.ApplicationTrait + Validate() error } type WorkflowStep interface { WorkflowStepName() string DefType() string Build() v1beta1.WorkflowStep + Validate() error } type Policy interface { PolicyName() string DefType() string Build() v1beta1.AppPolicy + Validate() error } type ComponentBase struct { diff --git a/pkg/definition/gen_sdk/gen_sdk.go b/pkg/definition/gen_sdk/gen_sdk.go index 4a43d3f2c..ad0341afe 100644 --- a/pkg/definition/gen_sdk/gen_sdk.go +++ b/pkg/definition/gen_sdk/gen_sdk.go @@ -84,7 +84,7 @@ type Modifier interface { func (meta *GenMeta) Init(c common.Args) (err error) { meta.config, err = c.GetConfig() if err != nil { - return err + klog.Info("No kubeconfig found, skipping") } err = stdlib.SetupBuiltinImports() if err != nil { @@ -148,9 +148,6 @@ func (meta *GenMeta) CreateScaffold() error { } return nil } - if d.Name() == "keep" { - return nil - } fileContent, err := Scaffold.ReadFile(_path) if err != nil { return err @@ -226,7 +223,10 @@ func (meta *GenMeta) PrepareGeneratorAndTemplate() error { } meta.templatePath = langDir } else { - meta.templatePath = meta.Template + meta.templatePath, err = filepath.Abs(meta.Template) + if err != nil { + return errors.Wrap(err, "failed to get absolute path of template") + } } return nil } @@ -335,9 +335,11 @@ func (g *Generator) completeOpenAPISchema(doc *openapi3.T) { spec := g.name + "-spec" schema.Value.Title = spec completeFreeFormSchema(schema) - completeSchemas(schema.Value.Properties) + completeSchema(key, schema) doc.Components.Schemas[spec] = schema delete(doc.Components.Schemas, key) + case g.name + "-spec": + continue default: completeSchema(key, schema) } @@ -361,6 +363,10 @@ func (g *Generator) GenerateCode() (err error) { if err != nil { return errors.Wrapf(err, "get absolute path of %s", apiDir) } + err = os.MkdirAll(path.Join(apiDir, definition.DefinitionKindToType[g.kind]), 0750) + if err != nil { + return errors.Wrapf(err, "create directory %s", apiDir) + } // nolint:gosec cmd := exec.Command("docker", "run", @@ -467,7 +473,7 @@ func completeSchema(key string, schema *openapi3.SchemaRef) { // allow all the fields to be empty to avoid this case: // A field is initialized with empty value and marshalled to JSON with empty value (e.g. empty string) // However, the empty value is not allowed on the server side when it is conflict with the default value in CUE. - schema.Value.Required = []string{} + // schema.Value.Required = []string{} switch schema.Value.Type { case "object": diff --git a/pkg/definition/gen_sdk/go.go b/pkg/definition/gen_sdk/go.go index 10adef53e..ed2e441f8 100644 --- a/pkg/definition/gen_sdk/go.go +++ b/pkg/definition/gen_sdk/go.go @@ -93,6 +93,7 @@ func (m *GoModifier) Modify() error { m.moveUtils, m.modifyDefs, m.addDefAPI, + m.addValidateTraits, m.exportMethods, m.format, } { @@ -193,6 +194,7 @@ func (m *GoModifier) moveUtils() error { return err } utilsBytes = bytes.Replace(utilsBytes, []byte(fmt.Sprintf("package %s", strcase.ToSnake(m.defName))), []byte("package utils"), 1) + utilsBytes = bytes.ReplaceAll(utilsBytes, []byte("isNil"), []byte("IsNil")) err = os.WriteFile(utilsFile, utilsBytes, 0600) if err != nil { return err @@ -433,30 +435,50 @@ func (m *GoModifier) genFromFunc() []*j.Statement { func (m *GoModifier) genDedicatedFunc() []*j.Statement { switch m.defKind { case v1beta1.ComponentDefinitionKind: - addTraitFunc := j.Func(). + setTraitFunc := j.Func(). Params(j.Id(m.defFuncReceiver).Add(m.defStructPointer)). - Id("AddTrait"). + Id("SetTraits"). Params(j.Id("traits").Op("...").Qual("apis", "Trait")). Add(m.defStructPointer). Block( - j.Id(m.defFuncReceiver).Dot("Base").Dot("Traits").Op("=").Append(j.Id(m.defFuncReceiver).Dot("Base").Dot("Traits"), j.Id("traits").Op("...")), + j.For(j.List(j.Id("_"), j.Id("addTrait")).Op(":=").Range().Id("traits")).Block( + j.Id("found").Op(":=").False(), + j.For(j.List(j.Id("i"), j.Id("_t")).Op(":=").Range().Id(m.defFuncReceiver).Dot("Base").Dot("Traits")).Block( + j.If(j.Id("_t").Dot("DefType").Call().Op("==").Id("addTrait").Dot("DefType").Call()).Block( + j.Id(m.defFuncReceiver).Dot("Base").Dot("Traits").Index(j.Id("i")).Op("=").Id("addTrait"), + j.Id("found").Op("=").True(), + j.Break(), + ), + j.If(j.Op("!").Id("found")).Block( + j.Id(m.defFuncReceiver).Dot("Base").Dot("Traits").Op("=").Append(j.Id(m.defFuncReceiver).Dot("Base").Dot("Traits"), j.Id("addTrait")), + ), + ), + ), j.Return(j.Id(m.defFuncReceiver)), ) getTraitFunc := j.Func(). Params(j.Id(m.defFuncReceiver).Add(m.defStructPointer)). Id("GetTrait"). - Params(j.Id("_type").String()). + Params(j.Id("typ").String()). Params(j.Qual("apis", "Trait")). Block( j.For(j.List(j.Id("_"), j.Id("_t")).Op(":=").Range().Id(m.defFuncReceiver).Dot("Base").Dot("Traits")).Block( - j.If(j.Id("_t").Dot("DefType").Call().Op("==").Id("_type")).Block( + j.If(j.Id("_t").Dot("DefType").Call().Op("==").Id("typ")).Block( j.Return(j.Id("_t")), ), ), j.Return(j.Nil()), ) + getAllTraitFunc := j.Func(). + Params(j.Id(m.defFuncReceiver).Add(m.defStructPointer)). + Id("GetAllTraits"). + Params(). + Params(j.Index().Qual("apis", "Trait")). + Block( + j.Return(j.Id(m.defFuncReceiver).Dot("Base").Dot("Traits")), + ) - return []*j.Statement{addTraitFunc, getTraitFunc} + return []*j.Statement{setTraitFunc, getTraitFunc, getAllTraitFunc} case v1beta1.WorkflowStepDefinitionKind: } return nil @@ -569,18 +591,47 @@ func (m *GoModifier) exportMethods() error { // replace all function receiver in function body // o.foo -> o.Properties.foo + // o.Base keeps the same // seek the MarshalJSON function, replace functions before it - from = "o." - to = "o.Properties." parts := strings.SplitN(fileStr, "MarshalJSON", 2) if len(parts) != 2 { return fmt.Errorf("can't find MarshalJSON function") } - fileStr = strings.ReplaceAll(parts[0], from, to) + "MarshalJSON" + parts[1] + parts[0] = strings.ReplaceAll(parts[0], "o.", "o.Properties.") + parts[0] = strings.ReplaceAll(parts[0], "o.Properties.Base", "o.Base") + fileStr = parts[0] + "MarshalJSON" + parts[1] return os.WriteFile(fileLoc, []byte(fileStr), 0600) } +func (m *GoModifier) addValidateTraits() error { + if m.defKind != v1beta1.ComponentDefinitionKind { + return nil + } + fileLoc := path.Join(m.defDir, m.nameInSnakeCase+".go") + // nolint:gosec + file, err := os.ReadFile(fileLoc) + if err != nil { + return err + } + var fileStr = string(file) + buf := bytes.Buffer{} + + err = j.For(j.List(j.Id("i"), j.Id("v").Op(":=").Range().Id("o").Dot("Base").Dot("Traits"))).Block( + j.If(j.Id("err").Op(":=").Id("v").Dot("Validate").Call().Op(";").Id("err").Op("!=").Nil()).Block( + j.Return(j.Qual("fmt", "Errorf").Call(j.Lit("traits[%d] %s in %s component is invalid: %w"), j.Id("i"), j.Id("v").Dot("DefType").Call(), j.Id(m.typeVarName), j.Id("err"))), + ), + ).Render(&buf) + if err != nil { + return err + } + // add validate trait part in Validate function + exp := regexp.MustCompile(`Validate\(\)((.|\n)*?)(return nil)`) + s := buf.String() + fileStr = exp.ReplaceAllString(fileStr, fmt.Sprintf("Validate()$1\n%s\n$3", s)) + + return os.WriteFile(fileLoc, []byte(fileStr), 0600) +} func (m *GoModifier) format() error { // check if gofmt is installed diff --git a/pkg/definition/gen_sdk/openapi-generator/templates/go/model.mustache b/pkg/definition/gen_sdk/openapi-generator/templates/go/model.mustache index a7a6ca57c..bd63fa71f 100644 --- a/pkg/definition/gen_sdk/openapi-generator/templates/go/model.mustache +++ b/pkg/definition/gen_sdk/openapi-generator/templates/go/model.mustache @@ -3,7 +3,11 @@ package {{packageName}} {{#models}} import ( +{{#imports}} + "{{import}}" +{{/imports}} "encoding/json" +"errors" "github.com/oam-dev/kubevela-core-api/apis/core.oam.dev/common" "github.com/oam-dev/kubevela-core-api/apis/core.oam.dev/v1beta1" @@ -12,9 +16,6 @@ import ( "github.com/kubevela/vela-go-sdk/pkg/apis" "github.com/kubevela/vela-go-sdk/pkg/apis/utils" sdkcommon "github.com/kubevela/vela-go-sdk/pkg/apis/common" -{{#imports}} - "{{import}}" -{{/imports}} ) {{#model}} diff --git a/pkg/definition/gen_sdk/openapi-generator/templates/go/model_oneof.mustache b/pkg/definition/gen_sdk/openapi-generator/templates/go/model_oneof.mustache index 2bd350cdf..9355ad3c4 100644 --- a/pkg/definition/gen_sdk/openapi-generator/templates/go/model_oneof.mustache +++ b/pkg/definition/gen_sdk/openapi-generator/templates/go/model_oneof.mustache @@ -15,6 +15,18 @@ func {{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}}As{{classname}}(v *{ {{/oneOf}} +// Validate validates this {{classname}} +func (o *{{classname}}) Validate() error{ +{{#oneOf}} + if o.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}} != nil { + return nil + } + +{{/oneOf}} +return fmt.Errorf("No oneOf schemas were matched in {{classname}}") +} + + // Unmarshal JSON data into one of the pointers in the struct func (dst *{{classname}}) UnmarshalJSON(data []byte) error { var err error diff --git a/pkg/definition/gen_sdk/openapi-generator/templates/go/model_simple.mustache b/pkg/definition/gen_sdk/openapi-generator/templates/go/model_simple.mustache index fdb5e57ca..9568216d0 100644 --- a/pkg/definition/gen_sdk/openapi-generator/templates/go/model_simple.mustache +++ b/pkg/definition/gen_sdk/openapi-generator/templates/go/model_simple.mustache @@ -22,7 +22,7 @@ type {{classname}} struct { {{#deprecated}} // Deprecated {{/deprecated}} - {{name}} {{^required}}{{^isNullable}}{{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{/isNullable}}{{/required}}{{{dataType}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"{{#withXml}} xml:"{{baseName}}{{#isXmlAttribute}},attr{{/isXmlAttribute}}"{{/withXml}}{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}` + {{name}} {{^isNullable}}{{^isArray}}{{^isMap}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isMap}}{{/isArray}}{{/isNullable}}{{{dataType}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"{{#withXml}} xml:"{{baseName}}{{#isXmlAttribute}},attr{{/isXmlAttribute}}"{{/withXml}}{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}` {{/vars}} {{#isAdditionalPropertiesTrue}} AdditionalProperties map[string]interface{} @@ -34,14 +34,14 @@ type _{{{classname}}} {{{classname}}} {{/isAdditionalPropertiesTrue}} // New{{classname}}With instantiates a new {{classname}} object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed +// This constructor will make sure properties required by API are set. +// For optional properties, it will set default values if they have been defined. +// The set of arguments will change when the set of required properties is changed func New{{classname}}With({{#requiredVars}}{{nameInCamelCase}} {{dataType}}{{^-last}}, {{/-last}}{{/requiredVars}}) *{{classname}} { this := {{classname}}{} {{#allVars}} {{#required}} - this.{{name}} = {{nameInCamelCase}} + this.{{name}} = {{^isArray}}{{^isMap}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isMap}}{{/isArray}}{{nameInCamelCase}} {{/required}} {{^required}} {{#defaultValue}} @@ -53,7 +53,7 @@ func New{{classname}}With({{#requiredVars}}{{nameInCamelCase}} {{dataType}}{{^-l {{/isNullable}} {{^isNullable}} var {{nameInCamelCase}} {{{dataType}}} = {{{.}}} - this.{{name}} = &{{nameInCamelCase}} + this.{{name}} = {{^isArray}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isArray}}{{nameInCamelCase}} {{/isNullable}} {{/isReadOnly}} {{/vendorExtensions.x-golang-is-container}} @@ -63,10 +63,10 @@ func New{{classname}}With({{#requiredVars}}{{nameInCamelCase}} {{dataType}}{{^-l return &this } -// New{{classname}} instantiates a new {{classname}} object +// New{{classname}}WithDefault instantiates a new {{classname}} object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func New{{classname}}() *{{classname}} { +func New{{classname}}WithDefault() *{{classname}} { this := {{classname}}{} {{#vars}} {{#defaultValue}} @@ -79,7 +79,7 @@ func New{{classname}}() *{{classname}} { {{/isNullable}} {{^isNullable}} var {{nameInCamelCase}} {{{dataType}}} = {{{.}}} - this.{{name}} = {{^required}}&{{/required}}{{nameInCamelCase}} + this.{{name}} = &{{nameInCamelCase}} {{/isNullable}} {{/isReadOnly}} {{/vendorExtensions.x-golang-is-container}} @@ -88,9 +88,24 @@ func New{{classname}}() *{{classname}} { return &this } +// New{{classname}} is short for New{{classname}}WithDefault which instantiates a new {{classname}} object. +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func New{{classname}}() *{{classname}} { + return New{{classname}}WithDefault() +} + +// New{{classname}}Empty instantiates a new {{classname}} object with no properties set. +// This constructor will not assign any default values to properties. +func New{{classname}}Empty() *{{classname}} { + this := {{classname}}{} + return &this +} + + // New{{classname}}s converts a list {{classname}} pointers to objects. // This is helpful when the Set{{classname}} requires a list of objects -func New{{classname}}s(ps ...*{{classname}}) []{{classname}} { +func New{{classname}}List(ps ...*{{classname}}) []{{classname}} { objs := []{{classname}}{} for _, p := range ps { objs = append(objs, *p) @@ -98,6 +113,31 @@ func New{{classname}}s(ps ...*{{classname}}) []{{classname}} { return objs } + +// Validate validates this {{classname}} +// 1. If the required properties are not set, this will return an error +// 2. If properties are set, will check if nested required properties are set +func (o *{{classname}}) Validate() error{ +{{#allVars}} + {{#required}} + if o.{{name}} == nil { + return errors.New("{{name}} in {{classname}} must be set") + } + {{/required}} +{{/allVars}} + // validate all nested properties +{{#allVars}} + {{#isModel}} + if o.{{name}} != nil { + if err:=o.{{name}}.Validate(); err != nil { + return err + } + } + {{/isModel}} +{{/allVars}} +return nil +} + {{#vars}} {{#required}} // Get{{name}} returns the {{name}} field value @@ -122,7 +162,7 @@ func (o *{{classname}}) Get{{name}}() {{vendorExtensions.x-go-base-type}} { {{/vendorExtensions.x-golang-is-container}} {{/isNullable}} {{^isNullable}} - return o.{{name}} + return {{^isArray}}{{^isMap}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isMap}}{{/isArray}}o.{{name}} {{/isNullable}} } @@ -134,7 +174,7 @@ func (o *{{classname}}) Get{{name}}() {{vendorExtensions.x-go-base-type}} { {{#deprecated}} // Deprecated {{/deprecated}} -func (o *{{classname}}) Get{{name}}Ok() ({{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{vendorExtensions.x-go-base-type}}, bool) { +func (o *{{classname}}) Get{{name}}Ok() ({{^isMap}}{{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{/isMap}}{{vendorExtensions.x-go-base-type}}, bool) { if o == nil{{#isNullable}}{{#vendorExtensions.x-golang-is-container}} || utils.IsNil(o.{{name}}){{/vendorExtensions.x-golang-is-container}}{{/isNullable}} { {{^isFreeFormObject}} return nil, false @@ -145,14 +185,15 @@ func (o *{{classname}}) Get{{name}}Ok() ({{^isArray}}{{^isFreeFormObject}}*{{/is } {{#isNullable}} {{#vendorExtensions.x-golang-is-container}} - return {{^isArray}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isArray}}o.{{name}}, true + {{! KubeVela: remove the de-pointer operator here }} + return {{^isArray}}{{^isFreeFormObject}}{{/isFreeFormObject}}{{/isArray}}o.{{name}}, true {{/vendorExtensions.x-golang-is-container}} {{^vendorExtensions.x-golang-is-container}} return o.{{name}}.Get(), o.{{name}}.IsSet() {{/vendorExtensions.x-golang-is-container}} {{/isNullable}} {{^isNullable}} - return {{^isArray}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isArray}}o.{{name}}, true + return {{^isMap}}{{^isArray}}{{^isFreeFormObject}}{{/isFreeFormObject}}{{/isArray}}{{/isMap}}o.{{name}}, true {{/isNullable}} } @@ -172,7 +213,7 @@ func (o *{{classname}}) Set{{name}}(v {{vendorExtensions.x-go-base-type}}) *{{cl {{/vendorExtensions.x-golang-is-container}} {{/isNullable}} {{^isNullable}} - o.{{name}} = v + o.{{name}} = {{^isMap}}{{^isArray}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isArray}}{{/isMap}}v return o {{/isNullable}} } @@ -197,7 +238,7 @@ func (o *{{classname}}) Get{{name}}() {{vendorExtensions.x-go-base-type}} { {{/vendorExtensions.x-golang-is-container}} {{/isNullable}} {{^isNullable}} - return {{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}o.{{name}} + return {{^isMap}}{{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{/isMap}}o.{{name}} {{/isNullable}} } @@ -209,7 +250,7 @@ func (o *{{classname}}) Get{{name}}() {{vendorExtensions.x-go-base-type}} { {{#deprecated}} // Deprecated {{/deprecated}} -func (o *{{classname}}) Get{{name}}Ok() ({{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{vendorExtensions.x-go-base-type}}, bool) { +func (o *{{classname}}) Get{{name}}Ok() ({{^isMap}}{{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{/isMap}}{{vendorExtensions.x-go-base-type}}, bool) { if o == nil{{^isNullable}} || utils.IsNil(o.{{name}}){{/isNullable}}{{#isNullable}}{{#vendorExtensions.x-golang-is-container}} || utils.IsNil(o.{{name}}){{/vendorExtensions.x-golang-is-container}}{{/isNullable}} { {{^isFreeFormObject}} return nil, false @@ -255,7 +296,7 @@ func (o *{{classname}}) Set{{name}}(v {{vendorExtensions.x-go-base-type}}) (*{{c {{/vendorExtensions.x-golang-is-container}} {{/isNullable}} {{^isNullable}} - o.{{name}} = {{^isArray}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isArray}}v + o.{{name}} = {{^isMap}}{{^isArray}}{{^isFreeFormObject}}&{{/isFreeFormObject}}{{/isArray}}{{/isMap}}v {{/isNullable}} return o } diff --git a/pkg/definition/gen_sdk/openapi-generator/templates/go/nullable_model.mustache b/pkg/definition/gen_sdk/openapi-generator/templates/go/nullable_model.mustache index 7b60ce6d3..7a5568cce 100644 --- a/pkg/definition/gen_sdk/openapi-generator/templates/go/nullable_model.mustache +++ b/pkg/definition/gen_sdk/openapi-generator/templates/go/nullable_model.mustache @@ -3,7 +3,7 @@ type Nullable{{{classname}}} struct { isSet bool } -func (v Nullable{{classname}}) Get() {{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{classname}} { +func (v *Nullable{{classname}}) Get() {{^isArray}}{{^isFreeFormObject}}*{{/isFreeFormObject}}{{/isArray}}{{classname}} { return v.value } @@ -12,7 +12,7 @@ func (v *Nullable{{classname}}) Set(val {{^isArray}}{{^isFreeFormObject}}*{{/isF v.isSet = true } -func (v Nullable{{classname}}) IsSet() bool { +func (v *Nullable{{classname}}) IsSet() bool { return v.isSet }