Skip to content

Commit 73e8dd7

Browse files
committed
Apply usage of VersionSpec in Applicability
1 parent 9abe711 commit 73e8dd7

File tree

16 files changed

+357
-182
lines changed

16 files changed

+357
-182
lines changed
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
`applies_to` accepts the following version formats:
22

3-
* `Major.Minor`
4-
* `Major.Minor.Patch`
3+
* **Greater than or equal to**: `x.x+`, `x.x`, `x.x.x+`, `x.x.x` (default behavior when no operator specified)
4+
* **Range (inclusive)**: `x.x-y.y`, `x.x.x-y.y.y`, `x.x-y.y.y`, `x.x.x-y.y`
5+
* **Exact version**: `=x.x`, `=x.x.x`
56

6-
Regardless of the version format used in the source file, the version number is always rendered in the `Major.Minor.Patch` format.
7+
**Version Display:**
8+
9+
- Versions are always displayed as **Major.Minor** (e.g., `9.1`) in badges, regardless of the format used in source files.
10+
- Each version represents the **latest patch** of that minor version (e.g., `9.1` means 9.1.0, 9.1.1, 9.1.6, etc.).
11+
- The `+` symbol indicates "this version and later" (e.g., `9.1+` means 9.1.0 and all subsequent releases).
12+
- Ranges show both versions (e.g., `9.0-9.2`) when both are released, or convert to `+` format if the end version is unreleased.
713

