Skip to content

Commit eba92f4

Browse files
authored
🐛 Skip unexported fields when generating CRDs (#584)
* Skip unexported fields when generating CRDs * Add generator flag to skip unexported fields
1 parent c796d03 commit eba92f4

File tree

8 files changed

+67
-14
lines changed

8 files changed

+67
-14
lines changed

pkg/crd/gen.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ const defaultVersion = v1
4141

4242
// Generator generates CustomResourceDefinition objects.
4343
type Generator struct {
44+
// IgnoreUnexportedFields indicates that we should skip unexported fields.
45+
//
46+
// Left unspecified, the default is false.
47+
IgnoreUnexportedFields *bool `marker:",optional"`
48+
4449
// AllowDangerousTypes allows types which are usually omitted from CRD generation
4550
// because they are not recommended.
4651
//
@@ -85,7 +90,8 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
8590
Collector: ctx.Collector,
8691
Checker: ctx.Checker,
8792
// Perform defaulting here to avoid ambiguity later
88-
AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
93+
IgnoreUnexportedFields: g.IgnoreUnexportedFields != nil && *g.IgnoreUnexportedFields == true,
94+
AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
8995
// Indicates the parser on whether to register the ObjectMeta type or not
9096
GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true,
9197
}

pkg/crd/parser.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ type Parser struct {
8787
// TODO: Should we have a more formal mechanism for putting "type patterns" in each of the above categories?
8888
AllowDangerousTypes bool
8989

90+
// IgnoreUnexportedFields specifies if unexported fields on the struct should be skipped
91+
IgnoreUnexportedFields bool
92+
9093
// GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta should be generated
9194
GenerateEmbeddedObjectMeta bool
9295
}
@@ -178,7 +181,7 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) {
178181
// avoid tripping recursive schemata, like ManagedFields, by adding an empty WIP schema
179182
p.Schemata[typ] = apiext.JSONSchemaProps{}
180183

181-
schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes)
184+
schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes, p.IgnoreUnexportedFields)
182185
ctxForInfo := schemaCtx.ForInfo(info)
183186

184187
pkgMarkers, err := markers.PackageMarkers(p.Collector, typ.Package)

pkg/crd/parser_integration_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func
7272
reg := &markers.Registry{}
7373
Expect(crdmarkers.Register(reg)).To(Succeed())
7474
parser := &crd.Parser{
75-
Collector: &markers.Collector{Registry: reg},
76-
Checker: &loader.TypeChecker{},
75+
Collector: &markers.Collector{Registry: reg},
76+
Checker: &loader.TypeChecker{},
77+
IgnoreUnexportedFields: true,
7778
}
7879
crd.AddKnownTypes(parser)
7980

pkg/crd/schema.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,31 @@ type schemaContext struct {
6969
schemaRequester schemaRequester
7070
PackageMarkers markers.MarkerValues
7171

72-
allowDangerousTypes bool
72+
allowDangerousTypes bool
73+
ignoreUnexportedFields bool
7374
}
7475

7576
// newSchemaContext constructs a new schemaContext for the given package and schema requester.
7677
// It must have type info added before use via ForInfo.
77-
func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes bool) *schemaContext {
78+
func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes, ignoreUnexportedFields bool) *schemaContext {
7879
pkg.NeedTypesInfo()
7980
return &schemaContext{
80-
pkg: pkg,
81-
schemaRequester: req,
82-
allowDangerousTypes: allowDangerousTypes,
81+
pkg: pkg,
82+
schemaRequester: req,
83+
allowDangerousTypes: allowDangerousTypes,
84+
ignoreUnexportedFields: ignoreUnexportedFields,
8385
}
8486
}
8587

8688
// ForInfo produces a new schemaContext with containing the same information
8789
// as this one, except with the given type information.
8890
func (c *schemaContext) ForInfo(info *markers.TypeInfo) *schemaContext {
8991
return &schemaContext{
90-
pkg: c.pkg,
91-
info: info,
92-
schemaRequester: c.schemaRequester,
93-
allowDangerousTypes: c.allowDangerousTypes,
92+
pkg: c.pkg,
93+
info: info,
94+
schemaRequester: c.schemaRequester,
95+
allowDangerousTypes: c.allowDangerousTypes,
96+
ignoreUnexportedFields: c.ignoreUnexportedFields,
9497
}
9598
}
9699

