Skip to content

Commit 5e061d5

Browse files
authored
fix: Default to setting Nullable to null in CRD generation (#830)
Default to setting Nullable to null and only explicitly set it to true. This avoids generating `nullable: false` (the default for nullable) which causes issues in ArgoCD
1 parent f0eb626 commit 5e061d5

File tree

2 files changed

+53
-52
lines changed

2 files changed

+53
-52
lines changed

src/KubeOps.Transpiler/Crds.cs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,11 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, PropertyI
215215
props.Description ??= prop.GetCustomAttributeData<DescriptionAttribute>()
216216
?.GetCustomAttributeCtorArg<string>(context, 0);
217217

218-
props.Nullable = prop.IsNullable();
218+
if (prop.IsNullable())
219+
{
220+
// Default to Nullable to null to avoid generating `nullable:false`
221+
props.Nullable = true;
222+
}
219223

220224
if (prop.GetCustomAttributeData<ExternalDocsAttribute>() is { } extDocs)
221225
{
@@ -280,7 +284,7 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, Type type
280284
{
281285
if (type.FullName == "System.String")
282286
{
283-
return new V1JSONSchemaProps { Type = String, Nullable = false };
287+
return new V1JSONSchemaProps { Type = String };
284288
}
285289

286290
if (type.Name == typeof(Nullable<>).Name && type.GenericTypeArguments.Length == 1)
@@ -310,13 +314,12 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, Type type
310314
{
311315
Type = Object,
312316
AdditionalProperties = additionalProperties,
313-
Nullable = false,
314317
};
315318
}
316319

317320
if (interfaceNames.Contains(typeof(IDictionary).FullName))
318321
{
319-
return new V1JSONSchemaProps { Type = Object, XKubernetesPreserveUnknownFields = true, Nullable = false, };
322+
return new V1JSONSchemaProps { Type = Object, XKubernetesPreserveUnknownFields = true };
320323
}
321324

322325
if (interfaceNames.Contains(typeof(IEnumerable<>).FullName))
@@ -347,9 +350,9 @@ private static V1JSONSchemaProps MapObjectType(this MetadataLoadContext context,
347350
switch (type.FullName)
348351
{
349352
case "k8s.Models.V1ObjectMeta":
350-
return new V1JSONSchemaProps { Type = Object, Nullable = false };
353+
return new V1JSONSchemaProps { Type = Object };
351354
case "k8s.Models.IntstrIntOrString":
352-
return new V1JSONSchemaProps { XKubernetesIntOrString = true, Nullable = false };
355+
return new V1JSONSchemaProps { XKubernetesIntOrString = true };
353356
default:
354357
if (context.GetContextType<IKubernetesObject>().IsAssignableFrom(type) &&
355358
type is { IsAbstract: false, IsInterface: false } &&
@@ -361,7 +364,6 @@ private static V1JSONSchemaProps MapObjectType(this MetadataLoadContext context,
361364
Properties = null,
362365
XKubernetesPreserveUnknownFields = true,
363366
XKubernetesEmbeddedResource = true,
364-
Nullable = false,
365367
};
366368
}
367369

@@ -412,25 +414,24 @@ private static V1JSONSchemaProps MapEnumerationType(
412414
{
413415
Type = Object,
414416
AdditionalProperties = additionalProperties,
415-
Nullable = false,
416417
};
417418
}
418419

419420
var items = context.Map(listType);
420-
return new V1JSONSchemaProps { Type = Array, Items = items, Nullable = false };
421+
return new V1JSONSchemaProps { Type = Array, Items = items };
421422
}
422423

423424
private static V1JSONSchemaProps MapValueType(this MetadataLoadContext _, Type type) =>
424425
type.FullName switch
425426
{
426-
"System.Int32" => new V1JSONSchemaProps { Type = Integer, Format = Int32, Nullable = false },
427-
"System.Int64" => new V1JSONSchemaProps { Type = Integer, Format = Int64, Nullable = false },
428-
"System.Single" => new V1JSONSchemaProps { Type = Number, Format = Float, Nullable = false },
429-
"System.Double" => new V1JSONSchemaProps { Type = Number, Format = Double, Nullable = false },
430-
"System.Decimal" => new V1JSONSchemaProps { Type = Number, Format = Decimal, Nullable = false },
431-
"System.Boolean" => new V1JSONSchemaProps { Type = Boolean, Nullable = false },
432-
"System.DateTime" => new V1JSONSchemaProps { Type = String, Format = DateTime, Nullable = false },
433-
"System.DateTimeOffset" => new V1JSONSchemaProps { Type = String, Format = DateTime, Nullable = false },
427+
"System.Int32" => new V1JSONSchemaProps { Type = Integer, Format = Int32 },
428+
"System.Int64" => new V1JSONSchemaProps { Type = Integer, Format = Int64 },
429+
"System.Single" => new V1JSONSchemaProps { Type = Number, Format = Float },
430+
"System.Double" => new V1JSONSchemaProps { Type = Number, Format = Double },
431+
"System.Decimal" => new V1JSONSchemaProps { Type = Number, Format = Decimal },
432+
"System.Boolean" => new V1JSONSchemaProps { Type = Boolean },
433+
"System.DateTime" => new V1JSONSchemaProps { Type = String, Format = DateTime },
434+
"System.DateTimeOffset" => new V1JSONSchemaProps { Type = String, Format = DateTime },
434435
_ => throw InvalidType(type),
435436
};
436437

test/KubeOps.Transpiler.Test/Crds.Mlc.Test.cs

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,42 +14,42 @@ namespace KubeOps.Transpiler.Test;
1414
public class CrdsMlcTest(MlcProvider provider) : TranspilerTestBase(provider)
1515
{
1616
[Theory]
17-
[InlineData(typeof(StringTestEntity), "string", null, false)]
17+
[InlineData(typeof(StringTestEntity), "string", null, null)]
1818
[InlineData(typeof(NullableStringTestEntity), "string", null, true)]
19-
[InlineData(typeof(IntTestEntity), "integer", "int32", false)]
19+
[InlineData(typeof(IntTestEntity), "integer", "int32", null)]
2020
[InlineData(typeof(NullableIntTestEntity), "integer", "int32", true)]
21-
[InlineData(typeof(LongTestEntity), "integer", "int64", false)]
21+
[InlineData(typeof(LongTestEntity), "integer", "int64", null)]
2222
[InlineData(typeof(NullableLongTestEntity), "integer", "int64", true)]
23-
[InlineData(typeof(FloatTestEntity), "number", "float", false)]
23+
[InlineData(typeof(FloatTestEntity), "number", "float", null)]
2424
[InlineData(typeof(NullableFloatTestEntity), "number", "float", true)]
25-
[InlineData(typeof(DecimalTestEntity), "number", "decimal", false)]
25+
[InlineData(typeof(DecimalTestEntity), "number", "decimal", null)]
2626
[InlineData(typeof(NullableDecimalTestEntity), "number", "decimal", true)]
27-
[InlineData(typeof(DoubleTestEntity), "number", "double", false)]
27+
[InlineData(typeof(DoubleTestEntity), "number", "double", null)]
2828
[InlineData(typeof(NullableDoubleTestEntity), "number", "double", true)]
29-
[InlineData(typeof(BoolTestEntity), "boolean", null, false)]
29+
[InlineData(typeof(BoolTestEntity), "boolean", null, null)]
3030
[InlineData(typeof(NullableBoolTestEntity), "boolean", null, true)]
31-
[InlineData(typeof(DateTimeTestEntity), "string", "date-time", false)]
31+
[InlineData(typeof(DateTimeTestEntity), "string", "date-time", null)]
3232
[InlineData(typeof(NullableDateTimeTestEntity), "string", "date-time", true)]
33-
[InlineData(typeof(DateTimeOffsetTestEntity), "string", "date-time", false)]
33+
[InlineData(typeof(DateTimeOffsetTestEntity), "string", "date-time", null)]
3434
[InlineData(typeof(NullableDateTimeOffsetTestEntity), "string", "date-time", true)]
35-
[InlineData(typeof(V1ObjectMetaTestEntity), "object", null, false)]
36-
[InlineData(typeof(StringArrayEntity), "array", null, false)]
35+
[InlineData(typeof(V1ObjectMetaTestEntity), "object", null, null)]
36+
[InlineData(typeof(StringArrayEntity), "array", null, null)]
3737
[InlineData(typeof(NullableStringArrayEntity), "array", null, true)]
38-
[InlineData(typeof(EnumerableIntEntity), "array", null, false)]
39-
[InlineData(typeof(HashSetIntEntity), "array", null, false)]
40-
[InlineData(typeof(SetIntEntity), "array", null, false)]
41-
[InlineData(typeof(InheritedEnumerableEntity), "array", null, false)]
42-
[InlineData(typeof(EnumEntity), "string", null, false)]
38+
[InlineData(typeof(EnumerableIntEntity), "array", null, null)]
39+
[InlineData(typeof(HashSetIntEntity), "array", null, null)]
40+
[InlineData(typeof(SetIntEntity), "array", null, null)]
41+
[InlineData(typeof(InheritedEnumerableEntity), "array", null, null)]
42+
[InlineData(typeof(EnumEntity), "string", null, null)]
4343
[InlineData(typeof(NullableEnumEntity), "string", null, true)]
44-
[InlineData(typeof(DictionaryEntity), "object", null, false)]
45-
[InlineData(typeof(EnumerableKeyPairsEntity), "object", null, false)]
46-
[InlineData(typeof(IntstrOrStringEntity), null, null, false)]
47-
[InlineData(typeof(EmbeddedResourceEntity), "object", null, false)]
48-
[InlineData(typeof(EmbeddedCustomResourceEntity), "object", null, false)]
49-
[InlineData(typeof(EmbeddedCustomResourceGenericEntity), "object", null, false)]
50-
[InlineData(typeof(EmbeddedResourceListEntity), "array", null, false)]
44+
[InlineData(typeof(DictionaryEntity), "object", null, null)]
45+
[InlineData(typeof(EnumerableKeyPairsEntity), "object", null, null)]
46+
[InlineData(typeof(IntstrOrStringEntity), null, null, null)]
47+
[InlineData(typeof(EmbeddedResourceEntity), "object", null, null)]
48+
[InlineData(typeof(EmbeddedCustomResourceEntity), "object", null, null)]
49+
[InlineData(typeof(EmbeddedCustomResourceGenericEntity), "object", null, null)]
50+
[InlineData(typeof(EmbeddedResourceListEntity), "array", null, null)]
5151
public void Should_Transpile_Entity_Type_Correctly(Type type, string? expectedType, string? expectedFormat,
52-
bool isNullable)
52+
bool? isNullable)
5353
{
5454
var crd = _mlc.Transpile(type);
5555
var prop = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["property"];
@@ -59,15 +59,15 @@ public void Should_Transpile_Entity_Type_Correctly(Type type, string? expectedTy
5959
}
6060

6161
[Theory]
62-
[InlineData(typeof(StringArrayEntity), "string", false)]
63-
[InlineData(typeof(NullableStringArrayEntity), "string", false)]
64-
[InlineData(typeof(EnumerableIntEntity), "integer", false)]
62+
[InlineData(typeof(StringArrayEntity), "string", null)]
63+
[InlineData(typeof(NullableStringArrayEntity), "string", null)]
64+
[InlineData(typeof(EnumerableIntEntity), "integer", null)]
6565
[InlineData(typeof(EnumerableNullableIntEntity), "integer", true)]
66-
[InlineData(typeof(HashSetIntEntity), "integer", false)]
67-
[InlineData(typeof(SetIntEntity), "integer", false)]
68-
[InlineData(typeof(InheritedEnumerableEntity), "integer", false)]
69-
[InlineData(typeof(EmbeddedResourceListEntity), "object", false)]
70-
public void Should_Set_Correct_Array_Type(Type type, string expectedType, bool isNullable)
66+
[InlineData(typeof(HashSetIntEntity), "integer", null)]
67+
[InlineData(typeof(SetIntEntity), "integer", null)]
68+
[InlineData(typeof(InheritedEnumerableEntity), "integer", null)]
69+
[InlineData(typeof(EmbeddedResourceListEntity), "object", null)]
70+
public void Should_Set_Correct_Array_Type(Type type, string expectedType, bool? isNullable)
7171
{
7272
var crd = _mlc.Transpile(type);
7373
var prop = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["property"].Items as V1JSONSchemaProps;
@@ -76,9 +76,9 @@ public void Should_Set_Correct_Array_Type(Type type, string expectedType, bool i
7676
}
7777

7878
[Theory]
79-
[InlineData(typeof(DictionaryEntity), "string", false)]
80-
[InlineData(typeof(EnumerableKeyPairsEntity), "string", false)]
81-
public void Should_Set_Correct_Dictionary_Additional_Properties_Type(Type type, string expectedType, bool isNullable)
79+
[InlineData(typeof(DictionaryEntity), "string", null)]
80+
[InlineData(typeof(EnumerableKeyPairsEntity), "string", null)]
81+
public void Should_Set_Correct_Dictionary_Additional_Properties_Type(Type type, string expectedType, bool? isNullable)
8282
{
8383
var crd = _mlc.Transpile(type);
8484
var prop = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["property"].AdditionalProperties as V1JSONSchemaProps;

0 commit comments

Comments
 (0)