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
4 changes: 4 additions & 0 deletions docs/syntax/applies.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
- The [version](#version) is optional
- You can specify multiple states by separating them with a comma. For example: `stack: preview 9.1, ga 9.4`

:::{note}
**Automatic Version Sorting**: When you specify multiple versions for the same product, the build system automatically sorts them in descending order (highest version first) regardless of the order you write them in the source file. For example, `stack: ga 8.18.6, ga 9.1.2, ga 8.19.2, ga 9.0.6` will be displayed as `stack: ga 9.1.2, ga 9.0.6, ga 8.19.2, ga 8.18.6`. Items without versions (like `ga` without a version or `all`) are sorted last.
:::

Note that a key without any value doesn't show any badge in the output.

### Lifecycle
Expand Down Expand Up @@ -252,7 +256,7 @@

### Block

```{applies_to}

Check notice on line 259 in docs/syntax/applies.md

View workflow job for this annotation

GitHub Actions / build

The 'planned' lifecycle is deprecated and will be removed in a future release.
stack: preview 9.1
serverless: planned

Expand Down
5 changes: 0 additions & 5 deletions src/Elastic.Documentation/AppliesTo/AllVersions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@

namespace Elastic.Documentation.AppliesTo;

public class AllVersions() : SemVersion(9999, 9999, 9999)
{
public static AllVersions Instance { get; } = new();
}

public class SemVersionConverter : IYamlTypeConverter
{
public bool Accepts(Type type) => type == typeof(SemVersion);
Expand Down
35 changes: 33 additions & 2 deletions src/Elastic.Documentation/AppliesTo/Applicability.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ public static bool TryParse(string? value, IList<(Severity, string)> diagnostics
if (applications.Count == 0)
return false;

availability = new AppliesCollection([.. applications]);
// Sort by version in descending order (the highest version first)
// Items without versions (AllVersions.Instance) are sorted last
var sortedApplications = applications.OrderDescending().ToArray();
availability = new AppliesCollection(sortedApplications);
return true;
}

Expand Down Expand Up @@ -92,7 +95,7 @@ public override string ToString()
}

[YamlSerializable]
public record Applicability
public record Applicability : IComparable<Applicability>, IComparable
{
public ProductLifecycle Lifecycle { get; init; }
public SemVersion? Version { get; init; }
Expand Down Expand Up @@ -120,6 +123,22 @@ public string GetLifeCycleName() =>
};


/// <inheritdoc />
public int CompareTo(Applicability? other)
{
var xIsNonVersioned = Version is null || ReferenceEquals(Version, AllVersions.Instance);
var yIsNonVersioned = other?.Version is null || ReferenceEquals(other.Version, AllVersions.Instance);

if (xIsNonVersioned && yIsNonVersioned)
return 0;
if (xIsNonVersioned)
return -1; // Non-versioned items sort last
if (yIsNonVersioned)
return 1; // Non-versioned items sort last

return Version!.CompareTo(other!.Version);
}

public override string ToString()
{
if (this == GenerallyAvailable)
Expand All @@ -144,6 +163,9 @@ public override string ToString()
return sb.ToString();
}

/// <inheritdoc />
public int CompareTo(object? obj) => CompareTo(obj as Applicability);

public static explicit operator Applicability(string b)
{
var diagnostics = new List<(Severity, string)>();
Expand Down Expand Up @@ -210,4 +232,13 @@ public static bool TryParse(string? value, IList<(Severity, string)> diagnostics
availability = new Applicability { Version = version, Lifecycle = lifecycle };
return true;
}

public static bool operator <(Applicability? left, Applicability? right) => left is null ? right is not null : left.CompareTo(right) < 0;

public static bool operator <=(Applicability? left, Applicability? right) => left is null || left.CompareTo(right) <= 0;

public static bool operator >(Applicability? left, Applicability? right) => left is not null && left.CompareTo(right) > 0;

public static bool operator >=(Applicability? left, Applicability? right) => left is null ? right is null : left.CompareTo(right) >= 0;
}

5 changes: 5 additions & 0 deletions src/Elastic.Documentation/SemVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

namespace Elastic.Documentation;

public class AllVersions() : SemVersion(9999, 9999, 9999)
{
public static AllVersions Instance { get; } = new();
}

/// <summary>
/// A semver2 compatible version.
/// </summary>
Expand Down
106 changes: 104 additions & 2 deletions tests/authoring/Applicability/AppliesToFrontMatter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module ``product availability``.``yaml frontmatter``

open Elastic.Documentation.AppliesTo
open JetBrains.Annotations
open Swensen.Unquote
open Xunit
open authoring
open authoring.MarkdownDocumentAssertions
Expand Down Expand Up @@ -163,8 +164,8 @@ applies_to:
let ``apply matches expected`` () =
markdown |> appliesTo (ApplicableTo(
Product=AppliesCollection([
Applicability.op_Explicit "preview 9.5";
Applicability.op_Explicit "removed 9.7"
Applicability.op_Explicit "removed 9.7";
Applicability.op_Explicit "preview 9.5"
] |> Array.ofList)
))

Expand Down Expand Up @@ -212,3 +213,104 @@ applies_to:
[<Fact>]
let ``does not render label`` () =
markdown |> appliesTo (Unchecked.defaultof<ApplicableTo>)

type ``sorts applies_to versions in descending order`` () =
static let markdown = frontMatter """
applies_to:
stack: preview 8.18.6, ga 9.2, beta 9.1, preview 9.0.6
"""
[<Fact>]
let ``versions are sorted highest to lowest`` () =
let expectedVersions = [
Applicability.op_Explicit "ga 9.2"
Applicability.op_Explicit "beta 9.1"
Applicability.op_Explicit "preview 9.0.6"
Applicability.op_Explicit "preview 8.18.6"
]
markdown |> appliesTo (ApplicableTo(
Stack=AppliesCollection(expectedVersions |> Array.ofList)
))

type ``sorts ga before all`` () =
static let markdown = frontMatter """
applies_to:
stack: ga, all
"""
[<Fact>]
let ``versioned items are sorted first, non-versioned items last`` () =
let expectedVersions = [
Applicability.op_Explicit "ga"
Applicability.op_Explicit "all"
]
markdown |> appliesTo (ApplicableTo(
Stack=AppliesCollection(expectedVersions |> Array.ofList)
))

type ``applicability comparisons`` () =
[<Fact>]
let ``equals`` () =
test <@ Applicability.op_Explicit "ga" = Applicability.op_Explicit "ga" @>

[<Fact>]
let ``not equals`` () =
test <@ Applicability.op_Explicit "ga" <> Applicability.op_Explicit "all" @>

[<Fact>]
let ``any version beats no version`` () =
test <@ Applicability.op_Explicit "ga 8.1.0" > Applicability.op_Explicit "ga" @>
test <@ Applicability.op_Explicit "all" < Applicability.op_Explicit "ga 8.1.0" @>

[<Fact>]
let ``comparison on version number only`` () =
test <@ Applicability.op_Explicit "ga 8.1.0" < Applicability.op_Explicit "beta 8.2.0" @>
test <@ Applicability.op_Explicit "beta 8.1.0-beta" < Applicability.op_Explicit "beta 8.1.0" @>


type ``sorts applies_to with mixed versioned and non-versioned items`` () =
static let markdown = frontMatter """
applies_to:
stack: ga 8.18.6, ga, ga 9.1.2, all, ga 8.19.2
"""
[<Fact>]
let ``versioned items are sorted first, non-versioned items last`` () =
let expectedVersions = [
Applicability.op_Explicit "ga 9.1.2"
Applicability.op_Explicit "ga 8.19.2"
Applicability.op_Explicit "ga 8.18.6"
Applicability.op_Explicit "ga"
Applicability.op_Explicit "all"
]
markdown |> appliesTo (ApplicableTo(
Stack=AppliesCollection(expectedVersions |> Array.ofList)
))

type ``sorts applies_to with patch versions correctly`` () =
static let markdown = frontMatter """
applies_to:
stack: ga 9.1, ga 9.1.1, ga 9.0.5
"""
[<Fact>]
let ``patch versions are sorted correctly`` () =
let expectedVersions = [
Applicability.op_Explicit "ga 9.1.1"
Applicability.op_Explicit "ga 9.1"
Applicability.op_Explicit "ga 9.0.5"
]
markdown |> appliesTo (ApplicableTo(
Stack=AppliesCollection(expectedVersions |> Array.ofList)
))

type ``sorts applies_to with major versions correctly`` () =
static let markdown = frontMatter """
applies_to:
stack: ga 3.x, ga 5.x
"""
[<Fact>]
let ``major versions are sorted correctly`` () =
let expectedVersions = [
Applicability.op_Explicit "ga 5.x"
Applicability.op_Explicit "ga 3.x"
]
markdown |> appliesTo (ApplicableTo(
Stack=AppliesCollection(expectedVersions |> Array.ofList)
))
14 changes: 7 additions & 7 deletions tests/authoring/Inline/AppliesToRole.fs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ This is an inline {applies_to}`stack: preview 9.0, ga 9.1` element.
let directives = markdown |> converts "index.md" |> parses<AppliesToRole>
test <@ directives.Length = 1 @>
directives |> appliesToDirective (ApplicableTo(
Stack=AppliesCollection.op_Explicit "preview 9.0, ga 9.1"
Stack=AppliesCollection.op_Explicit "ga 9.1, preview 9.0"
))

[<Fact>]
Expand All @@ -143,20 +143,20 @@ This is an inline {applies_to}`stack: preview 9.0, ga 9.1` element.
<span class="applies applies-inline">
<span class="applicable-info" data-tippy-content="We plan to add this functionality in a future Elastic&nbsp;Stack update. Subject to change.

This functionality may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.">
If this functionality is unavailable or behaves differently when deployed on ECH, ECE, ECK, or a self-managed installation, it will be indicated on the page.">
<span class="applicable-name">Stack</span>
<span class="applicable-separator"></span>
<span class="applicable-meta applicable-meta-preview">
Planned
<span class="applicable-meta applicable-meta-ga">
GA planned
</span>
</span>
<span class="applicable-info" data-tippy-content="We plan to add this functionality in a future Elastic&nbsp;Stack update. Subject to change.

If this functionality is unavailable or behaves differently when deployed on ECH, ECE, ECK, or a self-managed installation, it will be indicated on the page.">
This functionality may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.">
<span class="applicable-name">Stack</span>
<span class="applicable-separator"></span>
<span class="applicable-meta applicable-meta-ga">
GA planned
<span class="applicable-meta applicable-meta-preview">
Planned
</span>
</span>
</span>
Expand Down
Loading