@@ -339,6 +342,11 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON
339342
}
340343

341344
for _, field := range ctx.info.Fields {
345+
// Skip if the field is not an inline field, ignoreUnexportedFields is true, and the field is not exported
346+
if field.Name != "" && ctx.ignoreUnexportedFields && !ast.IsExported(field.Name) {
347+
continue
348+
}
349+
342350
jsonTag, hasTag := field.Tag.Lookup("json")
343351
if !hasTag {
344352
// if the field doesn't have a JSON tag, it doesn't belong in output (and shouldn't exist in a serialized type)

pkg/crd/schema_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func transform(t *testing.T, expr string) *apiext.JSONSchemaProps {
6363
pkg.NeedTypesInfo()
6464
failIfErrors(t, pkg.Errors)
6565

66-
schemaContext := newSchemaContext(pkg, nil, true).ForInfo(&markers.TypeInfo{})
66+
schemaContext := newSchemaContext(pkg, nil, true, false).ForInfo(&markers.TypeInfo{})
6767
// yick: grab the only type definition
6868
definedType := pkg.Syntax[0].Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Type
6969
result := typeToSchema(schemaContext, definedType)

pkg/crd/testdata/cronjob_types.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ type CronJobSpec struct {
181181

182182
// Maps of arrays of things-that-aren’t-strings are permitted
183183
MapOfArraysOfFloats map[string][]bool `json:"mapOfArraysOfFloats,omitempty"`
184+
185+
// This tests that unexported fields are skipped in the schema generation
186+
unexportedField string
187+
188+
// This tests that both unexported and exported inline fields are not skipped in the schema generation
189+
unexportedStruct `json:",inline"`
190+
ExportedStruct `json:",inline"`
184191
}
185192

186193
type ContainsNestedMap struct {
@@ -235,6 +242,22 @@ type MinMaxObject struct {
235242
Baz string `json:"baz,omitempty"`
236243
}
237244

245+
type unexportedStruct struct {
246+
// This tests that exported fields are not skipped in the schema generation
247+
Foo string `json:"foo"`
248+
249+
// This tests that unexported fields are skipped in the schema generation
250+
bar string
251+
}
252+
253+
type ExportedStruct struct {
254+
// This tests that exported fields are not skipped in the schema generation
255+
Baz string `json:"baz"`
256+
257+
// This tests that unexported fields are skipped in the schema generation
258+
qux string
259+
}
260+
238261
type RootObject struct {
239262
Nested NestedObject `json:"nested"`
240263
}

pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ spec:
5555
- name
5656
- secondary
5757
x-kubernetes-list-type: map
58+
baz:
59+
description: This tests that exported fields are not skipped in the schema generation
60+
type: string
5861
binaryName:
5962
description: This tests byte slice schema generation.
6063
format: byte
@@ -134,6 +137,9 @@ spec:
134137
for having a pattern on this type.
135138
pattern: ^((100|[0-9]{1,2})%|[0-9]+)$
136139
x-kubernetes-int-or-string: true
140+
foo:
141+
description: This tests that exported fields are not skipped in the schema generation
142+
type: string
137143
jobTemplate:
138144
description: Specifies the job that will be created when executing
139145
a CronJob.
@@ -7312,12 +7318,14 @@ spec:
73127318
x-kubernetes-preserve-unknown-fields: true
73137319
required:
73147320
- associativeList
7321+
- baz
73157322
- binaryName
73167323
- canBeNull
73177324
- defaultedObject
73187325
- defaultedSlice
73197326
- defaultedString
73207327
- embeddedResource
7328+
- foo
73217329
- jobTemplate
73227330
- mapOfInfo
73237331
- patternObject

pkg/crd/zz_generated.markerhelp.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)