Coverage for cz_keep_a_changelog_plugin/utils.py: 100.00%
23 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-01 14:01 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-01 14:01 +0000
1"""Utils."""
3import re
5import jinja2 as j2
7MD_LINK_PATTERN: re.Pattern[str] = re.compile(r"\[[^\]]*\]\([^)]+\)")
8GH_ISSUE_PATTERN: re.Pattern[str] = re.compile(r"(?<!\w)#(?P<issue_num>\d+)\b")
11def replace_github_issues(
12 text: str,
13 issue_url_template: j2.Template,
14) -> str:
15 """Replace GitHub issue numbers `"#123"` by a corresponding markdown link.
17 Notes:
18 Ignores GitHub issue numbers in markdown links.
20 Args:
21 text: The text to replace the GitHub issue numbers in.
22 issue_url_template: The issue URL template (`issue` will be replaced by
23 the issue number).
25 Returns:
26 The text with replaced GitHub issue numbers.
27 """
28 link_spans: list[tuple[int, int]] = [
29 (m.start(), m.end()) for m in MD_LINK_PATTERN.finditer(text)
30 ]
31 link_spans.sort()
33 out = []
34 i_link = 0
35 i_text = 0
37 for m in GH_ISSUE_PATTERN.finditer(text):
38 start, end = m.span()
39 while i_link < len(link_spans) and link_spans[i_link][1] <= start:
40 i_link += 1
41 # Skip in case of overlap with link
42 if (
43 i_link < len(link_spans)
44 and link_spans[i_link][0] <= start < link_spans[i_link][1]
45 ):
46 continue
47 # Append text inbetween
48 out.append(text[i_text:start])
49 # Append issue url
50 issue_num = m.group("issue_num")
51 issue_url = issue_url_template.render(issue=issue_num)
52 out.append(f"[#{issue_num:s}]({issue_url:s})")
53 # Set start of next text part to end
54 i_text = end
56 out.append(text[i_text:])
57 return "".join(out)