Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using Elastic.Documentation.AppliesTo;
using Elastic.Documentation.Configuration.LegacyUrlMappings;
using Elastic.Documentation.Configuration.Products;

namespace Elastic.Documentation.Configuration.Versions;

public interface IVersionInferrerService
{
VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<LegacyPageMapping>? legacyPages);
VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<LegacyPageMapping>? legacyPages, IReadOnlyCollection<Product>? products, ApplicableTo? applicableTo);
}

public class ProductVersionInferrerService(ProductsConfiguration productsConfiguration, VersionsConfiguration versionsConfiguration) : IVersionInferrerService
{
private ProductsConfiguration ProductsConfiguration { get; } = productsConfiguration;
private VersionsConfiguration VersionsConfiguration { get; } = versionsConfiguration;
public VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<LegacyPageMapping>? legacyPages)
public VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<LegacyPageMapping>? legacyPages, IReadOnlyCollection<Product>? products, ApplicableTo? applicableTo)
{
var versioning = legacyPages is not null && legacyPages.Count > 0
? legacyPages.ElementAt(0).Product.VersioningSystem! // If the page has a legacy page mapping, use the versioning system of the legacy page
: ProductsConfiguration.Products.TryGetValue(repositoryName, out var belonging)
if (legacyPages is { Count: > 0 })
return legacyPages.ElementAt(0).Product.VersioningSystem!; // If the page has legacy mappings, use the versioning system of the first mapping's product

if (applicableTo is not null)
{
var versioningFromApplicability = VersioningFromApplicability(applicableTo); // Try to infer the versioning system from the applicability metadata
if (versioningFromApplicability is not null)
return versioningFromApplicability;
}

var versioning = ProductsConfiguration.Products.TryGetValue(repositoryName, out var belonging)
? belonging.VersioningSystem! //If the page's docset has a name with a direct product match, use the versioning system of the product
: ProductsConfiguration.Products.Values.SingleOrDefault(p =>
p.Repository is not null && p.Repository.Equals(repositoryName, StringComparison.OrdinalIgnoreCase)) is { } repositoryMatch
Expand All @@ -29,11 +38,62 @@ public VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<

return versioning;
}

private VersioningSystem? VersioningFromApplicability(ApplicableTo applicableTo)
{
// Priority 1: Product applicability
var product = ProductFromApplicability(applicableTo.ProductApplicability);
if (product?.VersioningSystem is not null)
return product.VersioningSystem;

// Priority 2: Stack applicability
if (applicableTo.Stack is not null)
return VersionsConfiguration.VersioningSystems[VersioningSystemId.Stack];
// Priority 3: Deployment applicability
if (applicableTo.Deployment is not null)
{
var versioning = applicableTo.Deployment switch
{
{ Ece: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.Ece],
{ Eck: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.Eck],
{ Ess: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.Ess],
{ Self: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.Self],
_ => null
};
if (versioning is not null)
return versioning;
}

// Priority 4: Serverless applicability
if (applicableTo.Serverless is not null)
{
var versioning = applicableTo.Serverless switch
{
{ Elasticsearch: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.ElasticsearchProject],
{ Observability: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.ObservabilityProject],
{ Security: not null } => VersionsConfiguration.VersioningSystems[VersioningSystemId.SecurityProject],
_ => null
};
if (versioning is not null)
return versioning;
}

return null;
}
private Product? ProductFromApplicability(ProductApplicability? productApplicability)
{
if (productApplicability is null)
return null;

var productId = ProductApplicabilityConversion.ProductApplicabilityToProductId(productApplicability);

return productId is null ? null : ProductsConfiguration.Products.GetValueOrDefault(productId);
}
}

public class NoopVersionInferrer : IVersionInferrerService
{
public VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<LegacyPageMapping>? legacyPages) => new()
public VersioningSystem InferVersion(string repositoryName, IReadOnlyCollection<LegacyPageMapping>? legacyPages, IReadOnlyCollection<Product>? products, ApplicableTo? applicableTo) => new()
{
Id = VersioningSystemId.Stack,
Base = new SemVersion(0, 0, 0),
Expand Down
116 changes: 0 additions & 116 deletions src/Elastic.Documentation/AppliesTo/ApplicableTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,119 +236,3 @@ public override string ToString()
return sb.ToString();
}
}

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

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

