Skip to content

Conversation

@cotti
Copy link
Contributor

@cotti cotti commented Jan 27, 2026

Summary

This PR brings the {changelog} directive to feature parity with the changelog render CLI command.

Key improvements:

  • Support for date-based version sorting (Cloud Serverless style: 2025-08-05)
  • New directive options:
    • :type: — Filter entries by type
    • :subsections: — Group entries by area/component
    • :config: — Explicit path to changelog.yml
  • Automatic loading of changelog.yml configuration for publish blockers

Automatic behaviors (no configuration needed):

  • Bundle merging for same target versions
  • Private repository link hiding (via assembler.yml)
  • Publish blocker filtering (via changelog.yml)
  • Table of contents generation for right-hand navigation

New Directive Options

:::{changelog} /path/to/bundles
:subsections:                   % Group entries by area (default: false)
:config: /path/to/changelog.yml % Explicit config path
:type: all                      % Determine the release notes content by type (default: all except known-issue/deprecation/breaking-change)
:::

Options

Option Description Default
:type: value Filter entries by type Excludes separated types
:subsections: Group entries by area/component false
:config: path Path to changelog.yml auto-discover

:type: Values

Value Description
(omitted) Default: excludes known issues, breaking changes, deprecations
all Shows all entry types
breaking-change Shows only breaking changes
deprecation Shows only deprecations
known-issue Shows only known issues

Refactorings

Relocated and consolidated release notes types:

Before After
Elastic.Changelog.Serialization.* Elastic.Documentation.Configuration.ReleaseNotes.*
Elastic.Markdown.Myst.Directives.Changelog.LoadedBundle Elastic.Documentation.ReleaseNotes.LoadedBundle
Mapperly dependency for mapping Native serialization with ReleaseNotesSerialization

Test Plan

  • All changelog directive tests pass
  • dotnet format verification passes
  • dotnet build succeeds

@cotti cotti self-assigned this Jan 27, 2026
@cotti cotti requested review from a team as code owners January 27, 2026 16:40
@cotti cotti requested a review from reakaleek January 27, 2026 16:40
@cotti cotti added the feature label Jan 27, 2026
@github-actions
Copy link

github-actions bot commented Jan 27, 2026

@lcawl
Copy link
Contributor

lcawl commented Jan 27, 2026

Thanks for making these enhancements!

Simple single-repo use case

I tested against the simple single-repo elasticsearch use case (using files from elastic/elasticsearch#140795) and the subsections option works there.
The issues in this case are:

  • :hide-features: if I'm understanding correctly will apply to all changelogs uniformly, but a feature might be hidden in 9.2.1 and unhidden in 9.4.5, so I don't think it's feasible to apply it this way.
  • Order of types. Since all types of changelogs are on a single page, I think the more severe types should be prioritized (i.e. breaking changes, known issues, security issues, and deprecations before fixes/features/enhancements/other).
  • The items from the changelog directive are missing from the left nav. Can that be fixed?

Multi-repo use case

I also tested against the multi-repo Cloud Serverless use case, which is more complex because:

  1. The changelogs and bundles exist in a different repo than the docs.
  2. One of the three repos is a private repo and thus we only want to hide PR and issue links for that specific bundle.
  3. At the moment we'd want to continue publishing all three bundles merged together, though that isn't mandatory if their release cadences eventually diverge.

I've drafted the test in elastic/docs-content#4843, which happily seems to support not copying the changelogs over as long as the bundles were created with --resolve (maybe that should be a documented requirement for this use case?)

The issues in the case seem to be:

  • The block declarations in the changelog configuration file don't seem to take effect (i.e. I'm still seeing "Docs" type changelog and "Snapshot & restore" area changelogs, for example). You can compare to Serverless release note test docs-content#4627 to see the desired results. BTW if you haven't already done so, once it's heeding the "block" clauses, you'll also need logic to remove empty sections, akin to what I was wrestling with in Fix changelog render empty sections #2569
  • The :merge: clause is behaving differently than I would expect. It looks like the three bundles are listed one after another with identical headers rather than being merged. (Though the same problem does not seem to occur when I test locally)
  • The :hide-links: don't work as desired in this case, since if it's declared all PR and issue links are removed, but we only want them hidden for the elasticsearch-serverless (private) repo in this case.

