Skip to content

Update applicability lifecycles to match versioning RFC #1393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 20, 2025
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 .github/workflows/preview-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ jobs:
with:
prefix: ${{ env.PATH_PREFIX }}
strict: ${{ fromJSON(inputs.strict != '' && inputs.strict || 'true') }}
metadata-only: ${{ fromJSON(inputs.metadata-only != '' && inputs.metadata-only || 'true') }}
metadata-only: ${{ fromJSON(inputs.metadata-only != '' && inputs.metadata-only || 'false') }}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matches the default value on the inputs, was confusing to read true even though this always defaults to false.


- name: 'Validate inbound links'
if: |
Expand Down
14 changes: 6 additions & 8 deletions docs/syntax/applies.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ applies_to:
security: ga 9.0.0
elasticsearch: beta 9.1.0
observability: discontinued 9.2.0
product: planned 9.5, discontinued 9.7
product: preview 9.5, discontinued 9.7
---

# Applies to
Expand All @@ -28,12 +28,10 @@ Taking a mandatory [life-cycle](#life-cycle) with an optional version.
#### Life cycle:
* `preview`
* `beta`
* `development`
* `ga`
* `deprecated`
* `planned`
* `discontinued`
* `removed`
* `unavailable`
* `ga`

#### Version

Expand All @@ -42,7 +40,7 @@ Can be in either `major.minor` or `major.minor.patch` format
#### Examples

```
planned 9.5, discontinued 9.7
preview 9.5, discontinued 9.7
discontinued 9.2.0
all
```
Expand Down Expand Up @@ -107,7 +105,7 @@ applies_to:
security: ga 9.0.0
elasticsearch: beta 9.1.0
observability: discontinued 9.2.0
product: planned 9.5, discontinued 9.7
product: preview 9.5, discontinued 9.7
---
```

Expand All @@ -125,7 +123,7 @@ serverless:
security: ga 9.0.0
elasticsearch: beta 9.1.0
observability: discontinued 9.2.0
product: planned 9.5, discontinued 9.7
product: preview 9.5, discontinued 9.7
```

A header may be followed by an `{applies_to}` directive which will contextualize the applicability
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public void Write(Diagnostic diagnostic)
Channel.Write(diagnostic);
}

