Skip to content

Commit 59f51e8

Browse files
bmorelli25Mpdreamz
andauthored
Add automatic applies_to version sorting (#1726)
* add automatic version sorting Signed-off-by: bmorelli25 <[email protected]> * Clean up * add more complex test case Signed-off-by: bmorelli25 <[email protected]> * Implement `IComparable` for `Applicability` and update sorting logic * Simplify sorting logic in `Applicability` by using `OrderDescending()` method. --------- Signed-off-by: bmorelli25 <[email protected]> Co-authored-by: Martijn Laarman <[email protected]>
1 parent 89934b3 commit 59f51e8

File tree

6 files changed

+153
-16
lines changed

6 files changed

+153
-16
lines changed

docs/syntax/applies.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ Where:
7070
- The [version](#version) is optional
7171
- You can specify multiple states by separating them with a comma. For example: `stack: preview 9.1, ga 9.4`
7272

73+
:::{note}
74+
**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.
75+
:::
76+
7377
Note that a key without any value doesn't show any badge in the output.
7478

7579
### Lifecycle

src/Elastic.Documentation/AppliesTo/AllVersions.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@
88

99
namespace Elastic.Documentation.AppliesTo;
1010

11-
public class AllVersions() : SemVersion(9999, 9999, 9999)
12-
{
13-
public static AllVersions Instance { get; } = new();
14-
}
15-
1611
public class SemVersionConverter : IYamlTypeConverter
1712
{
1813
public bool Accepts(Type type) => type == typeof(SemVersion);

src/Elastic.Documentation/AppliesTo/Applicability.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ public static bool TryParse(string? value, IList<(Severity, string)> diagnostics
3737
if (applications.Count == 0)
3838
return false;
3939

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

@@ -92,7 +95,7 @@ public override string ToString()
9295
}
9396

9497
[YamlSerializable]
95-
public record Applicability
98+
public record Applicability : IComparable<Applicability>, IComparable
9699
{
97100
public ProductLifecycle Lifecycle { get; init; }
98101
public SemVersion? Version { get; init; }
@@ -120,6 +123,22 @@ public string GetLifeCycleName() =>
120123
};
121124

122125

126+
/// <inheritdoc />
127+
public int CompareTo(Applicability? other)
128+
{
129+
var xIsNonVersioned = Version is null || ReferenceEquals(Version, AllVersions.Instance);
130+
var yIsNonVersioned = other?.Version is null || ReferenceEquals(other.Version, AllVersions.Instance);
131+
132+
if (xIsNonVersioned && yIsNonVersioned)
133+
return 0;
134+
if (xIsNonVersioned)
135+
return -1; // Non-versioned items sort last
136+
if (yIsNonVersioned)
137+
return 1; // Non-versioned items sort last
138+
139+
return Version!.CompareTo(other!.Version);
140+
}
141+
123142
public override string ToString()
124143
{
125144
if (this == GenerallyAvailable)
@@ -144,6 +163,9 @@ public override string ToString()
144163
return sb.ToString();
145164
}
146165

166+
/// <inheritdoc />
167+
public int CompareTo(object? obj) => CompareTo(obj as Applicability);
168+
147169
public static explicit operator Applicability(string b)
148170
{
149171
var diagnostics = new List<(Severity, string)>();
@@ -210,4 +232,13 @@ public static bool TryParse(string? value, IList<(Severity, string)> diagnostics
210232
availability = new Applicability { Version = version, Lifecycle = lifecycle };
211233
return true;
212234
}
235+
236+
public static bool operator <(Applicability? left, Applicability? right) => left is null ? right is not null : left.CompareTo(right) < 0;
237+
238+
public static bool operator <=(Applicability? left, Applicability? right) => left is null || left.CompareTo(right) <= 0;
239+
240+
public static bool operator >(Applicability? left, Applicability? right) => left is not null && left.CompareTo(right) > 0;
241+
242+
public static bool operator >=(Applicability? left, Applicability? right) => left is null ? right is null : left.CompareTo(right) >= 0;
213243
}
244+

src/Elastic.Documentation/SemVersion.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
namespace Elastic.Documentation;
1010

11+
public class AllVersions() : SemVersion(9999, 9999, 9999)
12+
{
13+
public static AllVersions Instance { get; } = new();
14+
}
15+
1116
/// <summary>
1217
/// A semver2 compatible version.
1318
/// </summary>

tests/authoring/Applicability/AppliesToFrontMatter.fs

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module ``product availability``.``yaml frontmatter``
66

77
open Elastic.Documentation.AppliesTo
88
open JetBrains.Annotations
9+
open Swensen.Unquote
910
open Xunit
1011
open authoring
1112
open authoring.MarkdownDocumentAssertions
@@ -163,8 +164,8 @@ applies_to:
163164
let ``apply matches expected`` () =
164165
markdown |> appliesTo (ApplicableTo(
165166
Product=AppliesCollection([
166-
Applicability.op_Explicit "preview 9.5";
167-
Applicability.op_Explicit "removed 9.7"
167+
Applicability.op_Explicit "removed 9.7";
168+
Applicability.op_Explicit "preview 9.5"
168169
] |> Array.ofList)
169170
))
170171

@@ -212,3 +213,104 @@ applies_to:
212213
[<Fact>]
213214
let ``does not render label`` () =
214215
markdown |> appliesTo (Unchecked.defaultof<ApplicableTo>)
216+
217+
type ``sorts applies_to versions in descending order`` () =
218+
static let markdown = frontMatter """
219+
applies_to:
220+
stack: preview 8.18.6, ga 9.2, beta 9.1, preview 9.0.6
221+
"""
222+
[<Fact>]
223+
let ``versions are sorted highest to lowest`` () =
224+
let expectedVersions = [
225+
Applicability.op_Explicit "ga 9.2"
226+
Applicability.op_Explicit "beta 9.1"
227+
Applicability.op_Explicit "preview 9.0.6"
228+
Applicability.op_Explicit "preview 8.18.6"
229+
]
230+
markdown |> appliesTo (ApplicableTo(
231+
Stack=AppliesCollection(expectedVersions |> Array.ofList)
232+
))
233+
234+
type ``sorts ga before all`` () =
235+
static let markdown = frontMatter """
236+
applies_to:
237+
stack: ga, all
238+
"""
239+
[<Fact>]
240+
let ``versioned items are sorted first, non-versioned items last`` () =
241+
let expectedVersions = [
242+
Applicability.op_Explicit "ga"
243+
Applicability.op_Explicit "all"
244+
]
245+
markdown |> appliesTo (ApplicableTo(
246+
Stack=AppliesCollection(expectedVersions |> Array.ofList)
247+
))
248+
249+
type ``applicability comparisons`` () =
250+
[<Fact>]
251+
let ``equals`` () =
252+
test <@ Applicability.op_Explicit "ga" = Applicability.op_Explicit "ga" @>
253+
254+
[<Fact>]
255+
let ``not equals`` () =
256+
test <@ Applicability.op_Explicit "ga" <> Applicability.op_Explicit "all" @>
257+
258+
[<Fact>]
259+
let ``any version beats no version`` () =
260+
test <@ Applicability.op_Explicit "ga 8.1.0" > Applicability.op_Explicit "ga" @>
261+
test <@ Applicability.op_Explicit "all" < Applicability.op_Explicit "ga 8.1.0" @>
262+
263+
[<Fact>]
264+
let ``comparison on version number only`` () =
265+
test <@ Applicability.op_Explicit "ga 8.1.0" < Applicability.op_Explicit "beta 8.2.0" @>
266+
test <@ Applicability.op_Explicit "beta 8.1.0-beta" < Applicability.op_Explicit "beta 8.1.0" @>
267+
268+
269+
type ``sorts applies_to with mixed versioned and non-versioned items`` () =
270+
static let markdown = frontMatter """
271+
applies_to:
272+
stack: ga 8.18.6, ga, ga 9.1.2, all, ga 8.19.2
273+
"""
274+
[<Fact>]
275+
let ``versioned items are sorted first, non-versioned items last`` () =
276+
let expectedVersions = [
277+
Applicability.op_Explicit "ga 9.1.2"
278+
Applicability.op_Explicit "ga 8.19.2"
279+
Applicability.op_Explicit "ga 8.18.6"
280+
Applicability.op_Explicit "ga"
281+
Applicability.op_Explicit "all"
282+
]
283+
markdown |> appliesTo (ApplicableTo(
284+
Stack=AppliesCollection(expectedVersions |> Array.ofList)
285+
))
286+
287+
type ``sorts applies_to with patch versions correctly`` () =
288+
static let markdown = frontMatter """
289+
applies_to:
290+
stack: ga 9.1, ga 9.1.1, ga 9.0.5
291+
"""
292+
[<Fact>]
293+
let ``patch versions are sorted correctly`` () =
294+
let expectedVersions = [
295+
Applicability.op_Explicit "ga 9.1.1"
296+
Applicability.op_Explicit "ga 9.1"
297+
Applicability.op_Explicit "ga 9.0.5"
298+
]
299+
markdown |> appliesTo (ApplicableTo(
300+
Stack=AppliesCollection(expectedVersions |> Array.ofList)
301+
))
302+
303+
type ``sorts applies_to with major versions correctly`` () =
304+
static let markdown = frontMatter """
305+
applies_to:
306+
stack: ga 3.x, ga 5.x
307+
"""
308+
[<Fact>]
309+
let ``major versions are sorted correctly`` () =
310+
let expectedVersions = [
311+
Applicability.op_Explicit "ga 5.x"
312+
Applicability.op_Explicit "ga 3.x"
313+
]
314+
markdown |> appliesTo (ApplicableTo(
315+
Stack=AppliesCollection(expectedVersions |> Array.ofList)
316+
))

tests/authoring/Inline/AppliesToRole.fs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ This is an inline {applies_to}`stack: preview 9.0, ga 9.1` element.
133133
let directives = markdown |> converts "index.md" |> parses<AppliesToRole>
134134
test <@ directives.Length = 1 @>
135135
directives |> appliesToDirective (ApplicableTo(
136-
Stack=AppliesCollection.op_Explicit "preview 9.0, ga 9.1"
136+
Stack=AppliesCollection.op_Explicit "ga 9.1, preview 9.0"
137137
))
138138

139139
[<Fact>]
@@ -143,20 +143,20 @@ This is an inline {applies_to}`stack: preview 9.0, ga 9.1` element.
143143
<span class="applies applies-inline">
144144
<span class="applicable-info" data-tippy-content="We plan to add this functionality in a future Elastic&nbsp;Stack update. Subject to change.
145145
146-
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.">
146+
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.">
147147
<span class="applicable-name">Stack</span>
148148
<span class="applicable-separator"></span>
149-
<span class="applicable-meta applicable-meta-preview">
150-
Planned
149+
<span class="applicable-meta applicable-meta-ga">
150+
GA planned
151151
</span>
152152
</span>
153153
<span class="applicable-info" data-tippy-content="We plan to add this functionality in a future Elastic&nbsp;Stack update. Subject to change.
154154
155-
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.">
155+
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.">
156156
<span class="applicable-name">Stack</span>
157157
<span class="applicable-separator"></span>
158-
<span class="applicable-meta applicable-meta-ga">
159-
GA planned
158+
<span class="applicable-meta applicable-meta-preview">
159+
Planned
160160
</span>
161161
</span>
162162
</span>

0 commit comments

Comments
 (0)