diff --git a/src/utils/__tests__/changelog-extract.test.ts b/src/utils/__tests__/changelog-extract.test.ts
index ba119ca8..c64fb637 100644
--- a/src/utils/__tests__/changelog-extract.test.ts
+++ b/src/utils/__tests__/changelog-extract.test.ts
@@ -302,3 +302,126 @@ func foo() {}
expect(result).toBeNull();
});
});
+
+describe('extractChangelogEntry HTML blocks', () => {
+ it('preserves
tag after paragraph as nested content', () => {
+ const prBody = `### Changelog Entry
+
+Add a chart rendering engine for \`sentry dashboard view\`.
+
+
+
+### Next Section`;
+
+ const result = extractChangelogEntry(prBody);
+ expect(result).toHaveLength(1);
+ expect(result![0].text).toBe(
+ 'Add a chart rendering engine for `sentry dashboard view`.',
+ );
+ expect(result![0].nestedContent).toContain('
tag after list item as nested content', () => {
+ const prBody = `### Changelog Entry
+
+- Added dashboard charts
+
+
`;
+
+ const result = extractChangelogEntry(prBody);
+ expect(result).toHaveLength(1);
+ expect(result![0].text).toBe('Added dashboard charts');
+ expect(result![0].nestedContent).toContain('
{
+ const prBody = `### Changelog Entry
+
+
+
+### Next Section`;
+
+ const result = extractChangelogEntry(prBody);
+ // A bare HTML block without descriptive text is not a meaningful entry
+ expect(result).toBeNull();
+ });
+
+ it('preserves inline
within paragraph text', () => {
+ const prBody = `### Changelog Entry
+
+See the result:
pretty cool`;
+
+ const result = extractChangelogEntry(prBody);
+ expect(result).toHaveLength(1);
+ // Inline HTML within a paragraph is preserved in the text itself
+ expect(result![0].text).toContain('
{
+ const prBody = `### Changelog Entry
+
+- Entry with code and image:
+ \`\`\`go
+ func foo() {}
+ \`\`\`
+
+
`;
+
+ const result = extractChangelogEntry(prBody);
+ expect(result).toHaveLength(1);
+ expect(result![0].text).toBe('Entry with code and image:');
+ expect(result![0].nestedContent).toContain('```go');
+ expect(result![0].nestedContent).toContain('
{
+ // GitHub stores uploaded images as HTML img tags with width/height
+ const prBody = `## Changelog Entry
+
+Add a full chart rendering engine.
+
+
+
+## Chart Types`;
+
+ const result = extractChangelogEntry(prBody);
+ expect(result).toHaveLength(1);
+ expect(result![0].text).toBe('Add a full chart rendering engine.');
+ expect(result![0].nestedContent).toContain('width="2512"');
+ expect(result![0].nestedContent).toContain(
+ 'src="https://github.com/user-attachments/assets/abc123"',
+ );
+ });
+
+ it('indents all lines of multi-line HTML blocks', () => {
+ const prBody = `### Changelog Entry
+
+Added collapsible details section.
+
+
+Click to expand
+Some hidden content here.
+ `;
+
+ const result = extractChangelogEntry(prBody);
+ expect(result).toHaveLength(1);
+ expect(result![0].text).toBe('Added collapsible details section.');
+ // Every line should be indented with 2 spaces
+ const lines = result![0].nestedContent!.split('\n');
+ for (const line of lines) {
+ expect(line).toMatch(/^ {2}/);
+ }
+ expect(result![0].nestedContent).toContain(' ');
+ expect(result![0].nestedContent).toContain(
+ ' Click to expand
',
+ );
+ expect(result![0].nestedContent).toContain(' ');
+ });
+});
diff --git a/src/utils/changelog.ts b/src/utils/changelog.ts
index 6dbdb8b0..b2eb618f 100644
--- a/src/utils/changelog.ts
+++ b/src/utils/changelog.ts
@@ -428,6 +428,24 @@ function parseTokensToEntries(tokens: Token[]): ChangelogEntryItem[] | null {
}
// If no previous entry exists, skip the orphaned code block — a bare
// code block without descriptive text isn't a meaningful changelog entry.
+ } else if (token.type === 'html') {
+ // HTML blocks (e.g.,
tags from GitHub image uploads) become
+ // nested content on the previous entry, similar to code blocks.
+ // Indent every line with 2 spaces so multi-line HTML (e.g., ,
+ // ) nests properly under the list item in the final markdown.
+ const htmlContent = (token as Tokens.HTML).raw.trim();
+ if (htmlContent && entries.length > 0) {
+ const indented = htmlContent
+ .split('\n')
+ .map(line => ` ${line}`)
+ .join('\n');
+ const prev = entries[entries.length - 1];
+ prev.nestedContent = prev.nestedContent
+ ? `${prev.nestedContent}\n${indented}`
+ : indented;
+ }
+ // If no previous entry exists, skip — an orphaned HTML block
+ // without descriptive text isn't a meaningful changelog entry.
}
}