private void Emit(Severity severity, string file, string message) =>
public void Emit(Severity severity, string file, string message) =>
Write(new Diagnostic
{
Severity = severity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public interface IDiagnosticsCollector : IAsyncDisposable
HashSet<string> OffendingFiles { get; }
ConcurrentDictionary<string, bool> InUseSubstitutionKeys { get; }

void Emit(Severity severity, string file, string message);
void EmitError(string file, string message, Exception? e = null);
void EmitWarning(string file, string message);
void EmitHint(string file, string message);
Expand All @@ -27,6 +28,10 @@ public interface IDiagnosticsCollector : IAsyncDisposable

public static class DiagnosticsCollectorExtensions
{

public static void Emit(this IDiagnosticsCollector collector, Severity severity, IFileInfo file, string message) =>
collector.Emit(severity, file.FullName, message);

public static void EmitError(this IDiagnosticsCollector collector, IFileInfo file, string message, Exception? e = null) =>
collector.EmitError(file.FullName, message, e);

Expand Down
22 changes: 11 additions & 11 deletions src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ public static void EmitWarning(this ParserContext context, int line, int column,
context.Build.Collector.Write(d);
}

public static void EmitError(this IBlockExtension block, string message, Exception? e = null) => EmitDiagnostic(block, Severity.Error, message, e);
public static void EmitError(this IBlockExtension block, string message, Exception? e = null) => Emit(block, Severity.Error, message, e);

public static void EmitWarning(this IBlockExtension block, string message) => EmitDiagnostic(block, Severity.Warning, message);
public static void EmitWarning(this IBlockExtension block, string message) => Emit(block, Severity.Warning, message);

public static void EmitHint(this IBlockExtension block, string message) => EmitDiagnostic(block, Severity.Hint, message);
public static void EmitHint(this IBlockExtension block, string message) => Emit(block, Severity.Hint, message);

private static void EmitDiagnostic(IBlockExtension block, Severity severity, string message, Exception? e = null)
public static void Emit(this IBlockExtension block, Severity severity, string message, Exception? e = null)
{
if (block.SkipValidation)
return;
Expand All @@ -102,7 +102,7 @@ private static void EmitDiagnostic(IBlockExtension block, Severity severity, str
}


private static void LinkDiagnostic(InlineProcessor processor, Severity severity, Inline inline, int length, string message, Exception? e = null)
public static void Emit(this InlineProcessor processor, Severity severity, Inline inline, int length, string message, Exception? e = null)
{
var line = inline.Line + 1;
var column = inline.Column;
Expand All @@ -123,20 +123,20 @@ private static void LinkDiagnostic(InlineProcessor processor, Severity severity,
}

public static void EmitError(this InlineProcessor processor, LinkInline inline, string message) =>
LinkDiagnostic(processor, Severity.Error, inline, inline.Url?.Length ?? 1, message);
Emit(processor, Severity.Error, inline, inline.Url?.Length ?? 1, message);

public static void EmitWarning(this InlineProcessor processor, LinkInline inline, string message) =>
LinkDiagnostic(processor, Severity.Warning, inline, inline.Url?.Length ?? 1, message);
Emit(processor, Severity.Warning, inline, inline.Url?.Length ?? 1, message);

public static void EmitHint(this InlineProcessor processor, LinkInline inline, string message) =>
LinkDiagnostic(processor, Severity.Hint, inline, inline.Url?.Length ?? 1, message);
Emit(processor, Severity.Hint, inline, inline.Url?.Length ?? 1, message);

public static void EmitError(this InlineProcessor processor, Inline inline, int length, string message, Exception? e = null) =>
LinkDiagnostic(processor, Severity.Error, inline, length, message, e);
Emit(processor, Severity.Error, inline, length, message, e);

public static void EmitWarning(this InlineProcessor processor, Inline inline, int length, string message) =>
LinkDiagnostic(processor, Severity.Warning, inline, length, message);
Emit(processor, Severity.Warning, inline, length, message);

public static void EmitHint(this InlineProcessor processor, Inline inline, int length, string message) =>
LinkDiagnostic(processor, Severity.Hint, inline, length, message);
Emit(processor, Severity.Hint, inline, length, message);
}
6 changes: 6 additions & 0 deletions src/Elastic.Markdown/IO/MarkdownFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ private YamlFrontMatter ProcessYamlFrontMatter(MarkdownDocument document)
var raw = string.Join(Environment.NewLine, yaml.Lines.Lines);
var fm = ReadYamlFrontMatter(raw);

if (fm.AppliesTo?.Diagnostics is not null)
{
foreach (var (severity, message) in fm.AppliesTo.Diagnostics)
Collector.Emit(severity, FilePath, message);
}

// TODO remove when migration tool and our demo content sets are updated
var deprecatedTitle = fm.Title;
if (!string.IsNullOrEmpty(deprecatedTitle))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ private static void ProcessAppliesToDirective(AppliesToDirective appliesToDirect
{
var applicableTo = YamlSerialization.Deserialize<ApplicableTo>(yaml);
appliesToDirective.AppliesTo = applicableTo;
if (appliesToDirective.AppliesTo.Warnings is null)
if (appliesToDirective.AppliesTo.Diagnostics is null)
return;
foreach (var warning in appliesToDirective.AppliesTo.Warnings)
appliesToDirective.EmitWarning(warning);
applicableTo.Warnings = null;
foreach (var (severity, message) in appliesToDirective.AppliesTo.Diagnostics)
appliesToDirective.Emit(severity, message);
applicableTo.Diagnostics = null;
}
catch (Exception e)
{
Expand Down
35 changes: 26 additions & 9 deletions src/Elastic.Markdown/Myst/FrontMatter/Applicability.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Elastic.Documentation;
using Elastic.Documentation.Diagnostics;
using YamlDotNet.Serialization;

namespace Elastic.Markdown.Myst.FrontMatter;
Expand All @@ -17,7 +18,7 @@ public record AppliesCollection : IReadOnlyCollection<Applicability>
public AppliesCollection(Applicability[] items) => _items = items;

// <lifecycle> [version]
public static bool TryParse(string? value, out AppliesCollection? availability)
public static bool TryParse(string? value, IList<(Severity, string)> diagnostics, out AppliesCollection? availability)
{
availability = null;
if (string.IsNullOrWhiteSpace(value) || string.Equals(value.Trim(), "all", StringComparison.InvariantCultureIgnoreCase))
Expand All @@ -30,7 +31,7 @@ public static bool TryParse(string? value, out AppliesCollection? availability)
var applications = new List<Applicability>(items.Length);
foreach (var item in items)
{
if (Applicability.TryParse(item.Trim(), out var a))
if (Applicability.TryParse(item.Trim(), diagnostics, out var a))
applications.Add(a);
}

Expand Down Expand Up @@ -64,7 +65,10 @@ public override int GetHashCode()

public static explicit operator AppliesCollection(string b)
{
var productAvailability = TryParse(b, out var version) ? version : null;
var diagnostics = new List<(Severity, string)>();
var productAvailability = TryParse(b, diagnostics, out var version) ? version : null;
if (diagnostics.Count > 0)
throw new ArgumentException("Explicit conversion from string to AppliesCollection failed." + string.Join(Environment.NewLine, diagnostics));
return productAvailability ?? throw new ArgumentException($"'{b}' is not a valid applicability string array.");
}

Expand Down Expand Up @@ -112,6 +116,7 @@ public string GetLifeCycleName() =>
ProductLifecycle.Discontinued => "Discontinued",
ProductLifecycle.Unavailable => "Unavailable",
ProductLifecycle.GenerallyAvailable => "GA",
ProductLifecycle.Removed => "Removed",
_ => throw new ArgumentOutOfRangeException(nameof(Lifecycle), Lifecycle, null)
};

Expand All @@ -131,6 +136,7 @@ public override string ToString()
ProductLifecycle.Discontinued => "discontinued",
ProductLifecycle.Unavailable => "unavailable",
ProductLifecycle.GenerallyAvailable => "ga",
ProductLifecycle.Removed => "removed",
_ => throw new ArgumentOutOfRangeException()
};
_ = sb.Append(lifecycle);
Expand All @@ -141,11 +147,14 @@ public override string ToString()

public static explicit operator Applicability(string b)
{
var productAvailability = TryParse(b, out var version) ? version : TryParse(b + ".0", out version) ? version : null;
var diagnostics = new List<(Severity, string)>();
var productAvailability = TryParse(b, diagnostics, out var version) ? version : TryParse(b + ".0", diagnostics, out version) ? version : null;
if (diagnostics.Count > 0)
throw new ArgumentException("Explicit conversion from string to AppliesCollection failed." + string.Join(Environment.NewLine, diagnostics));
return productAvailability ?? throw new ArgumentException($"'{b}' is not a valid applicability string.");
}

public static bool TryParse(string? value, [NotNullWhen(true)] out Applicability? availability)
public static bool TryParse(string? value, IList<(Severity, string)> diagnostics, [NotNullWhen(true)] out Applicability? availability)
{
if (string.IsNullOrWhiteSpace(value) || string.Equals(value.Trim(), "all", StringComparison.InvariantCultureIgnoreCase))
{
Expand All @@ -160,22 +169,30 @@ public static bool TryParse(string? value, [NotNullWhen(true)] out Applicability
return false;
}

var lifecycle = tokens[0].ToLowerInvariant() switch
var lookup = tokens[0].ToLowerInvariant();
var lifecycle = lookup switch
{
"preview" => ProductLifecycle.TechnicalPreview,
"tech-preview" => ProductLifecycle.TechnicalPreview,
"beta" => ProductLifecycle.Beta,
"ga" => ProductLifecycle.GenerallyAvailable,
"deprecated" => ProductLifecycle.Deprecated,
"removed" => ProductLifecycle.Removed,
"unavailable" => ProductLifecycle.Unavailable,

// OBSOLETE should be removed once docs are cleaned up
"dev" => ProductLifecycle.Development,
"development" => ProductLifecycle.Development,
"deprecated" => ProductLifecycle.Deprecated,
"coming" => ProductLifecycle.Planned,
"planned" => ProductLifecycle.Planned,
"discontinued" => ProductLifecycle.Discontinued,
"unavailable" => ProductLifecycle.Unavailable,
"ga" => ProductLifecycle.GenerallyAvailable,
_ => throw new Exception($"Unknown product lifecycle: {tokens[0]}")
};

// TODO emit as error when all docs have been updated
if (lifecycle is ProductLifecycle.Planned or ProductLifecycle.Deprecated or ProductLifecycle.Development)
diagnostics.Add((Severity.Hint, $"The '{lookup}' lifecycle is deprecated and will be removed in a future release."));

var version = tokens.Length < 2
? null
: tokens[1] switch
Expand Down
Loading
Loading