Skip to content

Commit cf302a3

Browse files
authored
Merge pull request #1310 from JoelSpeed/revert-1270
⚠️ Revert local override breaking behavioural change
2 parents 2f0db50 + 49d7045 commit cf302a3

File tree

4 files changed

+53
-34
lines changed

4 files changed

+53
-34
lines changed

pkg/crd/parser.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,7 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) {
172172
// avoid tripping recursive schemata, like ManagedFields, by adding an empty WIP schema
173173
p.Schemata[typ] = apiext.JSONSchemaProps{}
174174

175-
schemaCtx := newSchemaContext(typ.Package, p, func(typ TypeIdent) *apiext.JSONSchemaProps {
176-
p.NeedSchemaFor(typ)
177-
178-
props := p.Schemata[typ]
179-
return &props
180-
}, p.AllowDangerousTypes, p.IgnoreUnexportedFields)
175+
schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes, p.IgnoreUnexportedFields)
181176
ctxForInfo := schemaCtx.ForInfo(info)
182177

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

pkg/crd/schema.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,10 @@ type applyFirstMarker interface {
5757
ApplyFirst()
5858
}
5959

60-
// schemaFetcher is a function that fetches a schema for a given type.
61-
type schemaFetcher func(TypeIdent) *apiext.JSONSchemaProps
62-
6360
// schemaRequester knows how to marker that another schema (e.g. via an external reference) is necessary.
6461
type schemaRequester interface {
6562
NeedSchemaFor(typ TypeIdent)
63+
LookupType(pkg *loader.Package, name string) *markers.TypeInfo
6664
}
6765