@Mpdreamz
Copy link
Member

Nice work!

I want to discuss the options:

:hide-links:                    % Hide all PR/issue links
:hide-features: feat-1, feat-2  % Hide entries with these feature IDs  
:subsections:                   % Group entries by area (default: false)
:config: /path/to/changelog.yml % Explicit config path
:merge:                         % Merge bundles with same target into single section

I think its better to be prescriptive and uniformity is a feature.

:hide-links: is this to prevent links to private repositories? This should be autodetected. (from assembler.yml private on repos). If not we should standardize to showing it IMO

:hide-features: this should be covered by the block.publish in the changelog.yml configuration.

:subsections: again I think we should standardize and be uniform and do the grouping. If it really needs to be an option this should be an option in changelog.yml's pivot.*

:config: there should be no need for this, the changelog.yml should always live next to docset.yml and should always be autodiscovered.

:merge: can you elaborate when this could happen? Not questioning it but want to make sure I share the same assumptions. If we do I think this should be the default behavior and not configurable.

Copy link
Member

@Mpdreamz Mpdreamz left a comment

Choose a reason for hiding this comment

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

Some small code nits and a question about directive properties.

/// 2. changelog.yml in the docset root
/// 3. docs/changelog.yml relative to docset root
/// </summary>
private void LoadConfiguration()
Copy link
Member

Choose a reason for hiding this comment

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

This should load ChangelogConfigurationLoader we probably want to inject a singleton in IServices for the configuration like we do for other configurations.

if (string.IsNullOrWhiteSpace(configPath))
return;

PublishBlocker = ChangelogConfigurationLoader.LoadPublishBlocker(fileSystem, configPath);
Copy link
Member

Choose a reason for hiding this comment

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

This should be read from the singleton changelog config

Copy link
Member

Choose a reason for hiding this comment

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

wait it can be a singleton in assembler builds but it can be shared on the relevant BuidContext. Which would make it available in markdown parsers.

/// </summary>
/// <param name="bundles">The sorted list of bundles to merge.</param>
/// <returns>A list of bundles where same-target bundles are merged.</returns>
private static List<LoadedBundle> MergeBundlesByTarget(List<LoadedBundle> bundles)
Copy link
Member

Choose a reason for hiding this comment

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

This should live in Elastic.Changelog as a service.

:hide-features: feat-1 , feat-2 , feat-3
:::
""") => FileSystem.AddFile("docs/changelog/bundles/9.3.0.yaml", new MockFileData(
"""
Copy link
Member

Choose a reason for hiding this comment

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

ultra nit add // language=yaml and // language=markdown hints to these so they highlight in supporting editors.

@Mpdreamz
Copy link
Member

@cotti I also implemented a similar merge for .amend-N.yaml bundle files in #2577

@lcawl
Copy link
Contributor

lcawl commented Jan 27, 2026

Here are my two cents with respect to Martijn's comments:

:hide-links: is this to prevent links to private repositories? This should be autodetected. (from assembler.yml private on repos). If not we should standardize to showing it IMO

Yes, for example the links to the elasticsearch-serverless repo in elastic/docs-content#4627 test. That would be great if it could be auto-detected and auto-hidden.

:hide-features: this should be covered by the block.publish in the changelog.yml configuration.

This relates to the --hide-features option described in https://docs-v3-preview.elastic.dev/elastic/docs-builder/tree/main/cli/release/changelog-render. There doesn't seem to be anything in the changelog configuration file (e.g. https://github.com/elastic/docs-builder/blob/main/config/changelog.example.yml) that maps to that yet. If it is added, per my earlier comment, it will need to be release/bundle-specific, since a feature could be "hidden" in release X but "unhidden" in release X+1 (and we don't want to unhide it in X when we unhide it in X+1 if that makes sense). If this means we need to push that metadata into the bundle itself, that's fine by me.

