From 47fe7853b3bed8bef97a960ef526852e519c8ab3 Mon Sep 17 00:00:00 2001 From: Jiacheng Xu Date: Thu, 9 Jul 2020 21:07:29 +0800 Subject: [PATCH 1/3] First version of crd generator --- cmd/codegen/main.go | 79 ++++++++ go.mod | 1 + go.sum | 2 + pkg/codegen/scaffold/resource.go | 37 ++++ pkg/codegen/scaffold/scaffold.go | 298 +++++++++++++++++++++++++++++++ pkg/codegen/scaffold/spec.go | 24 +++ pkg/codegen/scaffold/status.go | 22 +++ 7 files changed, 463 insertions(+) create mode 100644 cmd/codegen/main.go create mode 100644 pkg/codegen/scaffold/resource.go create mode 100644 pkg/codegen/scaffold/scaffold.go create mode 100644 pkg/codegen/scaffold/spec.go create mode 100644 pkg/codegen/scaffold/status.go diff --git a/cmd/codegen/main.go b/cmd/codegen/main.go new file mode 100644 index 0000000..8574193 --- /dev/null +++ b/cmd/codegen/main.go @@ -0,0 +1,79 @@ +/* +Copyright 2020 The Kubermatic 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 main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/kubermatic/utils/pkg/codegen/scaffold" +) + +func main() { + opts := &scaffold.ScaffoldOptions{ + Resource: scaffold.Resource{ + Version:"v1alpha1", + }, + Spec: scaffold.Spec{ + Metadata:true, + }, + Boilerplate: "./hack/boilerplate/boilerplate.go.txt", + } + scaffoldCmd := &cobra.Command{ + Use: "crdgen", + Short: "Quickly scaffold out basic bits of a Kubernetes type.", + Long: `Quickly scaffold out the structure of a type for a Kubernetes kind and associated types. +Produces: + +- a root type with appropriate metadata fields +- Spec and Status types +- a list type + +Also applies the appropriate comments to generate the code required to conform to runtime.Object.`, + Example: ` # Generate types for a Kind called Foo with a resource called foos + crdgen --kind Foo + + # Generate types for a Kind called Bar with metadata in its Spec + crdgen --kind Bar --metadata`, + RunE: func(_ *cobra.Command, _ []string) error { + if err := opts.Validate(); err != nil { + return err + } + return opts.Scaffold() + }, + } + + scaffoldCmd.Flags().StringVar(&opts.OutputPath, "output", opts.OutputPath, "the Path of the generated file, for example foo_types.go") + scaffoldCmd.Flags().StringVar(&opts.Resource.Kind, "kind", opts.Resource.Kind, "The Kind of the typescaffold being scaffolded.") + scaffoldCmd.Flags().StringVar(&opts.Resource.Version, "version", opts.Resource.Version, "The Version of the typescaffold being scaffolded.") + scaffoldCmd.Flags().StringVar(&opts.Boilerplate, "boilerplate", opts.Boilerplate, "The Boilerplate header file path.") + scaffoldCmd.Flags().BoolVar(&opts.Spec.Metadata, "metadata", opts.Spec.Metadata, "Whether wants to generate metadata fields in the Spec of this Kind") + + if err := cobra.MarkFlagRequired(scaffoldCmd.Flags(), "kind"); err != nil { + panic("unable to mark --kind as required") + } + + if err := scaffoldCmd.Execute(); err != nil { + if _, err := fmt.Fprintln(os.Stderr, err); err != nil { + // this would be exceedingly bizarre if we ever got here + panic("unable to write to error details to standard error") + } + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index f51a2ca..8c219e4 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.14 require ( github.com/go-logr/logr v0.1.0 github.com/go-logr/zapr v0.1.0 + github.com/gobuffalo/flect v0.2.1 github.com/google/go-cmp v0.5.0 github.com/spf13/cobra v1.0.0 github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index 0f64ddc..f8b5e26 100644 --- a/go.sum +++ b/go.sum @@ -125,6 +125,8 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/flect v0.2.1 h1:GPoRjEN0QObosV4XwuoWvSd5uSiL0N3e91/xqyY4crQ= +github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= diff --git a/pkg/codegen/scaffold/resource.go b/pkg/codegen/scaffold/resource.go new file mode 100644 index 0000000..c698dc3 --- /dev/null +++ b/pkg/codegen/scaffold/resource.go @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Kubermatic 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 scaffold + +import ( + "fmt" +) + +// Resource contains the information required to scaffold files for a resource. +type Resource struct { + // Kind is the API Kind. + Kind string + // Version is the API Version. + Version string +} + +// Validate checks the Resource values to make sure they are valid. +func (r *Resource) Validate() error { + if len(r.Kind) == 0 { + return fmt.Errorf("kind cannot be empty") + } + return nil +} diff --git a/pkg/codegen/scaffold/scaffold.go b/pkg/codegen/scaffold/scaffold.go new file mode 100644 index 0000000..5169eb4 --- /dev/null +++ b/pkg/codegen/scaffold/scaffold.go @@ -0,0 +1,298 @@ +/* +Copyright 2020 The Kubermatic 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 scaffold + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + "text/template" + "time" +) + +var ( + scaffoldTemplateRaw = ` +package {{.Resource.Version}} + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// {{.Resource.Kind}}Spec defines the desired state of {{.Resource.Kind}} +type {{.Resource.Kind}}Spec struct { + + // INSERT ADDITIONAL SPEC FIELDS -- desired state of cluster + +{{- if .Spec.Metadata }} + // Metadata contains additional human readable {{.Resource.Kind}} details. + Metadata *{{.Resource.Kind}}Metadata ` +"`" + `json:"metadata,omitempty"` + "`" + ` +{{ end }} +} + +{{- if .Spec.Metadata }} +// {{.Resource.Kind}}Metadata contains the metadata of the {{.Resource.Kind}}. +type {{.Resource.Kind}}Metadata struct { + // DisplayName is the human-readable name of this {{.Resource.Kind}}. + // +kubebuilder:validation:MinLength=1 + DisplayName string ` +"`" + `json:"displayName"` + "`" + ` + // Description is the long and detailed description of the {{.Resource.Kind}}. + // +kubebuilder:validation:MinLength=1 + Description string ` +"`" + `json:"description"` + "`" + ` +} +{{ end }} + +// {{.Resource.Kind}}Status defines the observed state of {{.Resource.Kind}}. +// It should always be reconstructable from the state of the cluster and/or outside world. +type {{.Resource.Kind}}Status struct { + + // INSERT ADDITIONAL STATUS FIELDS -- observed state of cluster + + // ObservedGeneration is the most recent generation observed for this {{.Resource.Kind}} by the controller. + ObservedGeneration int64 ` +"`" + `json:"observedGeneration,omitempty"` + "`" + ` + // Conditions represents the latest available observations of a {{.Resource.Kind}}'s current state. + Conditions []{{.Resource.Kind}}Condition ` +"`" + `json:"conditions,omitempty"` + "`" + ` + // DEPRECATED. + // Phase represents the current lifecycle state of this object. + // Consider this field DEPRECATED, it will be removed as soon as there + // is a mechanism to map conditions to strings when printing the property. + // This is only for display purpose, for everything else use conditions. + Phase {{.Resource.Kind}}PhaseType ` +"`" + `json:"phase,omitempty"` + "`" + ` +} + +// {{.Resource.Kind}}PhaseType represents all conditions as a single string for printing by using kubectl commands. +// +kubebuilder:validation:Ready;NotReady;Unknown;Terminating +type {{.Resource.Kind}}PhaseType string + +// Values of {{.Resource.Kind}}PhaseType. +const ( + {{.Resource.Kind}}PhaseReady {{.Resource.Kind}}PhaseType = "Ready" + {{.Resource.Kind}}PhaseNotReady {{.Resource.Kind}}PhaseType = "NotReady" + {{.Resource.Kind}}PhaseUnknown {{.Resource.Kind}}PhaseType = "Unknown" + {{.Resource.Kind}}PhaseTerminating {{.Resource.Kind}}PhaseType = "Terminating" +) + +const ( + {{.Resource.Kind}}TerminatingReason = "Deleting" +) + +// updatePhase updates the phase property based on the current conditions. +// this method should be called every time the conditions are updated. +func (s *{{.Resource.Kind}}Status) updatePhase() { + for _, condition := range s.Conditions { + if condition.Type != {{.Resource.Kind}}Ready { + continue + } + + switch condition.Status { + case {{.Resource.Kind}}ConditionTrue: + s.Phase = {{.Resource.Kind}}PhaseReady + case {{.Resource.Kind}}ConditionFalse: + if condition.Reason == {{.Resource.Kind}}TerminatingReason { + s.Phase = {{.Resource.Kind}}PhaseTerminating + } else { + s.Phase = {{.Resource.Kind}}PhaseNotReady + } + case {{.Resource.Kind}}ConditionUnknown: + s.Phase = {{.Resource.Kind}}PhaseUnknown + } + return + } + + s.Phase = {{.Resource.Kind}}PhaseUnknown +} + +// {{.Resource.Kind}}ConditionType represents a {{.Resource.Kind}}Condition value. +// +kubebuilder:validation:Ready +type {{.Resource.Kind}}ConditionType string + +const ( + // {{.Resource.Kind}}Ready represents a {{.Resource.Kind}} condition is in ready state. + {{.Resource.Kind}}Ready {{.Resource.Kind}}ConditionType = "Ready" +) + +// {{.Resource.Kind}}ConditionStatus represents a condition's status. +// +kubebuilder:validation:True;False;Unknown +type {{.Resource.Kind}}ConditionStatus string + +// These are valid condition statuses. "{{.Resource.Kind}}ConditionTrue" means a resource is in +// the condition; "{{.Resource.Kind}}ConditionFalse" means a resource is not in the condition; +// "{{.Resource.Kind}}ConditionFalse" means Kubernetes can't decide if a resource is in the +// condition or not. +const ( + // {{.Resource.Kind}}ConditionTrue represents the fact that a given condition is true + {{.Resource.Kind}}ConditionTrue {{.Resource.Kind}}ConditionStatus = "True" + + // {{.Resource.Kind}}ConditionFalse represents the fact that a given condition is false + {{.Resource.Kind}}ConditionFalse {{.Resource.Kind}}ConditionStatus = "False" + + // {{.Resource.Kind}}ConditionUnknown represents the fact that a given condition is unknown + {{.Resource.Kind}}ConditionUnknown {{.Resource.Kind}}ConditionStatus = "Unknown" +) + +// {{.Resource.Kind}}Condition contains details for the current condition of this {{.Resource.Kind}}. +type {{.Resource.Kind}}Condition struct { + // Type is the type of the {{.Resource.Kind}} condition, currently ('Ready'). + Type {{.Resource.Kind}}ConditionType ` + "`" + `json:"type"` + "`" + ` + // Status is the status of the condition, one of ('True', 'False', 'Unknown'). + Status {{.Resource.Kind}}ConditionStatus ` + "`" + `json:"status"` + "`" + ` + // LastTransitionTime is the last time the condition transits from one status to another. + LastTransitionTime metav1.Time ` + "`" + `json:"lastTransitionTime"` + "`" + ` + // Reason is the (brief) reason for the condition's last transition. + Reason string ` + "`" + `json:"reason"` + "`" + ` + // Message is the human readable message indicating details about last transition. + Message string ` + "`" + `json:"message"` + "`" + ` +} + +// GetCondition returns the Condition of the given condition type, if it exists. +func (s *{{.Resource.Kind}}Status) GetCondition(t {{.Resource.Kind}}ConditionType) (condition {{.Resource.Kind}}Condition, exists bool) { + for _, cond := range s.Conditions { + if cond.Type == t { + condition = cond + exists = true + return + } + } + return +} + +// SetCondition replaces or adds the given condition. +func (s *{{.Resource.Kind}}Status) SetCondition(condition {{.Resource.Kind}}Condition) { + defer s.updatePhase() + + if condition.LastTransitionTime.IsZero() { + condition.LastTransitionTime = metav1.Now() + } + + for i := range s.Conditions { + if s.Conditions[i].Type == condition.Type { + + // Only update the LastTransitionTime when the Status is changed. + if s.Conditions[i].Status != condition.Status { + s.Conditions[i].LastTransitionTime = condition.LastTransitionTime + } + + s.Conditions[i].Status = condition.Status + s.Conditions[i].Reason = condition.Reason + s.Conditions[i].Message = condition.Message + + return + } + } + + s.Conditions = append(s.Conditions, condition) +} + +// {{.Resource.Kind}} is the Schema for the {{.Resource.Kind}} API. +// +kubebuilder:object:root=true +type {{.Resource.Kind}} struct { + metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` + metav1.ObjectMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` + + Spec {{.Resource.Kind}}Spec ` + "`" + `json:"spec,omitempty"` + "`" + ` + Status {{.Resource.Kind}}Status ` + "`" + `json:"status,omitempty"` + "`" + ` +} + +// IsReady returns if the {{.Resource.Kind}} is ready. +func (s *{{.Resource.Kind}}) IsReady() bool { + if !s.DeletionTimestamp.IsZero() { + return false + } + + if s.Generation != s.Status.ObservedGeneration { + return false + } + + for _, condition := range s.Status.Conditions { + if condition.Type == {{.Resource.Kind}}Ready && + condition.Status == {{.Resource.Kind}}ConditionTrue { + return true + } + } + return false +} + +// {{.Resource.Kind}}List contains a list of {{.Resource.Kind}} +type {{.Resource.Kind}}List struct { + metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` + metav1.ListMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` + Items []{{.Resource.Kind}} ` + "`" + `json:"items"` + "`" + ` +} +` + typesTemplateHelpers = template.FuncMap{ + "SplitLines": func(raw string) []string { return strings.Split(raw, "\n") }, + } + + typesTemplate = template.Must(template.New("status-scaffolding").Funcs(typesTemplateHelpers).Parse(scaffoldTemplateRaw)) +) + +// ScaffoldOptions describes how to scaffold out a Kubernetes object +// with the basic metadata and comment annotations required to generate code +// for and conform to runtime.Object and metav1.Object. +type ScaffoldOptions struct { + Resource Resource + Spec Spec + Status Status + // The Path of the Boilerplate header file. + Boilerplate string + OutputPath string +} + +// Validate validates the options, returning an error if anything is invalid. +func (o *ScaffoldOptions) Validate() error { + if err := o.Resource.Validate(); err != nil { + return err + } + if o.OutputPath == "" { + o.OutputPath = strings.ToLower(o.Resource.Kind) + "_types.go" + } + + // Check if the file to write already exists + if _, err := os.Stat(o.OutputPath); err == nil { + // file is already exist + return fmt.Errorf("%s already exists", o.OutputPath) + }else if os.IsNotExist(err) { + return nil + }else { + return err + } +} + +// Scaffold prints the Kubernetes object scaffolding to the given output. +func (o *ScaffoldOptions) Scaffold() error { + f, err := os.Create(o.OutputPath) + defer f.Close() + boilerplate, err := o.loadBoilerplate() + if err != nil { + return err + } + if _, err := f.Write(boilerplate); err != nil { + return err + } + return typesTemplate.Execute(f, o) +} + +func (o *ScaffoldOptions) loadBoilerplate() ([]byte, error){ + b, err := ioutil.ReadFile(o.Boilerplate) + if err != nil { + return nil, err + } + b = bytes.Replace(b, []byte("YEAR"), []byte(strconv.Itoa(time.Now().UTC().Year())), -1) + return b, nil +} diff --git a/pkg/codegen/scaffold/spec.go b/pkg/codegen/scaffold/spec.go new file mode 100644 index 0000000..cac1eac --- /dev/null +++ b/pkg/codegen/scaffold/spec.go @@ -0,0 +1,24 @@ +/* +Copyright 2020 The Kubermatic 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 scaffold + +// Spec contains the information required to scaffold files for a CRD Spec. +type Spec struct { + // Metadata is true if you want to generate metadata fields in Spec. + Metadata bool +} + diff --git a/pkg/codegen/scaffold/status.go b/pkg/codegen/scaffold/status.go new file mode 100644 index 0000000..9880e44 --- /dev/null +++ b/pkg/codegen/scaffold/status.go @@ -0,0 +1,22 @@ +/* +Copyright 2020 The Kubermatic 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 scaffold + +// Status contains the information required to scaffold files for a CRD Status. +type Status struct { +} + From c8d15d186ea702172f8793d1cbc7153ce84dffa2 Mon Sep 17 00:00:00 2001 From: Jiacheng Xu Date: Thu, 9 Jul 2020 21:15:39 +0800 Subject: [PATCH 2/3] Fix go lint --- cmd/codegen/main.go | 4 ++-- go.mod | 1 - go.sum | 2 -- pkg/codegen/scaffold/scaffold.go | 26 +++++++++++++------------- pkg/codegen/scaffold/spec.go | 1 - pkg/codegen/scaffold/status.go | 1 - 6 files changed, 15 insertions(+), 20 deletions(-) diff --git a/cmd/codegen/main.go b/cmd/codegen/main.go index 8574193..106022b 100644 --- a/cmd/codegen/main.go +++ b/cmd/codegen/main.go @@ -28,10 +28,10 @@ import ( func main() { opts := &scaffold.ScaffoldOptions{ Resource: scaffold.Resource{ - Version:"v1alpha1", + Version: "v1alpha1", }, Spec: scaffold.Spec{ - Metadata:true, + Metadata: true, }, Boilerplate: "./hack/boilerplate/boilerplate.go.txt", } diff --git a/go.mod b/go.mod index 8c219e4..f51a2ca 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.14 require ( github.com/go-logr/logr v0.1.0 github.com/go-logr/zapr v0.1.0 - github.com/gobuffalo/flect v0.2.1 github.com/google/go-cmp v0.5.0 github.com/spf13/cobra v1.0.0 github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index f8b5e26..0f64ddc 100644 --- a/go.sum +++ b/go.sum @@ -125,8 +125,6 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/flect v0.2.1 h1:GPoRjEN0QObosV4XwuoWvSd5uSiL0N3e91/xqyY4crQ= -github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= diff --git a/pkg/codegen/scaffold/scaffold.go b/pkg/codegen/scaffold/scaffold.go index 5169eb4..4ab97b2 100644 --- a/pkg/codegen/scaffold/scaffold.go +++ b/pkg/codegen/scaffold/scaffold.go @@ -42,7 +42,7 @@ type {{.Resource.Kind}}Spec struct { {{- if .Spec.Metadata }} // Metadata contains additional human readable {{.Resource.Kind}} details. - Metadata *{{.Resource.Kind}}Metadata ` +"`" + `json:"metadata,omitempty"` + "`" + ` + Metadata *{{.Resource.Kind}}Metadata ` + "`" + `json:"metadata,omitempty"` + "`" + ` {{ end }} } @@ -51,10 +51,10 @@ type {{.Resource.Kind}}Spec struct { type {{.Resource.Kind}}Metadata struct { // DisplayName is the human-readable name of this {{.Resource.Kind}}. // +kubebuilder:validation:MinLength=1 - DisplayName string ` +"`" + `json:"displayName"` + "`" + ` + DisplayName string ` + "`" + `json:"displayName"` + "`" + ` // Description is the long and detailed description of the {{.Resource.Kind}}. // +kubebuilder:validation:MinLength=1 - Description string ` +"`" + `json:"description"` + "`" + ` + Description string ` + "`" + `json:"description"` + "`" + ` } {{ end }} @@ -65,15 +65,15 @@ type {{.Resource.Kind}}Status struct { // INSERT ADDITIONAL STATUS FIELDS -- observed state of cluster // ObservedGeneration is the most recent generation observed for this {{.Resource.Kind}} by the controller. - ObservedGeneration int64 ` +"`" + `json:"observedGeneration,omitempty"` + "`" + ` + ObservedGeneration int64 ` + "`" + `json:"observedGeneration,omitempty"` + "`" + ` // Conditions represents the latest available observations of a {{.Resource.Kind}}'s current state. - Conditions []{{.Resource.Kind}}Condition ` +"`" + `json:"conditions,omitempty"` + "`" + ` + Conditions []{{.Resource.Kind}}Condition ` + "`" + `json:"conditions,omitempty"` + "`" + ` // DEPRECATED. // Phase represents the current lifecycle state of this object. // Consider this field DEPRECATED, it will be removed as soon as there // is a mechanism to map conditions to strings when printing the property. // This is only for display purpose, for everything else use conditions. - Phase {{.Resource.Kind}}PhaseType ` +"`" + `json:"phase,omitempty"` + "`" + ` + Phase {{.Resource.Kind}}PhaseType ` + "`" + `json:"phase,omitempty"` + "`" + ` } // {{.Resource.Kind}}PhaseType represents all conditions as a single string for printing by using kubectl commands. @@ -247,11 +247,11 @@ type {{.Resource.Kind}}List struct { // for and conform to runtime.Object and metav1.Object. type ScaffoldOptions struct { Resource Resource - Spec Spec - Status Status + Spec Spec + Status Status // The Path of the Boilerplate header file. Boilerplate string - OutputPath string + OutputPath string } // Validate validates the options, returning an error if anything is invalid. @@ -260,16 +260,16 @@ func (o *ScaffoldOptions) Validate() error { return err } if o.OutputPath == "" { - o.OutputPath = strings.ToLower(o.Resource.Kind) + "_types.go" + o.OutputPath = strings.ToLower(o.Resource.Kind) + "_types.go" } // Check if the file to write already exists if _, err := os.Stat(o.OutputPath); err == nil { // file is already exist return fmt.Errorf("%s already exists", o.OutputPath) - }else if os.IsNotExist(err) { + } else if os.IsNotExist(err) { return nil - }else { + } else { return err } } @@ -288,7 +288,7 @@ func (o *ScaffoldOptions) Scaffold() error { return typesTemplate.Execute(f, o) } -func (o *ScaffoldOptions) loadBoilerplate() ([]byte, error){ +func (o *ScaffoldOptions) loadBoilerplate() ([]byte, error) { b, err := ioutil.ReadFile(o.Boilerplate) if err != nil { return nil, err diff --git a/pkg/codegen/scaffold/spec.go b/pkg/codegen/scaffold/spec.go index cac1eac..f36101d 100644 --- a/pkg/codegen/scaffold/spec.go +++ b/pkg/codegen/scaffold/spec.go @@ -21,4 +21,3 @@ type Spec struct { // Metadata is true if you want to generate metadata fields in Spec. Metadata bool } - diff --git a/pkg/codegen/scaffold/status.go b/pkg/codegen/scaffold/status.go index 9880e44..1325562 100644 --- a/pkg/codegen/scaffold/status.go +++ b/pkg/codegen/scaffold/status.go @@ -19,4 +19,3 @@ package scaffold // Status contains the information required to scaffold files for a CRD Status. type Status struct { } - From ac0f151d99952a37d17d5640300456016c3570cf Mon Sep 17 00:00:00 2001 From: Jiacheng Xu Date: Thu, 9 Jul 2020 21:20:42 +0800 Subject: [PATCH 3/3] Fix go lint --- pkg/codegen/scaffold/scaffold.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/codegen/scaffold/scaffold.go b/pkg/codegen/scaffold/scaffold.go index 4ab97b2..1e40763 100644 --- a/pkg/codegen/scaffold/scaffold.go +++ b/pkg/codegen/scaffold/scaffold.go @@ -277,6 +277,9 @@ func (o *ScaffoldOptions) Validate() error { // Scaffold prints the Kubernetes object scaffolding to the given output. func (o *ScaffoldOptions) Scaffold() error { f, err := os.Create(o.OutputPath) + if err != nil { + return nil + } defer f.Close() boilerplate, err := o.loadBoilerplate() if err != nil {