Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion docs/testing/req.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ The tutorial assumes that you have no previous knowledge of Elasticsearch or gen

- Python development
- The [Flask](https://flask.palletsprojects.com/) web framework for Python.
- The command prompt or terminal application in your operating system.
- The command prompt or terminal application in your operating system.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@
{
@RenderProduct("", appliesTo.Product)
}
@if (appliesTo.ProductApplicability is not null)
{
var pa = appliesTo.ProductApplicability;
if (pa.Ecctl is not null) { @RenderProduct("ecctl", pa.Ecctl); }
if (pa.Curator is not null) { @RenderProduct("Curator", pa.Curator); }
if (pa.ApmAgentDotnet is not null) { @RenderProduct("APM Agent .NET", pa.ApmAgentDotnet); }
if (pa.ApmAgentGo is not null) { @RenderProduct("APM Agent Go", pa.ApmAgentGo); }
if (pa.ApmAgentJava is not null) { @RenderProduct("APM Agent Java", pa.ApmAgentJava); }
if (pa.ApmAgentNode is not null) { @RenderProduct("APM Agent Node.js", pa.ApmAgentNode); }
if (pa.ApmAgentPython is not null) { @RenderProduct("APM Agent Python", pa.ApmAgentPython); }
if (pa.ApmAgentRuby is not null) { @RenderProduct("APM Agent Ruby", pa.ApmAgentRuby); }
if (pa.ApmAgentRum is not null) { @RenderProduct("APM Agent RUM", pa.ApmAgentRum); }
if (pa.EdotIos is not null) { @RenderProduct("OpenTelemetry iOS", pa.EdotIos); }
if (pa.EdotAndroid is not null) { @RenderProduct("OpenTelemetry Android", pa.EdotAndroid); }
if (pa.EdotDotnet is not null) { @RenderProduct("OpenTelemetry .NET", pa.EdotDotnet); }
if (pa.EdotJava is not null) { @RenderProduct("OpenTelemetry Java", pa.EdotJava); }
if (pa.EdotNode is not null) { @RenderProduct("OpenTelemetry Node.js", pa.EdotNode); }
if (pa.EdotPhp is not null) { @RenderProduct("OpenTelemetry PHP", pa.EdotPhp); }
if (pa.EdotPython is not null) { @RenderProduct("OpenTelemetry Python", pa.EdotPython); }
Comment on lines +71 to +77
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@theletterf can you please suggest the correct display names here?

thank you 🙇

}

@functions {

Expand Down
249 changes: 219 additions & 30 deletions src/Elastic.Markdown/Myst/FrontMatter/ApplicableTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public record ApplicableTo
[YamlMember(Alias = "product")]
public AppliesCollection? Product { get; set; }

public ProductApplicability? ProductApplicability { get; set; }

internal YamlDiagnosticsCollection? Diagnostics { get; set; }

public static ApplicableTo All { get; } = new()
Expand Down Expand Up @@ -113,12 +115,69 @@ public record ServerlessProjectApplicability
};
}

[YamlSerializable]
public record ProductApplicability
{
[YamlMember(Alias = "ecctl")]
public AppliesCollection? Ecctl { get; set; }

[YamlMember(Alias = "curator")]
public AppliesCollection? Curator { get; set; }

[YamlMember(Alias = "apm_agent_dotnet")]
public AppliesCollection? ApmAgentDotnet { get; set; }

[YamlMember(Alias = "apm_agent_go")]
public AppliesCollection? ApmAgentGo { get; set; }

[YamlMember(Alias = "apm_agent_java")]
public AppliesCollection? ApmAgentJava { get; set; }

[YamlMember(Alias = "apm_agent_node")]
public AppliesCollection? ApmAgentNode { get; set; }

[YamlMember(Alias = "apm_agent_python")]
public AppliesCollection? ApmAgentPython { get; set; }

[YamlMember(Alias = "apm_agent_ruby")]
public AppliesCollection? ApmAgentRuby { get; set; }

[YamlMember(Alias = "apm_agent_rum")]
public AppliesCollection? ApmAgentRum { get; set; }

[YamlMember(Alias = "edot_ios")]
public AppliesCollection? EdotIos { get; set; }

[YamlMember(Alias = "edot_android")]
public AppliesCollection? EdotAndroid { get; set; }

[YamlMember(Alias = "edot_dotnet")]
public AppliesCollection? EdotDotnet { get; set; }

[YamlMember(Alias = "edot_java")]
public AppliesCollection? EdotJava { get; set; }

[YamlMember(Alias = "edot_node")]
public AppliesCollection? EdotNode { get; set; }

[YamlMember(Alias = "edot_php")]
public AppliesCollection? EdotPhp { get; set; }

[YamlMember(Alias = "edot_python")]
public AppliesCollection? EdotPython { get; set; }
}

