Skip to content

Commit

Permalink
Merge pull request #211 from damemi/add-required-tag
Browse files Browse the repository at this point in the history
Add ability to set default field requirement status
  • Loading branch information
k8s-ci-robot authored Jun 7, 2019
2 parents 4d432d9 + fcf4205 commit 783d255
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 4 deletions.
2 changes: 2 additions & 0 deletions pkg/crd/markers/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ func init() {
AllDefinitions = append(AllDefinitions,
markers.Must(markers.MakeDefinition("groupName", markers.DescribesPackage, "")),
markers.Must(markers.MakeDefinition("versionName", markers.DescribesPackage, "")),
markers.Must(markers.MakeDefinition("kubebuilder:validation:Optional", markers.DescribesPackage, struct{}{})),
markers.Must(markers.MakeDefinition("kubebuilder:validation:Required", markers.DescribesPackage, struct{}{})),
)
}
13 changes: 12 additions & 1 deletion pkg/crd/markers/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import (
"sigs.k8s.io/controller-tools/pkg/markers"
)

// ValidationMarkers lists all available markers that affect CRD schema generation.
// ValidationMarkers lists all available markers that affect CRD schema generation,
// except for the few that don't make sense as type-level markers (see FieldOnlyMarkers).
// All markers start with `+kubebuilder:validation:`, and continue with their type name.
// A copy is produced of all markers that describes types as well, for making types
// reusable and writing complex validations on slice items.
Expand Down Expand Up @@ -60,6 +61,14 @@ var ValidationMarkers = mustMakeAllWithPrefix("kubebuilder:validation", markers.
Nullable(false),
)

// FieldOnlyMarkers list field-specific validation markers (i.e. those markers that don't make
// sense on a type, and thus aren't in ValidationMarkers).
var FieldOnlyMarkers = []*markers.Definition{
markers.Must(markers.MakeDefinition("kubebuilder:validation:Required", markers.DescribesField, struct{}{})),
markers.Must(markers.MakeDefinition("kubebuilder:validation:Optional", markers.DescribesField, struct{}{})),
markers.Must(markers.MakeDefinition("optional", markers.DescribesField, struct{}{})),
}

func init() {
AllDefinitions = append(AllDefinitions, ValidationMarkers...)

Expand Down Expand Up @@ -88,6 +97,8 @@ type Enum []interface{}
type Format string
type Type string
type Nullable bool
type Required struct{}
type Optional struct{}

func (m Maximum) ApplyToSchema(schema *v1beta1.JSONSchemaProps) error {
if schema.Type != "integer" {
Expand Down
10 changes: 9 additions & 1 deletion pkg/crd/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,15 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) {
p.Schemata[typ] = apiext.JSONSchemaProps{}

schemaCtx := newSchemaContext(typ.Package, p)
schema := infoToSchema(schemaCtx.ForInfo(info))
ctxForInfo := schemaCtx.ForInfo(info)

pkgMarkers, err := markers.PackageMarkers(p.Collector, typ.Package)
if err != nil {
typ.Package.AddError(err)
}
ctxForInfo.PackageMarkers = pkgMarkers

schema := infoToSchema(ctxForInfo)

p.Schemata[typ] = *schema

Expand Down
23 changes: 21 additions & 2 deletions pkg/crd/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type schemaContext struct {
info *markers.TypeInfo

schemaRequester schemaRequester
PackageMarkers markers.MarkerValues
}

// newSchemaContext constructs a new schemaContext for the given package and schema requester.
Expand Down Expand Up @@ -342,8 +343,26 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *v1beta1.JSO
fieldName := jsonOpts[0]
inline = inline || fieldName == "" // anonymous fields are inline fields in YAML/JSON

if !inline && !omitEmpty {
props.Required = append(props.Required, fieldName)
// if no default required mode is set, default to required
defaultMode := "required"
if ctx.PackageMarkers.Get("kubebuilder:validation:Optional") != nil {
defaultMode = "optional"
}

switch defaultMode {
// if this package isn't set to optional default...
case "required":
// ...everything that's not inline, omitempty, or explicitly optional is required
if !inline && !omitEmpty && field.Markers.Get("kubebuilder:validation:Optional") == nil && field.Markers.Get("optional") == nil {
props.Required = append(props.Required, fieldName)
}

// if this package isn't set to required default...
case "optional":
// ...everything that isn't explicitly required is optional
if field.Markers.Get("kubebuilder:validation:Required") != nil {
props.Required = append(props.Required, fieldName)
}
}

propSchema := typeToSchema(ctx.ForInfo(&markers.TypeInfo{}), field.RawField.Type)
Expand Down

0 comments on commit 783d255

Please sign in to comment.