Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions src/KubernetesClient/KubernetesYaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ public static string Serialize(object value)
private static TBuilder WithOverridesFromJsonPropertyAttributes<TBuilder>(this TBuilder builder)
where TBuilder : BuilderSkeleton<TBuilder>
{
var preferredPropertyOrder = new[] { "ApiVersion", "Kind", "Metadata" };
// Use VersionInfo from the model namespace as that should be stable.
// If this is not generated in the future we will get an obvious compiler error.
var targetNamespace = typeof(VersionInfo).Namespace;
Expand All @@ -307,15 +308,39 @@ private static TBuilder WithOverridesFromJsonPropertyAttributes<TBuilder>(this T
// Map any JsonPropertyAttribute instances to YamlMemberAttribute instances.
foreach (var type in types)
{
foreach (var property in type.GetProperties())
var properties = type.GetProperties()
.OrderBy(property => property.MetadataToken)
.ToArray();
var usePreferredOrder = properties.Any(property =>
property.Name == "ApiVersion" ||
property.Name == "Kind");
var nextOrder = usePreferredOrder ? preferredPropertyOrder.Length : 0;
foreach (var property in properties)
{
var jsonAttribute = property.GetCustomAttribute<JsonPropertyNameAttribute>();
if (jsonAttribute == null)
if (jsonAttribute == null && !usePreferredOrder)
{
continue;
}

var yamlAttribute = new YamlMemberAttribute { Alias = jsonAttribute.Name, ApplyNamingConventions = false };
var yamlAttribute = new YamlMemberAttribute();
if (usePreferredOrder)
{
var order = Array.IndexOf(preferredPropertyOrder, property.Name);
if (order < 0)
{
order = nextOrder++;
}

yamlAttribute.Order = order;
}

if (jsonAttribute != null)
{
yamlAttribute.Alias = jsonAttribute.Name;
yamlAttribute.ApplyNamingConventions = false;
}

builder.WithAttributeOverride(type, property.Name, yamlAttribute);
}
}
Expand Down
34 changes: 28 additions & 6 deletions tests/KubernetesClient.Tests/KubernetesYamlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -822,12 +822,12 @@ public void WriteSecret()
{
var kManifest = """
apiVersion: v1
data:
username: YlhrdFlYQnc=
password: TXprMU1qZ2tkbVJuTjBwaQ==
kind: Secret
metadata:
name: test-secret
data:
username: YlhrdFlYQnc=
password: TXprMU1qZ2tkbVJuTjBwaQ==
""";

var result = KubernetesYaml.Deserialize<V1Secret>(kManifest, true);
Expand Down Expand Up @@ -860,13 +860,13 @@ public void WriteConfigMap()
{
var kManifest = """
apiVersion: v1
kind: ConfigMap
metadata:
name: test-configmap
binaryData:
username: YlhrdFlYQnc=
data:
password: Mzk1MjgkdmRnN0pi
kind: ConfigMap
metadata:
name: test-configmap
""";

var result = KubernetesYaml.Deserialize<V1ConfigMap>(kManifest, true);
Expand All @@ -875,6 +875,28 @@ public void WriteConfigMap()
Assert.Equal(kManifest, yaml);
}

[Fact]
public void WriteConfigMapOrdersTypeMetaFirst()
{
var configMap = new V1ConfigMap
{
ApiVersion = "v1",
Kind = "ConfigMap",
Metadata = new V1ObjectMeta { Name = "my-configmap", NamespaceProperty = "my-namespace" },
Data = new Dictionary<string, string> { { "array.json", "value" } },
};

var yaml = KubernetesYaml.Serialize(configMap);

Assert.Equal(ToLines(@"apiVersion: v1
kind: ConfigMap
metadata:
name: my-configmap
namespace: my-namespace
data:
array.json: value"), ToLines(yaml));
}

[Fact]
public void DeserializeWithJsonPropertyName()
{
Expand Down