:subsections: again I think we should standardize and be uniform and do the grouping. If it really needs to be an option this should be an option in changelog.yml's pivot.*

Right now it reflects the difference between the way we handle release notes in Cloud vs Stack (e.g. no sections in https://www.elastic.co/docs/release-notes/cloud-serverless and sections in https://www.elastic.co/docs/release-notes/elasticsearch). I don't know the history of why they don't have sections in the Cloud context, so I was just matching the existing behaviour in the short-term.

:config: there should be no need for this, the changelog.yml should always live next to docset.yml and should always be autodiscovered.

IMO it's worth keeping in case we are publishing two or more release notes from a single repo. Currently that's true for the docs-content repo (though I haven't tried combining the Cloud Serverless and Observability and Security release notes into a single config file yet... maybe it's doable).

:merge: can you elaborate when this could happen? Not questioning it but want to make sure I share the same assumptions. If we do I think this should be the default behavior and not configurable.

This is currently for the use case where we're releasing bundles from multiple repos on the same date (e.g. the Cloud Serverless use case tested in elastic/docs-content#4627 and elastic/docs-content#4843)

@Mpdreamz
Copy link
Member

Here are my two cents with respect to Martijn's comments:

:hide-links: is this to prevent links to private repositories? This should be autodetected. (from assembler.yml private on repos). If not we should standardize to showing it IMO

Yes, for example the links to the elasticsearch-serverless repo in elastic/docs-content#4627 test. That would be great if it could be auto-detected and auto-hidden.

Cool we can! 😸

:hide-features: this should be covered by the block.publish in the changelog.yml configuration.

This relates to the --hide-features option described in https://docs-v3-preview.elastic.dev/elastic/docs-builder/tree/main/cli/release/changelog-render. There doesn't seem to be anything in the changelog configuration file (e.g. https://github.com/elastic/docs-builder/blob/main/config/changelog.example.yml) that maps to that yet. If it is added, per my earlier comment, it will need to be release/bundle-specific, since a feature could be "hidden" in release X but "unhidden" in release X+1 (and we don't want to unhide it in X when we unhide it in X+1 if that makes sense). If this means we need to push that metadata into the bundle itself, that's fine by me.

++ we need to encode that information into the bundle.

A bundle profile (see #2577) could list the features to hide and bake it into the bundle. That way folks can update the config prior to the bundle being created by automation.

We could even extend bundle-amend (see #2577) to add a filter after the fact in the bundle amend files.

:subsections: again I think we should standardize and be uniform and do the grouping. If it really needs to be an option this should be an option in changelog.yml's pivot.*

Right now it reflects the difference between the way we handle release notes in Cloud vs Stack (e.g. no sections in https://www.elastic.co/docs/release-notes/cloud-serverless and sections in https://www.elastic.co/docs/release-notes/elasticsearch). I don't know the history of why they don't have sections in the Cloud context, so I was just matching the existing behaviour in the short-term.

Ok if its really needed lets use the config for this, ideally we normalize this if folks do not have a strong opinion.

:config: there should be no need for this, the changelog.yml should always live next to docset.yml and should always be autodiscovered.

IMO it's worth keeping in case we are publishing two or more release notes from a single repo. Currently that's true for the docs-content repo (though I haven't tried combining the Cloud Serverless and Observability and Security release notes into a single config file yet... maybe it's doable).

Can you tell me more why docs-content is doing multiple release-notes?

:merge: can you elaborate when this could happen? Not questioning it but want to make sure I share the same assumptions. If we do I think this should be the default behavior and not configurable.

This is currently for the use case where we're releasing bundles from multiple repos on the same date (e.g. the Cloud Serverless use case tested in elastic/docs-content#4627 and elastic/docs-content#4843)

Cool, I think we should always merge and not expose this option.

@lcawl
Copy link
Contributor

lcawl commented Jan 27, 2026

Can you tell me more why docs-content is doing multiple release-notes?

The https://www.elastic.co/docs/release-notes/observability and https://www.elastic.co/docs/release-notes/security are a subset of the Kibana release notes (split off by area) so I'm not sure why they are being stored in docs-content but even if they were stored in the kibana repo, the question will be whether they can all be reasonably generated from a single changelog.yml or whether we need to support multiple. I think it should be doable to put in a single, so I'll mock up a test.

@cotti cotti requested a review from Mpdreamz January 30, 2026 14:38
Copy link
Member

@Mpdreamz Mpdreamz left a comment

Choose a reason for hiding this comment

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

LGTM

I do think we should remove :config: path but lets follow up :)

@cotti
Copy link
Contributor Author

cotti commented Jan 30, 2026

Summary: Review Comments → Commits Mapping

Here's a breakdown of which commits addressed which review feedback:


@Mpdreamz's Directive Options Discussion

Comment Commit(s) Status
:hide-links: should be auto-detected from private repos a9e3165e - Remove :hide-links:, use default inferred behavior ✅ Addressed
:hide-features: should be covered by block.publish in config 1deddc40 - Remove :hide-features: in favor of leveraging changelog data itself ✅ Addressed
:merge: should be default behavior, not configurable 8a138f40 - Remove :merge:, keep it as default behavior ✅ Addressed
:subsections: should standardize or move to config Still present as option ⏳ Follow-up needed
:config: path - should auto-discover Still present as option ⏳ Follow-up needed (per Mpdreamz's approval comment)

@Mpdreamz's Code Architecture Comments

Comment Commit(s) Status
LoadConfiguration should use ChangelogConfigurationLoader singleton fcb83d9e, eb97846e, 20757ea7 - Introduce BundleLoader service ✅ Addressed
MergeBundlesByTarget should live in Elastic.Changelog as a service fcb83d9e - Introduce bundle loading to Elastic.Changelog
eb97846e - Move functionality to dedicated service
20757ea7 - Use BundleLoader service
✅ Addressed
Add // language=yaml and // language=markdown hints to tests d0ae5de4 - Adjust formatting and hinting for changelog tests ✅ Addressed

github-code-quality bot: Path.Combine Warnings

Comment Commit(s) Status
Path.Combine may silently drop earlier arguments (multiple instances) f441db0a - Remove Path.Combine warnings, add extension method to IDirectoryInfo
60a3b5da - Remove Path.Combine calls
✅ Addressed

@lcawl's Testing Feedback

Issue Commit(s) Status
Items from changelog directive missing from left nav 3152fec6 - Collect ToC for changelog ✅ Addressed
:hide-features: not release-specific Removed in 1deddc40 (deferred to changelog data itself) ✅ Deferred to config
Order of types (severity prioritization) Not directly addressed ⏳ May need follow-up
block declarations not taking effect May need verification ❓ Needs testing
:hide-links: too broad (per-repo control needed) Auto-inferred now via a9e3165e ✅ Deferred to private repo detection

Additional Enhancements (New Functionality)

Commit Description
7e08e911 Add :types: parameter to support partial changelog displays
09f2880d Add sub-pages for Release Notes example
ab0eea18 Refactor and relocate data types to Elastic.Documentation
2909c30d Separate Deserializer for minimal changelog DTOs
8b9b5ad2 Unify data model usage, remove Mapperly dependence

Outstanding Items for Follow-up

Per Mpdreamz's approval comment:

"LGTM - I do think we should remove :config: path but lets follow up :)"

The :config: and :subsections: options remain for now and may be addressed in future iterations.

@cotti cotti merged commit 2e86d13 into main Jan 30, 2026
31 checks passed
@cotti cotti deleted the feature/changelog-directive-enhancements branch January 30, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants