Skip to content

Fix multi-product rule resolution for changelog render#2889

Draft
lcawl wants to merge 1 commit intochangelog-bundle-rulesfrom
changelog-render-rules
Draft

Fix multi-product rule resolution for changelog render#2889
lcawl wants to merge 1 commit intochangelog-bundle-rulesfrom
changelog-render-rules

Conversation

@lcawl
Copy link
Contributor

@lcawl lcawl commented Mar 11, 2026

Summary

This PR relates to a bug found while testing #2874:

Make per-product type/area rules (in rules.bundle.products and rules.publish.products) resolve consistently using intersection + alphabetical first-match, with output_products / bundle Products as the authoritative product context.

The core problem

The two existing behaviors are inconsistent and both wrong for multi-product entries:

  • **changelog bundle** (GetBlockerForEntry): "first-match from the entry's own product list in YAML order" — ignores which product(s) the bundle is being assembled for; YAML order is arbitrary
  • **changelog render** (ShouldHideEntry): "any-blocks from the bundle's Products array" — too aggressive; one product's exclusion rules block the entry from a different product's output

This PR fixes the render-specific scenario.

Implementation details

  • src/services/Elastic.Changelog/Rendering/ChangelogRenderUtilities.cs:

    • GetPublishBlockerForEntry: replaced the first-match-from-iteration-order loop over bundle products with a call to the shared PublishBlockerExtensions.ResolveBlocker(bundleProducts, entryOwnIds, byProduct, globalBlocker). The contextIds are the bundle's top-level product IDs (EntryToBundleProducts[entry]); the entryOwnIds come from entry.Products.Select(p => p.ProductId).
    • ShouldHideEntry: replaced the "any-blocks" loop with a single GetPublishBlockerForEntry call, returning blocker?.ShouldBlock(entry) ?? false.
    • Removed the now-unused private GetPublishBlockerForProduct method.
  • src/services/Elastic.Changelog/Rendering/ChangelogRenderingService.cs:

    • EmitBlockedEntryWarnings: replaced the "any-blocks" loop (which would emit a warning for every product whose rule blocked the entry) with a single PublishBlockerExtensions.ResolveBlocker call per entry. The resolved blocker is checked once; if it blocks, one warning is emitted without the now-incorrect "for product X" annotation.
    • Removed the duplicate private GetPublishBlockerForProduct method.
  • tests/Elastic.Changelog.Tests/Changelogs/Render/BlockConfigurationTests.cs — three new tests:

    1. RenderChangelogs_WithMultipleProducts_SharedEntry_UsesAlphabeticalFirstMatch — bundle has [elasticsearch, kibana]; a shared entry uses the alphabetically-first (elasticsearch) rule, while a kibana-only entry has no matching rule and stays visible.
    2. RenderChangelogs_WithMultipleProducts_SingleProductEntries_UseTheirOwnRules — each single-product entry (elasticsearch, kibana) in a mixed bundle uses only its own per-product rule.
    3. RenderChangelogs_WithDisjointBundleAndEntryProducts_FallsBackToGlobalBlocker — when the bundle's products ([kibana]) and the entry's own products ([elasticsearch]) are disjoint, the algorithm falls back to the entry's own product list and then to the global blocker, ensuring that per-product rules for the bundle context don't bleed across to unrelated entries.
  • Documentation:

    • docs/contribute/changelog.md — added a paragraph to the rules.publish section explaining that the same intersection + alphabetical first-match algorithm applies to per-product rules.publish overrides, with one key difference: at render time the context comes from the bundle's top-level products: array, not from a CLI flag like --output-products. Links to the existing #changelog-bundle-multi-product-rules anchor where the algorithm is documented in full.
    • docs/syntax/changelog.md — appended three lines to the "Filtering entries with publish rules" section noting that the directive picks one product's rule via :product: and applies it to everything, while the changelog render command is what uses the intersection + alphabetical first-match algorithm with the bundle's products: array as context.
    • docs/cli/release/changelog-render.md — extended the existing "block definitions" paragraph with a note covering rules.publish.products, and linking to the algorithm reference. This is the command reference page users will land on directly, so having the pointer here means they don't have to go digging.

Generative AI disclosure

  1. Did you use a generative AI (GenAI) tool to assist in creating this contribution?
  • Yes
  • No
  1. If you answered "Yes" to the previous question, please specify the tool(s) and model(s) used (e.g., Google Gemini, OpenAI ChatGPT-4, etc.).

Tool(s) and model(s) used: composer-1.5, claude-4.6-sonnet-medium

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.

1 participant