public class ApplicableToConverter : IYamlTypeConverter
{
private static readonly string[] KnownKeys =
["stack", "deployment", "serverless", "product", "ece",
"eck", "ess", "self", "elasticsearch", "observability","security"
];
[
"stack", "deployment", "serverless", "product",
"ece", "eck", "ess", "self",
"elasticsearch", "observability", "security",
"ecctl", "curator",
"apm_agent_dotnet", "apm_agent_go", "apm_agent_java", "apm_agent_node", "apm_agent_python", "apm_agent_ruby", "apm_agent_rum",
"edot_ios", "edot_android", "edot_dotnet", "edot_java", "edot_node", "edot_php", "edot_python"
];

public bool Accepts(Type type) => type == typeof(ApplicableTo);

Expand Down Expand Up @@ -154,9 +213,7 @@ public class ApplicableToConverter : IYamlTypeConverter
if (TryGetApplicabilityOverTime(dictionary, "stack", diagnostics, out var stackAvailability))
applicableTo.Stack = stackAvailability;

if (TryGetApplicabilityOverTime(dictionary, "product", diagnostics, out var productAvailability))
applicableTo.Product = productAvailability;

AssignProduct(dictionary, applicableTo, diagnostics);
AssignServerless(dictionary, applicableTo, diagnostics);
AssignDeploymentType(dictionary, applicableTo, diagnostics);

Expand All @@ -166,6 +223,9 @@ public class ApplicableToConverter : IYamlTypeConverter
if (TryGetProjectApplicability(dictionary, diagnostics, out var serverless))
applicableTo.Serverless = serverless;

if (TryGetProductApplicability(dictionary, diagnostics, out var product))
applicableTo.ProductApplicability = product;

if (diagnostics.Count > 0)
applicableTo.Diagnostics = new YamlDiagnosticsCollection(diagnostics);
return applicableTo;
Expand Down Expand Up @@ -196,6 +256,48 @@ private static void AssignDeploymentType(Dictionary<object, object?> dictionary,
}
}

private static void AssignProduct(Dictionary<object, object?> dictionary, ApplicableTo applicableTo, List<(Severity, string)> diagnostics)
{
if (!dictionary.TryGetValue("product", out var productValue))
return;

// This handles string, null, and empty string cases.
if (productValue is not Dictionary<object, object?> productDictionary)
{
if (TryGetApplicabilityOverTime(dictionary, "product", diagnostics, out var productAvailability))
applicableTo.Product = productAvailability;
return;
}

// Handle dictionary case
if (TryGetProductApplicability(productDictionary, diagnostics, out var applicability))
applicableTo.ProductApplicability = applicability;
}

private static void AssignServerless(Dictionary<object, object?> dictionary, ApplicableTo applicableTo, List<(Severity, string)> diagnostics)
{
if (!dictionary.TryGetValue("serverless", out var serverless))
return;

if (serverless is null || (serverless is string s && string.IsNullOrWhiteSpace(s)))
applicableTo.Serverless = ServerlessProjectApplicability.All;
else if (serverless is string serverlessString)
{
var av = AppliesCollection.TryParse(serverlessString, diagnostics, out var a) ? a : null;
applicableTo.Serverless = new ServerlessProjectApplicability
{
Elasticsearch = av,
Observability = av,
Security = av
};
}
else if (serverless is Dictionary<object, object?> serverlessDictionary)
{
if (TryGetProjectApplicability(serverlessDictionary, diagnostics, out var applicability))
applicableTo.Serverless = applicability;
}
}