6866
// schemaContext stores and provides information across a hierarchy of schema generation.
@@ -71,7 +69,6 @@ type schemaContext struct {
7169
info *markers.TypeInfo
7270

7371
schemaRequester schemaRequester
74-
schemaFetcher schemaFetcher
7572
PackageMarkers markers.MarkerValues
7673

7774
allowDangerousTypes bool
@@ -80,12 +77,11 @@ type schemaContext struct {
8077

8178
// newSchemaContext constructs a new schemaContext for the given package and schema requester.
8279
// It must have type info added before use via ForInfo.
83-
func newSchemaContext(pkg *loader.Package, req schemaRequester, fetcher schemaFetcher, allowDangerousTypes, ignoreUnexportedFields bool) *schemaContext {
80+
func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes, ignoreUnexportedFields bool) *schemaContext {
8481
pkg.NeedTypesInfo()
8582
return &schemaContext{
8683
pkg: pkg,
8784
schemaRequester: req,
88-
schemaFetcher: fetcher,
8985
allowDangerousTypes: allowDangerousTypes,
9086
ignoreUnexportedFields: ignoreUnexportedFields,
9187
}
@@ -98,7 +94,6 @@ func (c *schemaContext) ForInfo(info *markers.TypeInfo) *schemaContext {
9894
pkg: c.pkg,
9995
info: info,
10096
schemaRequester: c.schemaRequester,
101-
schemaFetcher: c.schemaFetcher,
10297
allowDangerousTypes: c.allowDangerousTypes,
10398
ignoreUnexportedFields: c.ignoreUnexportedFields,
10499
}
@@ -240,9 +235,7 @@ func typeToSchema(ctx *schemaContext, rawType ast.Expr) *apiext.JSONSchemaProps
240235
return &apiext.JSONSchemaProps{}
241236
}
242237

243-
if ctx.info.Doc != "" {
244-
props.Description = ctx.info.Doc
245-
}
238+
props.Description = ctx.info.Doc
246239

247240
applyMarkers(ctx, ctx.info.Markers, props, rawType)
248241

@@ -278,7 +271,6 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
278271
if aliasInfo, isAlias := typeInfo.(*types.Alias); isAlias {
279272
typeInfo = aliasInfo.Rhs()
280273
}
281-
282274
if basicInfo, isBasic := typeInfo.(*types.Basic); isBasic {
283275
typ, fmt, err := builtinToType(basicInfo, ctx.allowDangerousTypes)
284276
if err != nil {
@@ -290,21 +282,50 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
290282
// > Otherwise, the alias information is only in the type name, which
291283
// > points directly to the actual (aliased) type.
292284
if basicInfo.Name() != ident.Name {
293-
return ctx.schemaFetcher(TypeIdent{
294-
Package: ctx.pkg,
295-
Name: ident.Name,
296-
})
285+
ctx.requestSchema("", ident.Name)
286+
link := TypeRefLink("", ident.Name)
287+
return &apiext.JSONSchemaProps{
288+
Type: typ,
289+
Format: fmt,
290+
Ref: &link,
291+
}
297292
}
298293
return &apiext.JSONSchemaProps{
299294
Type: typ,
300295
Format: fmt,
301296
}
302297
}
298+
// NB(directxman12): if there are dot imports, this might be an external reference,
299+
// so use typechecking info to get the actual object
300+
typeNameInfo := typeInfo.(interface{ Obj() *types.TypeName }).Obj()
301+
pkg := typeNameInfo.Pkg()
302+
pkgPath := loader.NonVendorPath(pkg.Path())
303+
if pkg == ctx.pkg.Types {
304+
pkgPath = ""
305+
}
306+
ctx.requestSchema(pkgPath, typeNameInfo.Name())
307+
link := TypeRefLink(pkgPath, typeNameInfo.Name())
308+
309+
// In cases where we have a named type, apply the type and format from the named schema
310+
// to allow markers that need this information to apply correctly.
311+
var typ, fmt string
312+
if namedInfo, isNamed := typeInfo.(*types.Named); isNamed {
313+
// We don't want/need to do this for structs, maps, or arrays.
314+
// These are already handled in infoToSchema if they have custom marshalling.
315+
if _, isBasic := namedInfo.Underlying().(*types.Basic); isBasic {
316+
namedTypeInfo := ctx.schemaRequester.LookupType(ctx.pkg, namedInfo.Obj().Name())
317+
318+
namedSchema := infoToSchema(ctx.ForInfo(namedTypeInfo))
319+
typ = namedSchema.Type
320+
fmt = namedSchema.Format
321+
}
322+
}
303323

304-
return ctx.schemaFetcher(TypeIdent{
305-
Package: ctx.pkg,
306-
Name: ident.Name,
307-
})
324+
return &apiext.JSONSchemaProps{
325+
Type: typ,
326+
Format: fmt,
327+
Ref: &link,
328+
}
308329
}
309330

310331
// namedSchema creates a schema (ref) for an explicitly external type reference.
@@ -504,9 +525,7 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON
504525
} else {
505526
propSchema = typeToSchema(ctx.ForInfo(&markers.TypeInfo{}), field.RawField.Type)
506527
}
507-
if field.Doc != "" {
508-
propSchema.Description = field.Doc
509-
}
528+
propSchema.Description = field.Doc
510529

511530
applyMarkers(ctx, field.Markers, propSchema, field.RawField)
512531

pkg/crd/schema_test.go

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

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

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,18 +226,23 @@ spec:
226226
format: int32
227227
type: integer
228228
fieldLevelAliasOverride:
229+
allOf:
230+
- maxLength: 255
231+
minLength: 1
232+
- maxLength: 10
233+
minLength: 10
229234
description: |-
230235
This tests that field-level overrides are handled correctly
231236
for local type aliases.
232-
maxLength: 10
233-
minLength: 10
234237
type: string
235238
fieldLevelLocalDeclarationOverride:
239+
allOf:
240+
- minLength: 4
241+
- minLength: 10
236242
description: |-
237243
This tests that field-level overrides are handled correctly
238244
for local type declarations.
239245
maxLength: 10
240-
minLength: 10
241246
type: string
242247
float64WithValidations:
243248
maximum: 1.5
@@ -9098,10 +9103,10 @@ spec:
90989103
and type.
90999104
type: string
91009105
x-kubernetes-validations:
9101-
- message: must have even length
9102-
rule: self.size() % 2 == 0
91039106
- message: must have good prefix
91049107
rule: self.startsWith('good-')
9108+
- message: must have even length
9109+
rule: self.size() % 2 == 0
91059110
stringWithEvenLengthAndMessageExpression:
91069111
description: Test of the expression-based validation with messageExpression
91079112
marker.

0 commit comments

Comments
 (0)