814
:::{note}
9-
**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.
15+
**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 9.1, beta 9.0, preview 8.18` will be displayed with the highest priority lifecycle and version first. Items without versions are sorted last.
1016
:::

docs/syntax/applies.md

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,41 @@ Where:
2929
- The lifecycle is mandatory.
3030
- The version is optional.
3131

32+
### Version Syntax
33+
34+
Versions can be specified using several formats to indicate different applicability scenarios:
35+
36+
| Description | Syntax | Example | Badge Display |
37+
|:------------|:-------|:--------|:--------------|
38+
| **Greater than or equal to** (default) | `x.x+` `x.x` `x.x.x+` `x.x.x` | `ga 9.1` or `ga 9.1+` | `9.1+` |
39+
| **Range** (inclusive) | `x.x-y.y` `x.x.x-y.y.y` | `preview 9.0-9.2` | `9.0-9.2` or `9.0+`* |
40+
| **Exact version** | `=x.x` `=x.x.x` | `beta =9.1` | `9.1` |
41+
42+
\* Range display depends on release status of the second version.
43+
44+
**Important notes:**
45+
46+
- Versions are always displayed as **Major.Minor** (e.g., `9.1`) in badges, regardless of whether you specify patch versions in the source.
47+
- Each version statement corresponds to the **latest patch** of the specified minor version (e.g., `9.1` represents 9.1.0, 9.1.1, 9.1.6, etc.).
48+
- When critical patch-level differences exist, use plain text descriptions alongside the badge rather than specifying patch versions.
49+
50+
### Version Validation Rules
51+
52+
The build process enforces the following validation rules:
53+
54+
- **One version per lifecycle**: Each lifecycle (GA, Preview, Beta, etc.) can only have one version declaration.
55+
-`stack: ga 9.2+, beta 9.0-9.1`
56+
-`stack: ga 9.2, ga 9.3`
57+
- **One "greater than" per key**: Only one lifecycle per product key can use the `+` (greater than or equal to) syntax.
58+
-`stack: ga 9.2+, beta 9.0-9.1`
59+
-`stack: ga 9.2+, beta 9.0+`
60+
- **Valid range order**: In ranges, the first version must be less than or equal to the second version.
61+
-`stack: preview 9.0-9.2`
62+
-`stack: preview 9.2-9.0`
63+
- **No version overlaps**: Versions for the same key cannot overlap (ranges are inclusive).
64+
-`stack: ga 9.2+, beta 9.0-9.1`
65+
-`stack: ga 9.2+, beta 9.0-9.2`
66+
3267
### Page level
3368

3469
Page level annotations are added in the YAML frontmatter, starting with the `applies_to` key and following the [key-value reference](#key-value-reference). For example:
@@ -134,6 +169,22 @@ Use the following key-value reference to find the appropriate key and value for
134169

135170
## Examples
136171

172+
### Version Syntax Examples
173+
174+
The following table demonstrates the various version syntax options and their rendered output:
175+
176+
| Source Syntax | Description | Badge Display | Notes |
177+
|:-------------|:------------|:--------------|:------|
178+
| `stack: ga 9.1` | Greater than or equal to 9.1 | `Stack│9.1+` | Default behavior, equivalent to `9.1+` |
179+
| `stack: ga 9.1+` | Explicit greater than or equal to | `Stack│9.1+` | Explicit `+` syntax |
180+
| `stack: preview 9.0-9.2` | Range from 9.0 to 9.2 (inclusive) | `Stack│Preview 9.0-9.2` | Shows range if 9.2.0 is released |
181+
| `stack: preview 9.0-9.3` | Range where end is unreleased | `Stack│Preview 9.0+` | Shows `+` if 9.3.0 is not released |
182+
| `stack: beta =9.1` | Exact version 9.1 only | `Stack│Beta 9.1` | No `+` symbol for exact versions |
183+
| `stack: ga 9.2+, beta 9.0-9.1` | Multiple lifecycles | `Stack│9.2+` | Only highest priority lifecycle shown |
184+
| `stack: ga 9.3, beta 9.1+` | Unreleased GA with Preview | `Stack│Beta 9.1+` | Shows Beta when GA unreleased with 2+ lifecycles |
185+
| `serverless: ga` | No version (base 99999) | `Serverless` | No version badge for unversioned products |
186+
| `deployment:`<br/>` ece: ga 9.0+` | Nested deployment syntax | `ECE│9.0+` | Deployment products shown separately |
187+
137188
### Versioning examples
138189

139190
Versioned products require a `version` tag to be used with the `lifecycle` tag:
@@ -240,22 +291,46 @@ applies_to:
240291

241292
## Look and feel
242293

294+
### Version Syntax Demonstrations
295+
296+
:::::{dropdown} New version syntax examples
297+
298+
The following examples demonstrate the new version syntax capabilities:
299+
300+
**Greater than or equal to:**
301+
- {applies_to}`stack: ga 9.1` (implicit `+`)
302+
- {applies_to}`stack: ga 9.1+` (explicit `+`)
303+
- {applies_to}`stack: preview 9.0+`
304+
305+
**Ranges:**
306+
- {applies_to}`stack: preview 9.0-9.2` (range display when both released)
307+
- {applies_to}`stack: beta 9.1-9.3` (converts to `+` if end unreleased)
308+
309+
**Exact versions:**
310+
- {applies_to}`stack: beta =9.1` (no `+` symbol)
311+
- {applies_to}`stack: deprecated =9.0`
312+
313+
**Multiple lifecycles:**
314+
- {applies_to}`stack: ga 9.2+, beta 9.0-9.1` (shows highest priority)
315+
316+
:::::
317+
243318
### Block
244319

245320
:::::{dropdown} Block examples
246321

247322
```{applies_to}
248-
stack: preview 9.1
323+
stack: preview 9.1+
249324
serverless: ga
250325
251-
apm_agent_dotnet: ga 1.0.0
252-
apm_agent_java: beta 1.0.0
253-
edot_dotnet: preview 1.0.0
326+
apm_agent_dotnet: ga 1.0+
327+
apm_agent_java: beta 1.0+
328+
edot_dotnet: preview 1.0+
254329
edot_python:
255-
edot_node: ga 1.0.0
256-
elasticsearch: preview 9.0.0
257-
security: removed 9.0.0
258-
observability: deprecated 9.0.0
330+
edot_node: ga 1.0+
331+
elasticsearch: preview 9.0+
332+
security: removed 9.0
333+
observability: deprecated 9.0+
259334
```
260335
:::::
261336

src/Elastic.ApiExplorer/Elasticsearch/OpenApiDocumentExporter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ private bool ShouldIncludeOperation(OpenApiOperation operation, string product)
209209
return true; // Could not parse version, safe to include
210210

211211
// Get current version for the product
212-
var versioningSystemId = product == "elasticsearch"
212+
var versioningSystemId = product.Equals("elasticsearch", StringComparison.OrdinalIgnoreCase)
213213
? VersioningSystemId.Stack
214214
: VersioningSystemId.Stack; // Both use Stack for now
215215

@@ -294,14 +294,14 @@ private static ProductLifecycle ParseLifecycle(string stateValue)
294294
/// <summary>
295295
/// Parses the version from "Added in X.Y.Z" pattern in the x-state string.
296296
/// </summary>
297-
private static SemVersion? ParseVersion(string stateValue)
297+
private static VersionSpec? ParseVersion(string stateValue)
298298
{
299299
var match = AddedInVersionRegex().Match(stateValue);
300300
if (!match.Success)
301301
return null;
302302

303303
var versionString = match.Groups[1].Value;
304-
return SemVersion.TryParse(versionString, out var version) ? version : null;
304+
return VersionSpec.TryParse(versionString, out var version) ? version : null;
305305
}
306306

307307
/// <summary>

src/Elastic.Documentation/AppliesTo/Applicability.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static bool TryParse(string? value, IList<(Severity, string)> diagnostics
3838
return false;
3939

4040
// Sort by version in descending order (the highest version first)
41-
// Items without versions (AllVersions.Instance) are sorted last
41+
// Items without versions (AllVersionsSpec.Instance) are sorted last
4242
var sortedApplications = applications.OrderDescending().ToArray();
4343
availability = new AppliesCollection(sortedApplications);
4444
return true;
@@ -98,12 +98,12 @@ public override string ToString()
9898
public record Applicability : IComparable<Applicability>, IComparable
9999
{
100100
public ProductLifecycle Lifecycle { get; init; }
101-
public SemVersion? Version { get; init; }
101+
public VersionSpec? Version { get; init; }
102102

103103
public static Applicability GenerallyAvailable { get; } = new()
104104
{
105105
Lifecycle = ProductLifecycle.GenerallyAvailable,
106-
Version = AllVersions.Instance
106+
Version = AllVersionsSpec.Instance
107107
};
108108

109109

@@ -126,8 +126,8 @@ public string GetLifeCycleName() =>
126126
/// <inheritdoc />
127127
public int CompareTo(Applicability? other)
128128
{
129-
var xIsNonVersioned = Version is null || ReferenceEquals(Version, AllVersions.Instance);
130-
var yIsNonVersioned = other?.Version is null || ReferenceEquals(other.Version, AllVersions.Instance);
129+
var xIsNonVersioned = Version is null || ReferenceEquals(Version, AllVersionsSpec.Instance);
130+
var yIsNonVersioned = other?.Version is null || ReferenceEquals(other.Version, AllVersionsSpec.Instance);
131131

132132
if (xIsNonVersioned && yIsNonVersioned)
133133
return 0;
@@ -158,7 +158,7 @@ public override string ToString()
158158
_ => throw new ArgumentOutOfRangeException()
159159
};
160160
_ = sb.Append(lifecycle);
161-
if (Version is not null && Version != AllVersions.Instance)
161+
if (Version is not null && Version != AllVersionsSpec.Instance)
162162
_ = sb.Append(' ').Append(Version);
163163
return sb.ToString();
164164
}
@@ -224,10 +224,10 @@ public static bool TryParse(string? value, IList<(Severity, string)> diagnostics
224224
? null
225225
: tokens[1] switch
226226
{
227-
null => AllVersions.Instance,
228-
"all" => AllVersions.Instance,
229-
"" => AllVersions.Instance,
230-
var t => SemVersionConverter.TryParse(t, out var v) ? v : null
227+
null => AllVersionsSpec.Instance,
228+
"all" => AllVersionsSpec.Instance,
229+
"" => AllVersionsSpec.Instance,
230+
var t => VersionSpec.TryParse(t, out var v) ? v : null
231231
};
232232
availability = new Applicability { Version = version, Lifecycle = lifecycle };
233233
return true;

src/Elastic.Documentation/AppliesTo/ApplicabilitySelector.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,27 @@ public static Applicability GetPrimaryApplicability(IEnumerable<Applicability> a
3030
};
3131

3232
var availableApplicabilities = applicabilityList
33-
.Where(a => a.Version is null || a.Version is AllVersions || a.Version <= currentVersion)
33+
.Where(a => a.Version is null || a.Version is AllVersionsSpec ||
34+
(a.Version is VersionSpec vs && vs.Min <= currentVersion))
3435
.ToList();
3536

3637
if (availableApplicabilities.Count != 0)
3738
{
3839
return availableApplicabilities
39-
.OrderByDescending(a => a.Version ?? new SemVersion(0, 0, 0))
40+
.OrderByDescending(a => a.Version?.Min ?? new SemVersion(0, 0, 0))
4041
.ThenBy(a => lifecycleOrder.GetValueOrDefault(a.Lifecycle, 999))
4142
.First();
4243
}
4344

4445
var futureApplicabilities = applicabilityList
45-
.Where(a => a.Version is not null && a.Version is not AllVersions && a.Version > currentVersion)
46+
.Where(a => a.Version is not null && a.Version is not AllVersionsSpec &&
47+
a.Version is VersionSpec vs && vs.Min > currentVersion)
4648
.ToList();
4749

4850
if (futureApplicabilities.Count != 0)
4951
{
5052
return futureApplicabilities
51-
.OrderBy(a => a.Version!.CompareTo(currentVersion))
53+
.OrderBy(a => a.Version!.Min.CompareTo(currentVersion))
5254
.ThenBy(a => lifecycleOrder.GetValueOrDefault(a.Lifecycle, 999))
5355
.First();
5456
}

src/Elastic.Documentation/AppliesTo/ApplicableTo.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ public record ApplicableTo
6464
Product = AppliesCollection.GenerallyAvailable
6565
};
6666

67+
private static readonly VersionSpec DefaultVersion = VersionSpec.TryParse("9.0", out var v) ? v! : AllVersionsSpec.Instance;
68+
6769
public static ApplicableTo Default { get; } = new()
6870
{
69-
Stack = new AppliesCollection([new Applicability { Version = new SemVersion(9, 0, 0), Lifecycle = ProductLifecycle.GenerallyAvailable }]),
71+
Stack = new AppliesCollection([new Applicability { Version = DefaultVersion, Lifecycle = ProductLifecycle.GenerallyAvailable }]),
7072
Serverless = ServerlessProjectApplicability.All
7173
};
7274

src/Elastic.Documentation/AppliesTo/ApplicableToJsonConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class ApplicableToJsonConverter : JsonConverter<ApplicableTo>
4444
string? type = null;
4545
string? subType = null;
4646
var lifecycle = ProductLifecycle.GenerallyAvailable;
47-
SemVersion? version = null;
47+
VersionSpec? version = null;
4848

4949
while (reader.Read())
5050
{
@@ -72,7 +72,7 @@ public class ApplicableToJsonConverter : JsonConverter<ApplicableTo>
7272
break;
7373
case "version":
7474
var versionStr = reader.GetString();
75-
if (versionStr != null && SemVersionConverter.TryParse(versionStr, out var v))
75+
if (versionStr != null && VersionSpecConverter.TryParse(versionStr, out var v))
7676
version = v;
7777
break;
7878
}

0 commit comments

Comments
 (0)