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}");