Skip to content

Commit

Permalink
fix: Default to setting Nullable to null in CRD generation (#830)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gamingrobot authored Jan 6, 2025
1 parent f0eb626 commit 5e061d5
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 52 deletions.
35 changes: 18 additions & 17 deletions src/KubeOps.Transpiler/Crds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, PropertyI
props.Description ??= prop.GetCustomAttributeData<DescriptionAttribute>()
?.GetCustomAttributeCtorArg<string>(context, 0);

props.Nullable = prop.IsNullable();
if (prop.IsNullable())
{
// Default to Nullable to null to avoid generating `nullable:false`
props.Nullable = true;
}

if (prop.GetCustomAttributeData<ExternalDocsAttribute>() is { } extDocs)
{
Expand Down Expand Up @@ -280,7 +284,7 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, Type type
{
if (type.FullName == "System.String")
{
return new V1JSONSchemaProps { Type = String, Nullable = false };
return new V1JSONSchemaProps { Type = String };
}

if (type.Name == typeof(Nullable<>).Name && type.GenericTypeArguments.Length == 1)
Expand Down Expand Up @@ -310,13 +314,12 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, Type type
{
Type = Object,
AdditionalProperties = additionalProperties,
Nullable = false,
};
}

if (interfaceNames.Contains(typeof(IDictionary).FullName))
{
return new V1JSONSchemaProps { Type = Object, XKubernetesPreserveUnknownFields = true, Nullable = false, };
return new V1JSONSchemaProps { Type = Object, XKubernetesPreserveUnknownFields = true };
}

if (interfaceNames.Contains(typeof(IEnumerable<>).FullName))
Expand Down Expand Up @@ -347,9 +350,9 @@ private static V1JSONSchemaProps MapObjectType(this MetadataLoadContext context,
switch (type.FullName)
{
case "k8s.Models.V1ObjectMeta":
return new V1JSONSchemaProps { Type = Object, Nullable = false };
return new V1JSONSchemaProps { Type = Object };
case "k8s.Models.IntstrIntOrString":
return new V1JSONSchemaProps { XKubernetesIntOrString = true, Nullable = false };
return new V1JSONSchemaProps { XKubernetesIntOrString = true };
default:
if (context.GetContextType<IKubernetesObject>().IsAssignableFrom(type) &&
type is { IsAbstract: false, IsInterface: false } &&
Expand All @@ -361,7 +364,6 @@ private static V1JSONSchemaProps MapObjectType(this MetadataLoadContext context,
Properties = null,
XKubernetesPreserveUnknownFields = true,
XKubernetesEmbeddedResource = true,
Nullable = false,
};
}

Expand Down Expand Up @@ -412,25 +414,24 @@ private static V1JSONSchemaProps MapEnumerationType(
{
Type = Object,
AdditionalProperties = additionalProperties,
Nullable = false,
};
}

var items = context.Map(listType);
return new V1JSONSchemaProps { Type = Array, Items = items, Nullable = false };
return new V1JSONSchemaProps { Type = Array, Items = items };
}

private static V1JSONSchemaProps MapValueType(this MetadataLoadContext _, Type type) =>
type.FullName switch
{
"System.Int32" => new V1JSONSchemaProps { Type = Integer, Format = Int32, Nullable = false },
"System.Int64" => new V1JSONSchemaProps { Type = Integer, Format = Int64, Nullable = false },
"System.Single" => new V1JSONSchemaProps { Type = Number, Format = Float, Nullable = false },
"System.Double" => new V1JSONSchemaProps { Type = Number, Format = Double, Nullable = false },
"System.Decimal" => new V1JSONSchemaProps { Type = Number, Format = Decimal, Nullable = false },
"System.Boolean" => new V1JSONSchemaProps { Type = Boolean, Nullable = false },
"System.DateTime" => new V1JSONSchemaProps { Type = String, Format = DateTime, Nullable = false },
"System.DateTimeOffset" => new V1JSONSchemaProps { Type = String, Format = DateTime, Nullable = false },
"System.Int32" => new V1JSONSchemaProps { Type = Integer, Format = Int32 },
"System.Int64" => new V1JSONSchemaProps { Type = Integer, Format = Int64 },
"System.Single" => new V1JSONSchemaProps { Type = Number, Format = Float },
"System.Double" => new V1JSONSchemaProps { Type = Number, Format = Double },
"System.Decimal" => new V1JSONSchemaProps { Type = Number, Format = Decimal },
"System.Boolean" => new V1JSONSchemaProps { Type = Boolean },
"System.DateTime" => new V1JSONSchemaProps { Type = String, Format = DateTime },
"System.DateTimeOffset" => new V1JSONSchemaProps { Type = String, Format = DateTime },
_ => throw InvalidType(type),
};

Expand Down
70 changes: 35 additions & 35 deletions test/KubeOps.Transpiler.Test/Crds.Mlc.Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,42 @@ namespace KubeOps.Transpiler.Test;
public class CrdsMlcTest(MlcProvider provider) : TranspilerTestBase(provider)
{
[Theory]
[InlineData(typeof(StringTestEntity), "string", null, false)]
[InlineData(typeof(StringTestEntity), "string", null, null)]
[InlineData(typeof(NullableStringTestEntity), "string", null, true)]
[InlineData(typeof(IntTestEntity), "integer", "int32", false)]
[InlineData(typeof(IntTestEntity), "integer", "int32", null)]
[InlineData(typeof(NullableIntTestEntity), "integer", "int32", true)]
[InlineData(typeof(LongTestEntity), "integer", "int64", false)]
[InlineData(typeof(LongTestEntity), "integer", "int64", null)]
[InlineData(typeof(NullableLongTestEntity), "integer", "int64", true)]
[InlineData(typeof(FloatTestEntity), "number", "float", false)]
[InlineData(typeof(FloatTestEntity), "number", "float", null)]
[InlineData(typeof(NullableFloatTestEntity), "number", "float", true)]
[InlineData(typeof(DecimalTestEntity), "number", "decimal", false)]
[InlineData(typeof(DecimalTestEntity), "number", "decimal", null)]
[InlineData(typeof(NullableDecimalTestEntity), "number", "decimal", true)]
[InlineData(typeof(DoubleTestEntity), "number", "double", false)]
[InlineData(typeof(DoubleTestEntity), "number", "double", null)]
[InlineData(typeof(NullableDoubleTestEntity), "number", "double", true)]
[InlineData(typeof(BoolTestEntity), "boolean", null, false)]
[InlineData(typeof(BoolTestEntity), "boolean", null, null)]
[InlineData(typeof(NullableBoolTestEntity), "boolean", null, true)]
[InlineData(typeof(DateTimeTestEntity), "string", "date-time", false)]
[InlineData(typeof(DateTimeTestEntity), "string", "date-time", null)]
[InlineData(typeof(NullableDateTimeTestEntity), "string", "date-time", true)]
[InlineData(typeof(DateTimeOffsetTestEntity), "string", "date-time", false)]
[InlineData(typeof(DateTimeOffsetTestEntity), "string", "date-time", null)]
[InlineData(typeof(NullableDateTimeOffsetTestEntity), "string", "date-time", true)]
[InlineData(typeof(V1ObjectMetaTestEntity), "object", null, false)]
[InlineData(typeof(StringArrayEntity), "array", null, false)]
[InlineData(typeof(V1ObjectMetaTestEntity), "object", null, null)]
[InlineData(typeof(StringArrayEntity), "array", null, null)]
[InlineData(typeof(NullableStringArrayEntity), "array", null, true)]
[InlineData(typeof(EnumerableIntEntity), "array", null, false)]
[InlineData(typeof(HashSetIntEntity), "array", null, false)]
[InlineData(typeof(SetIntEntity), "array", null, false)]
[InlineData(typeof(InheritedEnumerableEntity), "array", null, false)]
[InlineData(typeof(EnumEntity), "string", null, false)]
[InlineData(typeof(EnumerableIntEntity), "array", null, null)]
[InlineData(typeof(HashSetIntEntity), "array", null, null)]
[InlineData(typeof(SetIntEntity), "array", null, null)]
[InlineData(typeof(InheritedEnumerableEntity), "array", null, null)]
[InlineData(typeof(EnumEntity), "string", null, null)]
[InlineData(typeof(NullableEnumEntity), "string", null, true)]
[InlineData(typeof(DictionaryEntity), "object", null, false)]
[InlineData(typeof(EnumerableKeyPairsEntity), "object", null, false)]
[InlineData(typeof(IntstrOrStringEntity), null, null, false)]
[InlineData(typeof(EmbeddedResourceEntity), "object", null, false)]
[InlineData(typeof(EmbeddedCustomResourceEntity), "object", null, false)]
[InlineData(typeof(EmbeddedCustomResourceGenericEntity), "object", null, false)]
[InlineData(typeof(EmbeddedResourceListEntity), "array", null, false)]
[InlineData(typeof(DictionaryEntity), "object", null, null)]
[InlineData(typeof(EnumerableKeyPairsEntity), "object", null, null)]
[InlineData(typeof(IntstrOrStringEntity), null, null, null)]
[InlineData(typeof(EmbeddedResourceEntity), "object", null, null)]
[InlineData(typeof(EmbeddedCustomResourceEntity), "object", null, null)]
[InlineData(typeof(EmbeddedCustomResourceGenericEntity), "object", null, null)]
[InlineData(typeof(EmbeddedResourceListEntity), "array", null, null)]
public void Should_Transpile_Entity_Type_Correctly(Type type, string? expectedType, string? expectedFormat,
bool isNullable)
bool? isNullable)
{
var crd = _mlc.Transpile(type);
var prop = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["property"];
Expand All @@ -59,15 +59,15 @@ public void Should_Transpile_Entity_Type_Correctly(Type type, string? expectedTy
}

[Theory]
[InlineData(typeof(StringArrayEntity), "string", false)]
[InlineData(typeof(NullableStringArrayEntity), "string", false)]
[InlineData(typeof(EnumerableIntEntity), "integer", false)]
[InlineData(typeof(StringArrayEntity), "string", null)]
[InlineData(typeof(NullableStringArrayEntity), "string", null)]
[InlineData(typeof(EnumerableIntEntity), "integer", null)]
[InlineData(typeof(EnumerableNullableIntEntity), "integer", true)]
[InlineData(typeof(HashSetIntEntity), "integer", false)]
[InlineData(typeof(SetIntEntity), "integer", false)]
[InlineData(typeof(InheritedEnumerableEntity), "integer", false)]
[InlineData(typeof(EmbeddedResourceListEntity), "object", false)]
public void Should_Set_Correct_Array_Type(Type type, string expectedType, bool isNullable)
[InlineData(typeof(HashSetIntEntity), "integer", null)]
[InlineData(typeof(SetIntEntity), "integer", null)]
[InlineData(typeof(InheritedEnumerableEntity), "integer", null)]
[InlineData(typeof(EmbeddedResourceListEntity), "object", null)]
public void Should_Set_Correct_Array_Type(Type type, string expectedType, bool? isNullable)
{
var crd = _mlc.Transpile(type);
var prop = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["property"].Items as V1JSONSchemaProps;
Expand All @@ -76,9 +76,9 @@ public void Should_Set_Correct_Array_Type(Type type, string expectedType, bool i
}

[Theory]
[InlineData(typeof(DictionaryEntity), "string", false)]
[InlineData(typeof(EnumerableKeyPairsEntity), "string", false)]
public void Should_Set_Correct_Dictionary_Additional_Properties_Type(Type type, string expectedType, bool isNullable)
[InlineData(typeof(DictionaryEntity), "string", null)]
[InlineData(typeof(EnumerableKeyPairsEntity), "string", null)]
public void Should_Set_Correct_Dictionary_Additional_Properties_Type(Type type, string expectedType, bool? isNullable)
{
var crd = _mlc.Transpile(type);
var prop = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["property"].AdditionalProperties as V1JSONSchemaProps;
Expand Down

0 comments on commit 5e061d5

Please sign in to comment.