Skip to content
Merged
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
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