diff --git a/docs/cli/changelog/render.md b/docs/cli/changelog/render.md
index ef28debd3..9ce352db2 100644
--- a/docs/cli/changelog/render.md
+++ b/docs/cli/changelog/render.md
@@ -98,6 +98,12 @@ When `--file-type asciidoc` is specified, the command generates a single asciido
The asciidoc output uses attribute references for links (for example, `{repo-pull}NUMBER[#NUMBER]`).
+AsciiDoc output ignores the `--dropdowns` flag and always uses a standardized format with the following characteristics:
+
+- Multi-block entries (containing description, Impact, and Action sections) use proper list continuation markers (`+`) to maintain list structure
+- Strong text formatting uses idiomatic single asterisk syntax (`*Impact:*`, `*Action:*`) following AsciiDoc best practices
+- All content blocks are properly attached to their parent list items for correct rendering
+
### Multiple PR and issue links
Changelog entries can reference multiple pull requests and issues using the `prs` and `issues` array fields. When an entry has multiple links, all of them are rendered inline for that entry:
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/AsciidocRendererBase.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/AsciidocRendererBase.cs
index 92a6e23f0..d9aa5fcb6 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/AsciidocRendererBase.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/AsciidocRendererBase.cs
@@ -61,40 +61,48 @@ private static void RenderEntryTitleAndLinks(StringBuilder sb, ChangelogEntry en
}
///
- /// Renders an entry's description with optional comment handling
+ /// Renders an entry's description with optional comment handling and list continuation
///
- private static void RenderEntryDescription(StringBuilder sb, ChangelogEntry entry, bool shouldHide)
+ private static void RenderEntryDescription(StringBuilder sb, ChangelogEntry entry, bool shouldHide, bool needsContinuation = true)
{
if (string.IsNullOrWhiteSpace(entry.Description))
return;
_ = sb.AppendLine();
- var indented = ChangelogTextUtilities.Indent(entry.Description);
+
+ // Add list continuation marker for multi-block list items
+ if (needsContinuation)
+ {
+ _ = sb.AppendLine("+");
+ }
+
if (shouldHide)
{
- var indentedLines = indented.Split('\n');
- foreach (var line in indentedLines)
+ var descriptionLines = entry.Description.Split('\n');
+ foreach (var line in descriptionLines)
_ = sb.AppendLine(CultureInfo.InvariantCulture, $"// {line}");
}
else
- _ = sb.AppendLine(indented);
+ _ = sb.AppendLine(entry.Description);
}
///
- /// Renders Impact and Action fields for breaking changes, deprecations, and known issues
+ /// Renders Impact and Action fields for breaking changes, deprecations, and known issues with list continuation
///
private static void RenderImpactAndAction(StringBuilder sb, ChangelogEntry entry)
{
if (!string.IsNullOrWhiteSpace(entry.Impact))
{
_ = sb.AppendLine();
- _ = sb.AppendLine(CultureInfo.InvariantCulture, $"**Impact:** {entry.Impact}");
+ _ = sb.AppendLine("+");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"*Impact:* {entry.Impact}");
}
if (!string.IsNullOrWhiteSpace(entry.Action))
{
_ = sb.AppendLine();
- _ = sb.AppendLine(CultureInfo.InvariantCulture, $"**Action:** {entry.Action}");
+ _ = sb.AppendLine("+");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"*Action:* {entry.Action}");
}
}
@@ -105,7 +113,7 @@ protected void RenderBasicEntry(StringBuilder sb, ChangelogEntry entry, Changelo
{
var (entryRepo, _, hideLinks, shouldHide) = ChangelogRenderUtilities.GetEntryContext(entry, context);
RenderEntryTitleAndLinks(sb, entry, entryRepo, hideLinks, shouldHide);
- RenderEntryDescription(sb, entry, shouldHide);
+ RenderEntryDescription(sb, entry, shouldHide, needsContinuation: !string.IsNullOrWhiteSpace(entry.Description));
_ = sb.AppendLine();
}
@@ -116,7 +124,11 @@ protected void RenderEntryWithImpactAction(StringBuilder sb, ChangelogEntry entr
{
var (entryRepo, _, hideLinks, shouldHide) = ChangelogRenderUtilities.GetEntryContext(entry, context);
RenderEntryTitleAndLinks(sb, entry, entryRepo, hideLinks, shouldHide);
- RenderEntryDescription(sb, entry, shouldHide);
+
+ // Description needs continuation when it exists
+ var hasDescription = !string.IsNullOrWhiteSpace(entry.Description);
+ RenderEntryDescription(sb, entry, shouldHide, needsContinuation: hasDescription);
+
RenderImpactAndAction(sb, entry);
_ = sb.AppendLine();
}
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/BreakingChangesAsciidocRenderer.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/BreakingChangesAsciidocRenderer.cs
index cdf2a794d..99532acf3 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/BreakingChangesAsciidocRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/BreakingChangesAsciidocRenderer.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.Text;
using Elastic.Documentation;
using Elastic.Documentation.ReleaseNotes;
@@ -30,8 +31,17 @@ public override void Render(IReadOnlyCollection entries, Changel
if (context.Subsections && !string.IsNullOrWhiteSpace(group.Key))
{
var header = ChangelogTextUtilities.FormatSubtypeHeader(group.Key);
- var headerLine = allEntriesHidden ? $"// **{header}**" : $"**{header}**";
- _ = sb.AppendLine(headerLine);
+
+ if (allEntriesHidden)
+ {
+ _ = sb.AppendLine("// [float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"// ==== {header}");
+ }
+ else
+ {
+ _ = sb.AppendLine("[float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"==== {header}");
+ }
_ = sb.AppendLine();
}
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/DeprecationsAsciidocRenderer.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/DeprecationsAsciidocRenderer.cs
index 11d1cf7c0..264730c05 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/DeprecationsAsciidocRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/DeprecationsAsciidocRenderer.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.Text;
using Elastic.Documentation.ReleaseNotes;
@@ -15,22 +16,37 @@ public class DeprecationsAsciidocRenderer(StringBuilder sb) : AsciidocRendererBa
///
public override void Render(IReadOnlyCollection entries, ChangelogRenderContext context)
{
- var groupedByArea = entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).OrderBy(g => g.Key).ToList();
+ // Group by area if subsections is enabled, otherwise use single group
+ var groupedEntries = context.Subsections
+ ? entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).OrderBy(g => g.Key).ToList()
+ : [entries.GroupBy(_ => string.Empty).First()];
- foreach (var areaGroup in groupedByArea)
+ foreach (var group in groupedEntries)
{
- // Check if all entries in this area group are hidden
- var allEntriesHidden = areaGroup.All(entry =>
+ // Check if all entries in this group are hidden
+ var allEntriesHidden = group.All(entry =>
ChangelogRenderUtilities.ShouldHideEntry(entry, context.FeatureIdsToHide, context));
- var componentName = !string.IsNullOrWhiteSpace(areaGroup.Key) ? areaGroup.Key : "General";
- var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
+ // Add nested section header when subsections are enabled and group has a name
+ if (context.Subsections && !string.IsNullOrWhiteSpace(group.Key))
+ {
+ var componentName = group.Key != string.Empty ? group.Key : "General";
+ var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
- var headerLine = allEntriesHidden ? $"// {formattedComponent}::" : $"{formattedComponent}::";
- _ = sb.AppendLine(headerLine);
- _ = sb.AppendLine();
+ if (allEntriesHidden)
+ {
+ _ = sb.AppendLine("// [float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"// ==== {formattedComponent}");
+ }
+ else
+ {
+ _ = sb.AppendLine("[float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"==== {formattedComponent}");
+ }
+ _ = sb.AppendLine();
+ }
- foreach (var entry in areaGroup)
+ foreach (var entry in group)
RenderEntryWithImpactAction(sb, entry, context);
}
}
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/EntriesByAreaAsciidocRenderer.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/EntriesByAreaAsciidocRenderer.cs
index 0bd171ad2..513f8901b 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/EntriesByAreaAsciidocRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/EntriesByAreaAsciidocRenderer.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.Text;
using Elastic.Documentation.ReleaseNotes;
@@ -15,24 +16,37 @@ public class EntriesByAreaAsciidocRenderer(StringBuilder sb) : AsciidocRendererB
///
public override void Render(IReadOnlyCollection entries, ChangelogRenderContext context)
{
- var groupedByArea = context.Subsections
+ // Group by area if subsections is enabled, otherwise use single group
+ var groupedEntries = context.Subsections
? entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).OrderBy(g => g.Key).ToList()
- : entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).ToList();
+ : [entries.GroupBy(_ => string.Empty).First()];
- foreach (var areaGroup in groupedByArea)
+ foreach (var group in groupedEntries)
{
- // Check if all entries in this area group are hidden
- var allEntriesHidden = areaGroup.All(entry =>
+ // Check if all entries in this group are hidden
+ var allEntriesHidden = group.All(entry =>
ChangelogRenderUtilities.ShouldHideEntry(entry, context.FeatureIdsToHide, context));
- var componentName = !string.IsNullOrWhiteSpace(areaGroup.Key) ? areaGroup.Key : "General";
- var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
+ // Add nested section header when subsections are enabled and group has a name
+ if (context.Subsections && !string.IsNullOrWhiteSpace(group.Key))
+ {
+ var componentName = group.Key != string.Empty ? group.Key : "General";
+ var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
- var headerLine = allEntriesHidden ? $"// {formattedComponent}::" : $"{formattedComponent}::";
- _ = sb.AppendLine(headerLine);
- _ = sb.AppendLine();
+ if (allEntriesHidden)
+ {
+ _ = sb.AppendLine("// [float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"// ==== {formattedComponent}");
+ }
+ else
+ {
+ _ = sb.AppendLine("[float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"==== {formattedComponent}");
+ }
+ _ = sb.AppendLine();
+ }
- foreach (var entry in areaGroup)
+ foreach (var entry in group)
RenderBasicEntry(sb, entry, context);
}
}
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/HighlightsAsciidocRenderer.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/HighlightsAsciidocRenderer.cs
index eff5542d0..07312f14f 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/HighlightsAsciidocRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/HighlightsAsciidocRenderer.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.Text;
using Elastic.Documentation.ReleaseNotes;
@@ -15,24 +16,37 @@ public class HighlightsAsciidocRenderer(StringBuilder sb) : AsciidocRendererBase
///
public override void Render(IReadOnlyCollection entries, ChangelogRenderContext context)
{
- var groupedByArea = context.Subsections
+ // Group by area if subsections is enabled, otherwise use single group
+ var groupedEntries = context.Subsections
? entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).OrderBy(g => g.Key).ToList()
- : entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).ToList();
+ : [entries.GroupBy(_ => string.Empty).First()];
- foreach (var areaGroup in groupedByArea)
+ foreach (var group in groupedEntries)
{
- // Check if all entries in this area group are hidden
- var allEntriesHidden = areaGroup.All(entry =>
+ // Check if all entries in this group are hidden
+ var allEntriesHidden = group.All(entry =>
ChangelogRenderUtilities.ShouldHideEntry(entry, context.FeatureIdsToHide, context));
- var componentName = !string.IsNullOrWhiteSpace(areaGroup.Key) ? areaGroup.Key : "General";
- var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
+ // Add nested section header when subsections are enabled and group has a name
+ if (context.Subsections && !string.IsNullOrWhiteSpace(group.Key))
+ {
+ var componentName = group.Key != string.Empty ? group.Key : "General";
+ var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
- var headerLine = allEntriesHidden ? $"// {formattedComponent}::" : $"{formattedComponent}::";
- _ = sb.AppendLine(headerLine);
- _ = sb.AppendLine();
+ if (allEntriesHidden)
+ {
+ _ = sb.AppendLine("// [float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"// ==== {formattedComponent}");
+ }
+ else
+ {
+ _ = sb.AppendLine("[float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"==== {formattedComponent}");
+ }
+ _ = sb.AppendLine();
+ }
- foreach (var entry in areaGroup)
+ foreach (var entry in group)
RenderBasicEntry(sb, entry, context);
}
}
diff --git a/src/services/Elastic.Changelog/Rendering/Asciidoc/KnownIssuesAsciidocRenderer.cs b/src/services/Elastic.Changelog/Rendering/Asciidoc/KnownIssuesAsciidocRenderer.cs
index f7ff3bc34..74fac4e4f 100644
--- a/src/services/Elastic.Changelog/Rendering/Asciidoc/KnownIssuesAsciidocRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Asciidoc/KnownIssuesAsciidocRenderer.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.Text;
using Elastic.Documentation.ReleaseNotes;
@@ -15,22 +16,37 @@ public class KnownIssuesAsciidocRenderer(StringBuilder sb) : AsciidocRendererBas
///
public override void Render(IReadOnlyCollection entries, ChangelogRenderContext context)
{
- var groupedByArea = entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).OrderBy(g => g.Key).ToList();
+ // Group by area if subsections is enabled, otherwise use single group
+ var groupedEntries = context.Subsections
+ ? entries.GroupBy(e => ChangelogRenderUtilities.GetComponent(e, context)).OrderBy(g => g.Key).ToList()
+ : [entries.GroupBy(_ => string.Empty).First()];
- foreach (var areaGroup in groupedByArea)
+ foreach (var group in groupedEntries)
{
- // Check if all entries in this area group are hidden
- var allEntriesHidden = areaGroup.All(entry =>
+ // Check if all entries in this group are hidden
+ var allEntriesHidden = group.All(entry =>
ChangelogRenderUtilities.ShouldHideEntry(entry, context.FeatureIdsToHide, context));
- var componentName = !string.IsNullOrWhiteSpace(areaGroup.Key) ? areaGroup.Key : "General";
- var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
+ // Add nested section header when subsections are enabled and group has a name
+ if (context.Subsections && !string.IsNullOrWhiteSpace(group.Key))
+ {
+ var componentName = group.Key != string.Empty ? group.Key : "General";
+ var formattedComponent = ChangelogTextUtilities.FormatAreaHeader(componentName);
- var headerLine = allEntriesHidden ? $"// {formattedComponent}::" : $"{formattedComponent}::";
- _ = sb.AppendLine(headerLine);
- _ = sb.AppendLine();
+ if (allEntriesHidden)
+ {
+ _ = sb.AppendLine("// [float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"// ==== {formattedComponent}");
+ }
+ else
+ {
+ _ = sb.AppendLine("[float]");
+ _ = sb.AppendLine(CultureInfo.InvariantCulture, $"==== {formattedComponent}");
+ }
+ _ = sb.AppendLine();
+ }
- foreach (var entry in areaGroup)
+ foreach (var entry in group)
RenderEntryWithImpactAction(sb, entry, context);
}
}
diff --git a/src/services/Elastic.Changelog/Rendering/Markdown/BreakingChangesMarkdownRenderer.cs b/src/services/Elastic.Changelog/Rendering/Markdown/BreakingChangesMarkdownRenderer.cs
index 783df0253..4cee9acec 100644
--- a/src/services/Elastic.Changelog/Rendering/Markdown/BreakingChangesMarkdownRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Markdown/BreakingChangesMarkdownRenderer.cs
@@ -70,7 +70,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
_ = sb.AppendLine(InvariantCulture, $"::::{{dropdown}} {ChangelogTextUtilities.Beautify(entry.Title)}");
_ = sb.AppendLine(entry.Description ?? "% Describe the functionality that changed");
_ = sb.AppendLine();
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks));
_ = sb.AppendLine(!string.IsNullOrWhiteSpace(entry.Impact)
? "**Impact**
" + entry.Impact
@@ -99,7 +99,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
}
// PR/Issue links with "For more information" pattern - indented for list continuation
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks, indentForListItem: true);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks, IndentForListItem: true));
// Impact and Action sections - indented for list continuation
if (!string.IsNullOrWhiteSpace(entry.Impact))
diff --git a/src/services/Elastic.Changelog/Rendering/Markdown/DeprecationsMarkdownRenderer.cs b/src/services/Elastic.Changelog/Rendering/Markdown/DeprecationsMarkdownRenderer.cs
index 0d47e0a22..c5b80228b 100644
--- a/src/services/Elastic.Changelog/Rendering/Markdown/DeprecationsMarkdownRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Markdown/DeprecationsMarkdownRenderer.cs
@@ -67,7 +67,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
_ = sb.AppendLine(InvariantCulture, $"::::{{dropdown}} {ChangelogTextUtilities.Beautify(entry.Title)}");
_ = sb.AppendLine(entry.Description ?? "% Describe the functionality that was deprecated");
_ = sb.AppendLine();
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks));
_ = sb.AppendLine(!string.IsNullOrWhiteSpace(entry.Impact)
? "**Impact**
" + entry.Impact
@@ -96,7 +96,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
}
// PR/Issue links with "For more information" pattern - indented for list continuation
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks, indentForListItem: true);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks, IndentForListItem: true));
// Impact and Action sections - indented for list continuation
if (!string.IsNullOrWhiteSpace(entry.Impact))
diff --git a/src/services/Elastic.Changelog/Rendering/Markdown/HighlightsMarkdownRenderer.cs b/src/services/Elastic.Changelog/Rendering/Markdown/HighlightsMarkdownRenderer.cs
index d20a43902..5d5cf5a2e 100644
--- a/src/services/Elastic.Changelog/Rendering/Markdown/HighlightsMarkdownRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Markdown/HighlightsMarkdownRenderer.cs
@@ -70,7 +70,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
_ = sb.AppendLine(InvariantCulture, $"::::{{dropdown}} {ChangelogTextUtilities.Beautify(entry.Title)}");
_ = sb.AppendLine(entry.Description ?? "% Describe the highlight");
_ = sb.AppendLine();
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks));
_ = sb.AppendLine("::::");
}
else
@@ -88,7 +88,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
}
// PR/Issue links with "For more information" pattern - indented for list continuation
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks, indentForListItem: true);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks, IndentForListItem: true));
}
if (shouldHide)
diff --git a/src/services/Elastic.Changelog/Rendering/Markdown/KnownIssuesMarkdownRenderer.cs b/src/services/Elastic.Changelog/Rendering/Markdown/KnownIssuesMarkdownRenderer.cs
index 46e94fb34..3f6e3b22d 100644
--- a/src/services/Elastic.Changelog/Rendering/Markdown/KnownIssuesMarkdownRenderer.cs
+++ b/src/services/Elastic.Changelog/Rendering/Markdown/KnownIssuesMarkdownRenderer.cs
@@ -67,7 +67,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
_ = sb.AppendLine(InvariantCulture, $"::::{{dropdown}} {ChangelogTextUtilities.Beautify(entry.Title)}");
_ = sb.AppendLine(entry.Description ?? "% Describe the known issue");
_ = sb.AppendLine();
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks));
_ = sb.AppendLine(!string.IsNullOrWhiteSpace(entry.Impact)
? "**Impact**
" + entry.Impact
@@ -96,7 +96,7 @@ public override async Task RenderAsync(ChangelogRenderContext context, Cancel ct
}
// PR/Issue links with "For more information" pattern - indented for list continuation
- RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks, indentForListItem: true);
+ RenderPrIssueLinks(sb, new PrIssueLinkOptions(entry, entryRepo, entryOwner, entryHideLinks, IndentForListItem: true));
// Impact and Action sections - indented for list continuation
if (!string.IsNullOrWhiteSpace(entry.Impact))
diff --git a/src/services/Elastic.Changelog/Rendering/Markdown/MarkdownRendererBase.cs b/src/services/Elastic.Changelog/Rendering/Markdown/MarkdownRendererBase.cs
index 704394972..d545d6e50 100644
--- a/src/services/Elastic.Changelog/Rendering/Markdown/MarkdownRendererBase.cs
+++ b/src/services/Elastic.Changelog/Rendering/Markdown/MarkdownRendererBase.cs
@@ -10,6 +10,17 @@
namespace Elastic.Changelog.Rendering.Markdown;
+///
+/// Options for rendering PR and issue links
+///
+public record PrIssueLinkOptions(
+ ChangelogEntry Entry,
+ string Repo,
+ string Owner,
+ bool HideLinks,
+ bool IndentForListItem = false
+);
+
///
/// Abstract base class for changelog markdown renderers
///
@@ -37,28 +48,22 @@ protected async Task WriteOutputFileAsync(string outputDir, string titleSlug, st
}
///
- /// Renders PR and issue links for dropdown entries
- ///
- protected static void RenderPrIssueLinks(StringBuilder sb, ChangelogEntry entry, string entryRepo, string entryOwner, bool entryHideLinks)
- => RenderPrIssueLinks(sb, entry, entryRepo, entryOwner, entryHideLinks, indentForListItem: false);
-
- ///
- /// Renders PR and issue links with optional indentation for flattened list items
+ /// Renders PR and issue links with configurable formatting options
///
- protected static void RenderPrIssueLinks(StringBuilder sb, ChangelogEntry entry, string entryRepo, string entryOwner, bool entryHideLinks, bool indentForListItem)
+ protected static void RenderPrIssueLinks(StringBuilder sb, PrIssueLinkOptions options)
{
var prParts = new List();
- foreach (var pr in entry.Prs ?? [])
+ foreach (var pr in options.Entry.Prs ?? [])
{
- var s = ChangelogTextUtilities.FormatPrLink(pr, entryRepo, entryHideLinks, entryOwner);
+ var s = ChangelogTextUtilities.FormatPrLink(pr, options.Repo, options.HideLinks, options.Owner);
if (!string.IsNullOrEmpty(s))
prParts.Add(s);
}
var issueParts = new List();
- foreach (var issue in entry.Issues ?? [])
+ foreach (var issue in options.Entry.Issues ?? [])
{
- var s = ChangelogTextUtilities.FormatIssueLink(issue, entryRepo, entryHideLinks, entryOwner);
+ var s = ChangelogTextUtilities.FormatIssueLink(issue, options.Repo, options.HideLinks, options.Owner);
if (!string.IsNullOrEmpty(s))
issueParts.Add(s);
}
@@ -66,21 +71,21 @@ protected static void RenderPrIssueLinks(StringBuilder sb, ChangelogEntry entry,
if (prParts.Count == 0 && issueParts.Count == 0)
return;
- if (entryHideLinks)
+ if (options.HideLinks)
{
foreach (var s in prParts)
{
- var line = indentForListItem ? ChangelogTextUtilities.Indent(s) : s;
+ var line = options.IndentForListItem ? ChangelogTextUtilities.Indent(s) : s;
_ = sb.AppendLine(line);
}
foreach (var s in issueParts)
{
- var line = indentForListItem ? ChangelogTextUtilities.Indent(s) : s;
+ var line = options.IndentForListItem ? ChangelogTextUtilities.Indent(s) : s;
_ = sb.AppendLine(line);
}
var infoLine = "For more information, check the pull request or issue above.";
- _ = sb.AppendLine(indentForListItem ? ChangelogTextUtilities.Indent(infoLine) : infoLine);
+ _ = sb.AppendLine(options.IndentForListItem ? ChangelogTextUtilities.Indent(infoLine) : infoLine);
}
else
{
@@ -89,7 +94,7 @@ protected static void RenderPrIssueLinks(StringBuilder sb, ChangelogEntry entry,
lineParts.AddRange(issueParts);
var fullLine = string.Join(" ", lineParts) + ".";
- _ = sb.AppendLine(indentForListItem ? ChangelogTextUtilities.Indent(fullLine) : fullLine);
+ _ = sb.AppendLine(options.IndentForListItem ? ChangelogTextUtilities.Indent(fullLine) : fullLine);
}
_ = sb.AppendLine();
diff --git a/tests/Elastic.Changelog.Tests/Changelogs/Render/DropdownRenderTests.cs b/tests/Elastic.Changelog.Tests/Changelogs/Render/DropdownRenderTests.cs
index af37eb8f7..204fe7c0d 100644
--- a/tests/Elastic.Changelog.Tests/Changelogs/Render/DropdownRenderTests.cs
+++ b/tests/Elastic.Changelog.Tests/Changelogs/Render/DropdownRenderTests.cs
@@ -418,8 +418,8 @@ public async Task RenderChangelogs_AsciidocFormat_IgnoresDropdownsFlag()
// AsciiDoc should always use bullet format regardless of dropdowns flag
content.Should().Contain("* Breaking API change");
- content.Should().Contain("**Impact:** Existing API calls will fail");
- content.Should().Contain("**Action:** Update your code");
+ content.Should().Contain("*Impact:* Existing API calls will fail");
+ content.Should().Contain("*Action:* Update your code");
// Should never contain MyST dropdown syntax
content.Should().NotContain("::::{dropdown}");