packagekit: link issue references in Markdown changelogs

Markdown changelogs are rendered with markdown-to-jsx, so issue
references in them were not linked like in plain-text changelogs. Use
a renderRule to run text nodes through renderChangelogWithIssueLinks(),
skipping text that is already inside a Markdown link or an <a> tag.

state.inAnchor is only set while parsing, not while rendering, so track
link nesting ourselves: a link's children are rendered inside its
next() call.

Add a Markdown entry to the mock updates for manual testing.
This commit is contained in:
Tarun Vashishtha 2026-10-15 12:03:44 +00:00 committed by Freya Gustavsson
parent ca996825df
commit d0bfdf0d03
No known key found for this signature in database
2 changed files with 38 additions and 1 deletions

View file

@ -127,4 +127,16 @@ export function injectMockUpdates(updates) {
severity: 4,
description: "Fixes rhbz#12345 and RHEL-67890 in one update.",
});
// Markdown changelog: plain references get linked, existing links are kept as they are
updates.push({
id: "tracker-links-markdown;1-1",
name: "tracker-links-markdown",
version: "1-1",
bug_urls: [],
cve_urls: [],
severity: 4,
description: "Fixes rhbz#12345 and *RHEL-67890*\n\n * already linked: [RHEL-11111](https://redhat.atlassian.net/browse/RHEL-11111)\n * not a reference: `RHEL-22222`",
markdown: true,
});
}

View file

@ -41,7 +41,7 @@ import {
SecurityIcon,
} from "@patternfly/react-icons";
import { TableText } from "@patternfly/react-table";
import Markdown from "markdown-to-jsx";
import Markdown, { RuleType } from "markdown-to-jsx";
import { AutoUpdates, getBackend } from "./autoupdates.jsx";
import { KpatchSettings, KpatchStatus } from "./kpatch";
@ -473,6 +473,30 @@ function isSafeUrl(href) {
}
}
// Link issue references in Markdown text, except for text that is already part of a link.
// markdown-to-jsx renders a node's children inside its next() call, so track link nesting
// here; state.inAnchor is only set while parsing, not while rendering.
let markdownLinkDepth = 0;
function renderMarkdownWithIssueLinks(next, node, _renderChildren, state) {
if (node.type === RuleType.link || (node.type === RuleType.htmlBlock && node.tag === "a")) {
markdownLinkDepth++;
try {
return next();
} finally {
markdownLinkDepth--;
}
}
if (node.type === RuleType.text && markdownLinkDepth === 0) {
const linked = renderChangelogWithIssueLinks(node.text);
if (linked !== node.text)
return <React.Fragment key={state.key}>{linked}</React.Fragment>;
}
return next();
}
const markdownOptions = {
overrides: {
a: {
@ -483,6 +507,7 @@ const markdownOptions = {
},
},
forceInline: true,
renderRule: renderMarkdownWithIssueLinks,
};
function updateItem(info, pkgNames, key, partialUpdates) {