[YamlMember(Alias = "apm-agent-android")]
public AppliesCollection? ApmAgentAndroid { 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-ios")]
public AppliesCollection? ApmAgentIos { 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-php")]
public AppliesCollection? ApmAgentPhp { 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-js")]
public AppliesCollection? ApmAgentRumJs { 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; }

[YamlMember(Alias = "edot-cf-aws")]
public AppliesCollection? EdotCfAws { get; set; }

[YamlMember(Alias = "edot-cf-azure")]
public AppliesCollection? EdotCfAzure { get; set; }

[YamlMember(Alias = "edot-cf-gcp")]
public AppliesCollection? EdotCfGcp { get; set; }

[YamlMember(Alias = "edot-collector")]
public AppliesCollection? EdotCollector { get; set; }

/// <inheritdoc />
public override string ToString()
{
var sb = new StringBuilder();
var hasContent = false;

void AppendProduct(string name, AppliesCollection? value)
{
if (value is null)
return;
if (hasContent)
_ = sb.Append(", ");
_ = sb.Append(name).Append('=').Append(value);
hasContent = true;
}

AppendProduct("ecctl", Ecctl);
AppendProduct("curator", Curator);
AppendProduct("apm-agent-android", ApmAgentAndroid);
AppendProduct("apm-agent-dotnet", ApmAgentDotnet);
AppendProduct("apm-agent-go", ApmAgentGo);
AppendProduct("apm-agent-ios", ApmAgentIos);
AppendProduct("apm-agent-java", ApmAgentJava);
AppendProduct("apm-agent-node", ApmAgentNode);
AppendProduct("apm-agent-php", ApmAgentPhp);
AppendProduct("apm-agent-python", ApmAgentPython);
AppendProduct("apm-agent-ruby", ApmAgentRuby);
AppendProduct("apm-agent-rum-js", ApmAgentRumJs);
AppendProduct("edot-ios", EdotIos);
AppendProduct("edot-android", EdotAndroid);
AppendProduct("edot-dotnet", EdotDotnet);
AppendProduct("edot-java", EdotJava);
AppendProduct("edot-node", EdotNode);
AppendProduct("edot-php", EdotPhp);
AppendProduct("edot-python", EdotPython);
AppendProduct("edot-cf-aws", EdotCfAws);
AppendProduct("edot-cf-azure", EdotCfAzure);
AppendProduct("edot-cf-gcp", EdotCfGcp);
AppendProduct("edot-collector", EdotCollector);

return sb.ToString();
}
}
155 changes: 155 additions & 0 deletions src/Elastic.Documentation/AppliesTo/ProductApplicability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Text;
using YamlDotNet.Serialization;

namespace Elastic.Documentation.AppliesTo;

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

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

[YamlMember(Alias = "apm-agent-android")]
public AppliesCollection? ApmAgentAndroid { 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-ios")]
public AppliesCollection? ApmAgentIos { 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-php")]
public AppliesCollection? ApmAgentPhp { 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-js")]
public AppliesCollection? ApmAgentRumJs { 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; }

[YamlMember(Alias = "edot-cf-aws")]
public AppliesCollection? EdotCfAws { get; set; }

[YamlMember(Alias = "edot-cf-azure")]
public AppliesCollection? EdotCfAzure { get; set; }

[YamlMember(Alias = "edot-cf-gcp")]
public AppliesCollection? EdotCfGcp { get; set; }

[YamlMember(Alias = "edot-collector")]
public AppliesCollection? EdotCollector { get; set; }

/// <inheritdoc />
public override string ToString()
{
var sb = new StringBuilder();
var hasContent = false;

void AppendProduct(string name, AppliesCollection? value)
{
if (value is null)
return;
if (hasContent)
_ = sb.Append(": not null } => ");
_ = sb.Append(name).Append('=').Append(value);
hasContent = true;
}

AppendProduct("ecctl", Ecctl);
AppendProduct("curator", Curator);
AppendProduct("apm-agent-android", ApmAgentAndroid);
AppendProduct("apm-agent-dotnet", ApmAgentDotnet);
AppendProduct("apm-agent-go", ApmAgentGo);
AppendProduct("apm-agent-ios", ApmAgentIos);
AppendProduct("apm-agent-java", ApmAgentJava);
AppendProduct("apm-agent-node", ApmAgentNode);
AppendProduct("apm-agent-php", ApmAgentPhp);
AppendProduct("apm-agent-python", ApmAgentPython);
AppendProduct("apm-agent-ruby", ApmAgentRuby);
AppendProduct("apm-agent-rum-js", ApmAgentRumJs);
AppendProduct("edot-ios", EdotIos);
AppendProduct("edot-android", EdotAndroid);
AppendProduct("edot-dotnet", EdotDotnet);
AppendProduct("edot-java", EdotJava);
AppendProduct("edot-node", EdotNode);
AppendProduct("edot-php", EdotPhp);
AppendProduct("edot-python", EdotPython);
AppendProduct("edot-cf-aws", EdotCfAws);
AppendProduct("edot-cf-azure", EdotCfAzure);
AppendProduct("edot-cf-gcp", EdotCfGcp);
AppendProduct("edot-collector", EdotCollector);

return sb.ToString();
}
}

public static class ProductApplicabilityConversion
{
public static string? ProductApplicabilityToProductId(ProductApplicability p) => p switch
{
{ Ecctl: not null } => "cloud-control-ecctl",
{ Curator: not null } => "curator",
{ ApmAgentAndroid: not null } => "edot-android",
{ ApmAgentDotnet: not null } => "apm-agent-dotnet",
{ ApmAgentGo: not null } => "apm-agent-go",
{ ApmAgentIos: not null } => "edot-ios",
{ ApmAgentJava: not null } => "apm-agent-java",
{ ApmAgentNode: not null } => "apm-agent-node",
{ ApmAgentPhp: not null } => "apm-agent-php",
{ ApmAgentPython: not null } => "apm-agent-python",
{ ApmAgentRuby: not null } => "apm-agent-ruby",
{ ApmAgentRumJs: not null } => "apm-agent-rum-js",
{ EdotIos: not null } => "edot-ios",
{ EdotAndroid: not null } => "edot-android",
{ EdotDotnet: not null } => "edot-dotnet",
{ EdotJava: not null } => "edot-java",
{ EdotNode: not null } => "edot-node",
{ EdotPhp: not null } => "edot-php",
{ EdotPython: not null } => "edot-python",
{ EdotCfAws: not null } => "edot-cf-aws",
{ EdotCfAzure: not null } => "edot-cf-azure",
{ EdotCfGcp: not null } => "edot-cf-gcp",
{ EdotCollector: not null } => "edot-collector",
_ => null
};
}
3 changes: 2 additions & 1 deletion src/Elastic.Markdown/HtmlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private async Task<RenderResult> RenderLayout(MarkdownFile markdown, MarkdownDoc

}

var pageVersioning = VersionInferrerService.InferVersion(DocumentationSet.Context.Git.RepositoryName, legacyPages);
var pageVersioning = VersionInferrerService.InferVersion(DocumentationSet.Context.Git.RepositoryName, legacyPages, markdown.YamlFrontMatter?.Products, markdown.YamlFrontMatter?.AppliesTo);

var currentBaseVersion = $"{pageVersioning.Base.Major}.{pageVersioning.Base.Minor}+";

Expand Down Expand Up @@ -154,6 +154,7 @@ private async Task<RenderResult> RenderLayout(MarkdownFile markdown, MarkdownDoc
LegacyPages = legacyPages?.ToArray(),
VersionDropdownItems = VersionDropDownItemViewModel.FromLegacyPageMappings(legacyPages?.ToArray()),
Products = pageProducts,
VersioningSystem = pageVersioning,
VersionsConfig = DocumentationSet.Context.VersionsConfiguration,
StructuredBreadcrumbsJson = structuredBreadcrumbsJsonString
});
Expand Down
Loading
Loading