private static bool TryGetDeployment(Dictionary<object, object?> dictionary, List<(Severity, string)> diagnostics,
[NotNullWhen(true)] out DeploymentApplicability? applicability)
{
Expand All @@ -207,6 +309,7 @@ private static bool TryGetDeployment(Dictionary<object, object?> dictionary, Lis
d.Ece = ece;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "eck", diagnostics, out var eck))
{
d.Eck = eck;
Expand Down Expand Up @@ -234,30 +337,6 @@ private static bool TryGetDeployment(Dictionary<object, object?> dictionary, Lis
return false;
}

private static void AssignServerless(Dictionary<object, object?> dictionary, ApplicableTo applicableTo, List<(Severity, string)> diagnostics)
{
if (!dictionary.TryGetValue("serverless", out var serverless))
return;

if (serverless is null || (serverless is string s && string.IsNullOrWhiteSpace(s)))
applicableTo.Serverless = ServerlessProjectApplicability.All;
else if (serverless is string serverlessString)
{
var av = AppliesCollection.TryParse(serverlessString, diagnostics, out var a) ? a : null;
applicableTo.Serverless = new ServerlessProjectApplicability
{
Elasticsearch = av,
Observability = av,
Security = av
};
}
else if (serverless is Dictionary<object, object?> serverlessDictionary)
{
if (TryGetProjectApplicability(serverlessDictionary, diagnostics, out var applicability))
applicableTo.Serverless = applicability;
}
}

private static bool TryGetProjectApplicability(Dictionary<object, object?> dictionary,
List<(Severity, string)> diagnostics,
[NotNullWhen(true)] out ServerlessProjectApplicability? applicability)
Expand All @@ -270,6 +349,7 @@ private static bool TryGetProjectApplicability(Dictionary<object, object?> dicti
serverlessAvailability.Elasticsearch = elasticsearch;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "observability", diagnostics, out var observability))
{
serverlessAvailability.Observability = observability;
Expand All @@ -288,6 +368,115 @@ private static bool TryGetProjectApplicability(Dictionary<object, object?> dicti
return true;
}

private static bool TryGetProductApplicability(Dictionary<object, object?> dictionary,
List<(Severity, string)> diagnostics,
[NotNullWhen(true)] out ProductApplicability? applicability)
{
applicability = null;
var productAvailability = new ProductApplicability();
var assigned = false;
if (TryGetApplicabilityOverTime(dictionary, "ecctl", diagnostics, out var ecctl))
{
productAvailability.Ecctl = ecctl;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "curator", diagnostics, out var curator))
{
productAvailability.Curator = curator;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_dotnet", diagnostics, out var apmAgentDotnet))
{
productAvailability.ApmAgentDotnet = apmAgentDotnet;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_go", diagnostics, out var apmAgentGo))
{
productAvailability.ApmAgentGo = apmAgentGo;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_java", diagnostics, out var apmAgentJava))
{
productAvailability.ApmAgentJava = apmAgentJava;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_node", diagnostics, out var apmAgentNode))
{
productAvailability.ApmAgentNode = apmAgentNode;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_python", diagnostics, out var apmAgentPython))
{
productAvailability.ApmAgentPython = apmAgentPython;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_ruby", diagnostics, out var apmAgentRuby))
{
productAvailability.ApmAgentRuby = apmAgentRuby;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "apm_agent_rum", diagnostics, out var apmAgentRum))
{
productAvailability.ApmAgentRum = apmAgentRum;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_ios", diagnostics, out var edotIos))
{
productAvailability.EdotIos = edotIos;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_android", diagnostics, out var edotAndroid))
{
productAvailability.EdotAndroid = edotAndroid;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_dotnet", diagnostics, out var edotDotnet))
{
productAvailability.EdotDotnet = edotDotnet;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_java", diagnostics, out var edotJava))
{
productAvailability.EdotJava = edotJava;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_node", diagnostics, out var edotNode))
{
productAvailability.EdotNode = edotNode;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_php", diagnostics, out var edotPhp))
{
productAvailability.EdotPhp = edotPhp;
assigned = true;
}

if (TryGetApplicabilityOverTime(dictionary, "edot_python", diagnostics, out var edotPython))
{
productAvailability.EdotPython = edotPython;
assigned = true;
}

if (!assigned)
return false;
applicability = productAvailability;
return true;
}

private static bool TryGetApplicabilityOverTime(Dictionary<object, object?> dictionary, string key, List<(Severity, string)> diagnostics,
out AppliesCollection? availability)
{
Expand Down
6 changes: 6 additions & 0 deletions tests/authoring/Applicability/AppliesToDirective.fs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ serverless:
security: ga 9.0.0
elasticsearch: beta 9.1.0
observability: discontinued 9.2.0
apm_agent_dotnet: ga 9.0
apm_agent_node: ga 10.0
```
"""

Expand All @@ -54,6 +56,10 @@ serverless:
Security=AppliesCollection.op_Explicit "ga 9.0.0",
Elasticsearch=AppliesCollection.op_Explicit "beta 9.1.0",
Observability=AppliesCollection.op_Explicit "discontinued 9.2.0"
),
ProductApplicability=ProductApplicability(
ApmAgentDotnet=AppliesCollection.op_Explicit "ga 9.0",
ApmAgentNode=AppliesCollection.op_Explicit "ga 10.0"
)
))

Expand Down
8 changes: 7 additions & 1 deletion tests/authoring/Applicability/AppliesToFrontMatter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ applies_to:
elasticsearch: beta 9.1.0
observability: discontinued 9.2.0
product: preview 9.5, discontinued 9.7
apm_agent_dotnet: ga 9.0
ecctl: ga 10.0
stack: ga 9.1
"""
[<Fact>]
Expand All @@ -196,7 +198,11 @@ applies_to:
Observability=AppliesCollection.op_Explicit "discontinued 9.2.0"
),
Stack=AppliesCollection.op_Explicit "ga 9.1.0",
Product=AppliesCollection.op_Explicit "preview 9.5, discontinued 9.7"
Product=AppliesCollection.op_Explicit "preview 9.5, discontinued 9.7",
ProductApplicability=ProductApplicability(
ApmAgentDotnet=AppliesCollection.op_Explicit "ga 9.0",
Ecctl=AppliesCollection.op_Explicit "ga 10.0"
)
))

type ``parses empty applies_to as null`` () =
Expand Down
Loading