diff --git a/docs/cli/changelog/bundle.md b/docs/cli/changelog/bundle.md
index 2a62695af..2b6e38f52 100644
--- a/docs/cli/changelog/bundle.md
+++ b/docs/cli/changelog/bundle.md
@@ -388,6 +388,25 @@ docs-builder changelog bundle \
--description "Elasticsearch {version} includes performance improvements. Download: https://github.com/{owner}/{repo}/releases/tag/v{version}"
```
+### Bundle with release date
+
+You can add a `release-date` field directly to a bundle YAML file. This field is optional and purely informative for end-users. It is especially useful for components released outside the usual stack lifecycle, such as APM agents and EDOT agents.
+
+```yaml
+products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+release-date: "April 9, 2026"
+description: |
+ This release includes tracing improvements and bug fixes.
+entries:
+ - file:
+ name: tracing-improvement.yaml
+ checksum: abc123
+```
+
+When the bundle is rendered (by the `changelog render` command or `{changelog}` directive), the release date appears immediately after the version heading as italicized text: `_Released: April 9, 2026_`.
+
## Profile-based examples
When the changelog configuration file defines `bundle.profiles`, you can use those profiles with the `changelog bundle` command.
diff --git a/docs/syntax/changelog.md b/docs/syntax/changelog.md
index dfada1db0..ca2128c6d 100644
--- a/docs/syntax/changelog.md
+++ b/docs/syntax/changelog.md
@@ -142,10 +142,11 @@ For full syntax, refer to the [rules for filtered bundles](/cli/changelog/bundle
When bundles contain a `hide-features` field, entries with matching `feature-id` values are automatically filtered out from the rendered output. This allows you to hide unreleased or experimental features without modifying the bundle at render time.
```yaml
-# Example bundle with description and hide-features
+# Example bundle with release-date, description, and hide-features
products:
- product: elasticsearch
target: 9.3.0
+release-date: "2026-04-09"
description: |
This release includes new features and bug fixes.
@@ -227,11 +228,13 @@ The version is extracted from the first product's `target` field in each bundle
## Rendered output
-Each bundle renders as a `## {version}` section with optional description and subsections beneath:
+Each bundle renders as a `## {version}` section with optional release date, description, and subsections beneath:
```markdown
## 0.100.0
+_Released: 2026-04-09_
+
This release includes new features and bug fixes.
Download the release binaries: https://github.com/elastic/elasticsearch/releases/tag/v0.100.0
@@ -246,7 +249,9 @@ Download the release binaries: https://github.com/elastic/elasticsearch/releases
...
```
-Bundle descriptions are rendered when present in the bundle YAML file. The description appears immediately after the version heading but before any entry sections. Descriptions support Markdown formatting including links, lists, and multiple paragraphs.
+When present, the `release-date` field is rendered immediately after the version heading as italicized text (e.g., `_Released: 2026-04-09_`). This is purely informative for end-users and is especially useful for components released outside the usual stack lifecycle, such as APM agents and EDOT agents.
+
+Bundle descriptions are rendered when present in the bundle YAML file. The description appears after the release date (if any) but before any entry sections. Descriptions support Markdown formatting including links, lists, and multiple paragraphs.
### Section types
diff --git a/src/Elastic.Documentation.Configuration/ReleaseNotes/Bundle.cs b/src/Elastic.Documentation.Configuration/ReleaseNotes/Bundle.cs
index a417ceabe..11e72a87f 100644
--- a/src/Elastic.Documentation.Configuration/ReleaseNotes/Bundle.cs
+++ b/src/Elastic.Documentation.Configuration/ReleaseNotes/Bundle.cs
@@ -18,6 +18,12 @@ public sealed record BundleDto
///
public string? Description { get; set; }
///
+ /// Optional release date for this bundle.
+ /// Purely informative; rendered after the release heading.
+ ///
+ [YamlMember(Alias = "release-date", ApplyNamingConventions = false)]
+ public string? ReleaseDate { get; set; }
+ ///
/// Feature IDs that should be hidden when rendering this bundle.
/// Entries with matching feature-id values will be commented out in the output.
///
diff --git a/src/Elastic.Documentation.Configuration/ReleaseNotes/BundleLoader.cs b/src/Elastic.Documentation.Configuration/ReleaseNotes/BundleLoader.cs
index b25a45e1a..c3c1420fa 100644
--- a/src/Elastic.Documentation.Configuration/ReleaseNotes/BundleLoader.cs
+++ b/src/Elastic.Documentation.Configuration/ReleaseNotes/BundleLoader.cs
@@ -229,7 +229,20 @@ private static LoadedBundle MergeBundleGroup(IGrouping gro
_ => string.Join("\n\n", descriptions)
};
- var mergedData = first.Data with { Description = mergedDescription };
+ var releaseDates = bundlesList
+ .Select(b => b.Data?.ReleaseDate)
+ .Where(d => d.HasValue)
+ .Select(d => d!.Value)
+ .Distinct()
+ .ToList();
+
+ var mergedReleaseDate = releaseDates.Count switch
+ {
+ 0 => (DateOnly?)null,
+ _ => releaseDates[0]
+ };
+
+ var mergedData = first.Data with { Description = mergedDescription, ReleaseDate = mergedReleaseDate };
return new LoadedBundle(
first.Version,
diff --git a/src/Elastic.Documentation.Configuration/ReleaseNotes/ReleaseNotesSerialization.cs b/src/Elastic.Documentation.Configuration/ReleaseNotes/ReleaseNotesSerialization.cs
index 671c2d510..6f0690ec9 100644
--- a/src/Elastic.Documentation.Configuration/ReleaseNotes/ReleaseNotesSerialization.cs
+++ b/src/Elastic.Documentation.Configuration/ReleaseNotes/ReleaseNotesSerialization.cs
@@ -2,6 +2,7 @@
// 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.Globalization;
using System.IO.Abstractions;
using System.Text.RegularExpressions;
using Elastic.Documentation.Configuration.Serialization;
@@ -136,6 +137,7 @@ public static string SerializeBundle(Bundle bundle)
{
Products = dto.Products?.Select(ToBundledProduct).ToList() ?? [],
Description = dto.Description,
+ ReleaseDate = ParseReleaseDate(dto.ReleaseDate),
HideFeatures = dto.HideFeatures ?? [],
Entries = dto.Entries?.Select(ToBundledEntry).ToList() ?? []
};
@@ -212,6 +214,11 @@ private static ChangelogEntryType ParseEntryType(string? value)
: null;
}
+ private static DateOnly? ParseReleaseDate(string? value) =>
+ DateOnly.TryParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)
+ ? date
+ : null;
+
// Reverse mappings (Domain → DTO) for serialization
private static ChangelogEntryDto ToDto(ChangelogEntry entry) => new()
@@ -241,6 +248,7 @@ private static ChangelogEntryType ParseEntryType(string? value)
{
Products = bundle.Products.Select(ToDto).ToList(),
Description = bundle.Description,
+ ReleaseDate = bundle.ReleaseDate?.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
HideFeatures = bundle.HideFeatures.Count > 0 ? bundle.HideFeatures.ToList() : null,
Entries = bundle.Entries.Select(ToDto).ToList()
};
diff --git a/src/Elastic.Documentation/ReleaseNotes/Bundle.cs b/src/Elastic.Documentation/ReleaseNotes/Bundle.cs
index be5bf36ba..70c470eb7 100644
--- a/src/Elastic.Documentation/ReleaseNotes/Bundle.cs
+++ b/src/Elastic.Documentation/ReleaseNotes/Bundle.cs
@@ -19,6 +19,14 @@ public record Bundle
///
public string? Description { get; init; }
+ ///
+ /// Optional release date for this bundle.
+ /// Purely informative for end-users; rendered after the release heading.
+ /// Useful for components released outside the usual stack lifecycle (e.g., APM/EDOT agents).
+ /// Parsed from YYYY-MM-DD format in YAML; serialized back as YYYY-MM-DD.
+ ///
+ public DateOnly? ReleaseDate { get; init; }
+
///
/// Feature IDs that should be hidden when rendering this bundle.
/// Entries with matching feature-id values will be commented out in the output.
diff --git a/src/Elastic.Markdown/Myst/Directives/Changelog/ChangelogInlineRenderer.cs b/src/Elastic.Markdown/Myst/Directives/Changelog/ChangelogInlineRenderer.cs
index cd055e9d7..af282fef5 100644
--- a/src/Elastic.Markdown/Myst/Directives/Changelog/ChangelogInlineRenderer.cs
+++ b/src/Elastic.Markdown/Myst/Directives/Changelog/ChangelogInlineRenderer.cs
@@ -79,7 +79,7 @@ private static string RenderSingleBundle(
};
var displayVersion = VersionOrDate.FormatDisplayVersion(bundle.Version);
- return GenerateMarkdown(displayVersion, titleSlug, bundle.Repo, bundle.Owner, entriesByType, subsections, hideLinks, typeFilter, publishBlocker, bundle.Data?.Description);
+ return GenerateMarkdown(displayVersion, titleSlug, bundle.Repo, bundle.Owner, entriesByType, subsections, hideLinks, typeFilter, publishBlocker, bundle.Data?.Description, bundle.Data?.ReleaseDate);
}
///
@@ -153,7 +153,8 @@ private static string GenerateMarkdown(
bool hideLinks,
ChangelogTypeFilter typeFilter,
PublishBlocker? publishBlocker,
- string? description = null)
+ string? description = null,
+ DateOnly? releaseDate = null)
{
var sb = new StringBuilder();
@@ -177,6 +178,13 @@ private static string GenerateMarkdown(
_ = sb.AppendLine(CultureInfo.InvariantCulture, $"## {title}");
+ // Add release date if present
+ if (releaseDate is { } date)
+ {
+ _ = sb.AppendLine();
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"_Released: {date.ToString("MMMM d, yyyy", CultureInfo.InvariantCulture)}_");
+ }
+
// Add description if present
if (!string.IsNullOrEmpty(description))
{
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/ChangelogAsciidocRenderer.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/ChangelogAsciidocRenderer.cs
index edce4ad1e..e23554c59 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/ChangelogAsciidocRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/ChangelogAsciidocRenderer.cs
@@ -32,6 +32,13 @@ public async Task RenderAsciidoc(ChangelogRenderContext context, Cancel ctx)
_ = sb.AppendLine(InvariantCulture, $"== {context.Title}");
_ = sb.AppendLine();
+ // Add release date if present
+ if (context.BundleReleaseDate is { } releaseDate)
+ {
+ _ = sb.AppendLine(InvariantCulture, $"_Released: {releaseDate.ToString("MMMM d, yyyy", InvariantCulture)}_");
+ _ = sb.AppendLine();
+ }
+
// Add description if present
if (!string.IsNullOrEmpty(context.BundleDescription))
{
diff --git a/src/services/Elastic.Changelog/Rendering/ChangelogRenderContext.cs b/src/services/Elastic.Changelog/Rendering/ChangelogRenderContext.cs
index a2f0d5633..4fcdfbe20 100644
--- a/src/services/Elastic.Changelog/Rendering/ChangelogRenderContext.cs
+++ b/src/services/Elastic.Changelog/Rendering/ChangelogRenderContext.cs
@@ -30,4 +30,9 @@ public record ChangelogRenderContext
/// Optional bundle-level introductory description. Only set when there's a single bundle with a description (MVP approach).
///
public string? BundleDescription { get; init; }
+ ///
+ /// Optional release date for this bundle. Purely informative for end-users.
+ /// Only set when there's a single unique release date across all bundles (MVP approach).
+ ///
+ public DateOnly? BundleReleaseDate { get; init; }
}
diff --git a/src/services/Elastic.Changelog/Rendering/ChangelogRenderingService.cs b/src/services/Elastic.Changelog/Rendering/ChangelogRenderingService.cs
index c78d4ba27..800d64b93 100644
--- a/src/services/Elastic.Changelog/Rendering/ChangelogRenderingService.cs
+++ b/src/services/Elastic.Changelog/Rendering/ChangelogRenderingService.cs
@@ -137,6 +137,7 @@ Cancel ctx
var bundleDescriptions = validationResult.Bundles
.Select(b => b.Data.Description)
.Where(d => !string.IsNullOrEmpty(d))
+ .Distinct()
.ToList();
// MVP: Check for multiple descriptions and warn
@@ -152,8 +153,28 @@ Cancel ctx
renderDescription = bundleDescriptions[0];
}
+ // Extract release dates from bundles for MVP support
+ var bundleReleaseDates = validationResult.Bundles
+ .Select(b => b.Data.ReleaseDate)
+ .Where(d => d.HasValue)
+ .Select(d => d!.Value)
+ .Distinct()
+ .ToList();
+
+ DateOnly? renderReleaseDate = null;
+ if (bundleReleaseDates.Count > 1)
+ {
+ collector.EmitWarning(string.Empty,
+ $"Multiple bundles contain release dates ({bundleReleaseDates.Count} found). " +
+ "Multi-bundle release date support is not yet implemented. Release dates will be skipped.");
+ }
+ else if (bundleReleaseDates.Count == 1)
+ {
+ renderReleaseDate = bundleReleaseDates[0];
+ }
+
// Build render context
- var context = BuildRenderContext(input, outputSetup, resolvedResult, combinedHideFeatures, config, renderDescription);
+ var context = BuildRenderContext(input, outputSetup, resolvedResult, combinedHideFeatures, config, renderDescription, renderReleaseDate);
// Validate entry types
if (!ValidateEntryTypes(collector, resolvedResult.Entries, config.Types))
@@ -266,7 +287,8 @@ private static ChangelogRenderContext BuildRenderContext(
ResolvedEntriesResult resolved,
HashSet featureIdsToHide,
ChangelogConfiguration? config,
- string? description = null)
+ string? description = null,
+ DateOnly? releaseDate = null)
{
// Group entries by type
var entriesByType = resolved.Entries
@@ -308,7 +330,8 @@ private static ChangelogRenderContext BuildRenderContext(
EntryToOwner = entryToOwner,
EntryToHideLinks = entryToHideLinks,
Configuration = config,
- BundleDescription = description
+ BundleDescription = description,
+ BundleReleaseDate = releaseDate
};
}
diff --git a/src/services/Elastic.Changelog/Rendering/Markdown/IndexMarkdownRenderer.cs b/src/services/Elastic.Changelog/Rendering/Markdown/IndexMarkdownRenderer.cs
index 3d9b19234..9933eacee 100644
--- a/src/services/Elastic.Changelog/Rendering/Markdown/IndexMarkdownRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Markdown/IndexMarkdownRenderer.cs
@@ -52,6 +52,13 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
var sb = new StringBuilder();
_ = sb.AppendLine(InvariantCulture, $"## {context.Title} [{context.Repo}-release-notes-{context.TitleSlug}]");
+ // Add release date if present
+ if (context.BundleReleaseDate is { } releaseDate)
+ {
+ _ = sb.AppendLine();
+ _ = sb.AppendLine(InvariantCulture, $"_Released: {releaseDate.ToString("MMMM d, yyyy", InvariantCulture)}_");
+ }
+
// Add description if present
if (!string.IsNullOrEmpty(context.BundleDescription))
{
diff --git a/tests/Elastic.Changelog.Tests/Changelogs/BundleLoading/BundleLoaderTests.cs b/tests/Elastic.Changelog.Tests/Changelogs/BundleLoading/BundleLoaderTests.cs
index 3887682e1..d272a3152 100644
--- a/tests/Elastic.Changelog.Tests/Changelogs/BundleLoading/BundleLoaderTests.cs
+++ b/tests/Elastic.Changelog.Tests/Changelogs/BundleLoading/BundleLoaderTests.cs
@@ -1184,6 +1184,195 @@ public void LoadBundles_DescriptionCanBeNull()
_warnings.Should().BeEmpty();
}
+ [Fact]
+ public void LoadBundles_ReleaseDateSerializesAndDeserializesCorrectly()
+ {
+ // Arrange - Test round-trip serialization of release-date field
+ var bundlesFolder = "/docs/changelog/bundles";
+ _fileSystem.Directory.CreateDirectory(bundlesFolder);
+
+ var originalBundle = new Bundle
+ {
+ Products =
+ [
+ new BundledProduct { ProductId = "apm-agent-dotnet", Target = "1.34.0" }
+ ],
+ ReleaseDate = new DateOnly(2026, 4, 9),
+ Entries =
+ [
+ new BundledEntry
+ {
+ Title = "Test feature",
+ Type = ChangelogEntryType.Feature,
+ File = new BundledFile { Name = "test.yaml", Checksum = "abc123" }
+ }
+ ]
+ };
+
+ var serializedYaml = ReleaseNotesSerialization.SerializeBundle(originalBundle);
+ _fileSystem.File.WriteAllText($"{bundlesFolder}/1.34.0.yaml", serializedYaml);
+
+ var service = CreateService();
+
+ // Act
+ var bundles = service.LoadBundles(bundlesFolder, EmitWarning);
+
+ // Assert
+ bundles.Should().HaveCount(1);
+ bundles[0].Data.ReleaseDate.Should().Be(new DateOnly(2026, 4, 9));
+ _warnings.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void LoadBundles_ReleaseDateCanBeNull()
+ {
+ var bundlesFolder = "/docs/changelog/bundles";
+ _fileSystem.Directory.CreateDirectory(bundlesFolder);
+
+ var originalBundle = new Bundle
+ {
+ Products =
+ [
+ new BundledProduct { ProductId = "elasticsearch", Target = "9.3.0" }
+ ],
+ ReleaseDate = null,
+ Entries =
+ [
+ new BundledEntry
+ {
+ Title = "Test feature",
+ Type = ChangelogEntryType.Feature,
+ File = new BundledFile { Name = "test.yaml", Checksum = "abc123" }
+ }
+ ]
+ };
+
+ var serializedYaml = ReleaseNotesSerialization.SerializeBundle(originalBundle);
+ _fileSystem.File.WriteAllText($"{bundlesFolder}/9.3.0.yaml", serializedYaml);
+
+ var service = CreateService();
+
+ // Act
+ var bundles = service.LoadBundles(bundlesFolder, EmitWarning);
+
+ // Assert
+ bundles.Should().HaveCount(1);
+ bundles[0].Data.ReleaseDate.Should().BeNull();
+ _warnings.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void LoadBundles_ReleaseDateFromYaml_ParsedCorrectly()
+ {
+ var bundlesFolder = "/docs/changelog/bundles";
+ _fileSystem.Directory.CreateDirectory(bundlesFolder);
+
+ // language=yaml
+ var bundleContent =
+ """
+ products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+ release-date: "2026-04-09"
+ entries:
+ - title: Test feature
+ type: feature
+ prs:
+ - "100"
+ """;
+ _fileSystem.File.WriteAllText($"{bundlesFolder}/1.34.0.yaml", bundleContent);
+
+ var service = CreateService();
+
+ // Act
+ var bundles = service.LoadBundles(bundlesFolder, EmitWarning);
+
+ // Assert
+ bundles.Should().HaveCount(1);
+ bundles[0].Data.ReleaseDate.Should().Be(new DateOnly(2026, 4, 9));
+ _warnings.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void LoadBundles_ReleaseDateInvalidFormat_ParsedAsNull()
+ {
+ var bundlesFolder = "/docs/changelog/bundles";
+ _fileSystem.Directory.CreateDirectory(bundlesFolder);
+
+ // language=yaml
+ var bundleContent =
+ """
+ products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+ release-date: "April 9, 2026"
+ entries:
+ - title: Test feature
+ type: feature
+ prs:
+ - "100"
+ """;
+ _fileSystem.File.WriteAllText($"{bundlesFolder}/1.34.0.yaml", bundleContent);
+
+ var service = CreateService();
+
+ // Act
+ var bundles = service.LoadBundles(bundlesFolder, EmitWarning);
+
+ // Assert
+ bundles.Should().HaveCount(1);
+ bundles[0].Data.ReleaseDate.Should().BeNull();
+ _warnings.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void MergeBundlesByTarget_ReleaseDatePreserved()
+ {
+ // Arrange - Two bundles with same target, one has release-date
+ var bundlesFolder = "/docs/changelog/bundles";
+ _fileSystem.Directory.CreateDirectory(bundlesFolder);
+
+ // language=yaml
+ var bundle1 =
+ """
+ products:
+ - product: elasticsearch
+ target: 9.3.0
+ release-date: "2026-04-09"
+ entries:
+ - title: Feature from ES
+ type: feature
+ prs:
+ - "100"
+ """;
+
+ // language=yaml
+ var bundle2 =
+ """
+ products:
+ - product: kibana
+ target: 9.3.0
+ entries:
+ - title: Feature from Kibana
+ type: feature
+ prs:
+ - "200"
+ """;
+
+ _fileSystem.File.WriteAllText($"{bundlesFolder}/elasticsearch-9.3.0.yaml", bundle1);
+ _fileSystem.File.WriteAllText($"{bundlesFolder}/kibana-9.3.0.yaml", bundle2);
+
+ var service = CreateService();
+ var loaded = service.LoadBundles(bundlesFolder, EmitWarning);
+
+ // Act
+ var merged = service.MergeBundlesByTarget(loaded);
+
+ // Assert
+ merged.Should().HaveCount(1);
+ merged[0].Data.ReleaseDate.Should().Be(new DateOnly(2026, 4, 9));
+ }
+
[Fact]
public void LoadedBundle_HideFeatures_ExposedFromBundleData()
{
diff --git a/tests/Elastic.Markdown.Tests/Directives/ChangelogBasicTests.cs b/tests/Elastic.Markdown.Tests/Directives/ChangelogBasicTests.cs
index 0ea1b5ba1..4f2b49466 100644
--- a/tests/Elastic.Markdown.Tests/Directives/ChangelogBasicTests.cs
+++ b/tests/Elastic.Markdown.Tests/Directives/ChangelogBasicTests.cs
@@ -610,3 +610,112 @@ public void RendersDescriptionText() =>
public void DoesNotConcatenateTitleAndDescriptionWithoutSeparator() =>
Html.Should().NotContain("allowlist.This PR introduces");
}
+
+///
+/// Verifies that when a bundle has a release-date field, it is rendered in the output.
+///
+public class ChangelogReleaseDateTests : DirectiveTest
+{
+ public ChangelogReleaseDateTests(ITestOutputHelper output) : base(output,
+ // language=markdown
+ """
+ :::{changelog}
+ :::
+ """) => FileSystem.AddFile("docs/changelog/bundles/1.34.0.yaml", new MockFileData(
+ // language=yaml
+ """
+ products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+ release-date: "2026-04-09"
+ entries:
+ - title: Add tracing improvements
+ type: feature
+ products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+ prs:
+ - "500"
+ """));
+
+ [Fact]
+ public void RendersReleaseDate() =>
+ Html.Should().Contain("Released: April 9, 2026");
+
+ [Fact]
+ public void RendersEntries() =>
+ Html.Should().Contain("Add tracing improvements");
+}
+
+///
+/// Verifies that when a bundle has no release-date field, no "Released:" text appears.
+///
+public class ChangelogNoReleaseDateTests : DirectiveTest
+{
+ public ChangelogNoReleaseDateTests(ITestOutputHelper output) : base(output,
+ // language=markdown
+ """
+ :::{changelog}
+ :::
+ """) => FileSystem.AddFile("docs/changelog/bundles/9.3.0.yaml", new MockFileData(
+ // language=yaml
+ """
+ products:
+ - product: elasticsearch
+ target: 9.3.0
+ entries:
+ - title: New feature
+ type: feature
+ products:
+ - product: elasticsearch
+ target: 9.3.0
+ prs:
+ - "100"
+ """));
+
+ [Fact]
+ public void DoesNotRenderReleaseDate() =>
+ Html.Should().NotContain("Released:");
+}
+
+///
+/// Verifies that both release-date and description render together.
+///
+public class ChangelogReleaseDateWithDescriptionTests : DirectiveTest
+{
+ public ChangelogReleaseDateWithDescriptionTests(ITestOutputHelper output) : base(output,
+ // language=markdown
+ """
+ :::{changelog}
+ :::
+ """) => FileSystem.AddFile("docs/changelog/bundles/1.34.0.yaml", new MockFileData(
+ // language=yaml
+ """
+ products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+ release-date: "2026-04-09"
+ description: |
+ This release includes tracing improvements and bug fixes.
+ entries:
+ - title: Add tracing improvements
+ type: feature
+ products:
+ - product: apm-agent-dotnet
+ target: 1.34.0
+ prs:
+ - "500"
+ """));
+
+ [Fact]
+ public void RendersReleaseDate() =>
+ Html.Should().Contain("Released: April 9, 2026");
+
+ [Fact]
+ public void RendersDescription() =>
+ Html.Should().Contain("This release includes tracing improvements and bug fixes.");
+
+ [Fact]
+ public void RendersEntries() =>
+ Html.Should().Contain("Add tracing improvements");
+}