Skip to content

Commit 26857e7

Browse files
committed
feat: add PR link support to changelog schema
Signed-off-by: Rohit Agrawal <[email protected]>
1 parent 56937ac commit 26857e7

File tree

5 files changed

+45
-16
lines changed

5 files changed

+45
-16
lines changed

envoy.base.utils/envoy/base/utils/abstract/project/changelog.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import logging
32
import pathlib
43
import re
@@ -95,9 +94,18 @@ def lines(self) -> list[str]:
9594

9695
def _parse_line(self, line: str) -> typing.ChangeDict:
9796
area, change = line[2:].split(":", 1)
98-
return dict(
99-
area=area,
100-
change=typing.Change(change.lstrip(" ")))
97+
98+
# Try to extract PR reference from the change text if it exists
99+
pr_match = re.search(r"(?:PR |#)(\d+)", change)
100+
pr = pr_match.group(1) if pr_match else None
101+
102+
result: typing.ChangeDict = {
103+
"area": area,
104+
"change": typing.Change(change.lstrip(" "))
105+
}
106+
if pr:
107+
result["pr"] = pr
108+
return result
101109

102110

103111
@abstracts.implementer(interface.IChangelogEntry)
@@ -125,6 +133,10 @@ def area(self) -> str:
125133
def change(self) -> str:
126134
return self.entry["change"]
127135

136+
@property
137+
def pr(self) -> str | None:
138+
return self.entry.get("pr")
139+
128140

129141
@abstracts.implementer(interface.IChangelog)
130142
class AChangelog(metaclass=abstracts.Abstraction):
@@ -141,7 +153,8 @@ def get_data(cls, path) -> typing.ChangelogDict:
141153
{k: (v
142154
if k == "date"
143155
else [dict(area=c["area"],
144-
change=typing.Change(c["change"]))
156+
change=typing.Change(c["change"]),
157+
**({"pr": c["pr"]} if "pr" in c else {}))
145158
for c
146159
in v])
147160
for k, v

envoy.base.utils/envoy/base/utils/interface.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from __future__ import annotations
32

43
import pathlib
@@ -128,6 +127,12 @@ def change(self) -> str:
128127
"""Description of the change for this entry."""
129128
raise NotImplementedError
130129

130+
@property
131+
@abstracts.interfacemethod
132+
def pr(self) -> str | None:
133+
"""PR reference number for this entry."""
134+
raise NotImplementedError
135+
131136

132137
class IChangelog(metaclass=abstracts.Interface):
133138
"""A changelog."""

envoy.base.utils/envoy/base/utils/typing.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
21
import pathlib
3-
from typing import TypedDict
2+
from typing import TypedDict, NotRequired
43

54
from packaging import version as _version
65

@@ -16,11 +15,13 @@ def __add__(self, other: str) -> "Change":
1615
class SourceChangeDict(TypedDict):
1716
area: str
1817
change: str
18+
pr: NotRequired[str] # Optional PR reference
1919

2020

2121
class ChangeDict(TypedDict):
2222
area: str
2323
change: Change
24+
pr: NotRequired[str] # Optional PR reference
2425

2526

2627
ChangeList = list[ChangeDict]

envoy.base.utils/tests/test_abstract_project_changelogs.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import json
32
import pathlib
43
import types
@@ -1340,18 +1339,25 @@ def test_legacy_changelog_lines():
13401339
def test_legacy_changelog__parse_line(patches):
13411340
legacy = abstract.project.changelog.LegacyChangelog("CONTENT")
13421341
patched = patches(
1342+
"re",
13431343
"dict",
13441344
"typing",
13451345
prefix="envoy.base.utils.abstract.project.changelog")
13461346
line = MagicMock()
13471347
area = MagicMock()
13481348
change = MagicMock()
13491349
line.__getitem__.return_value.split.return_value = [area, change]
1350+
pr_match = MagicMock()
1351+
pr_match.group.return_value = "12345"
13501352

1351-
with patched as (m_dict, m_typing):
1352-
assert (
1353-
legacy._parse_line(line)
1354-
== m_dict.return_value)
1353+
with patched as (m_re, m_dict, m_typing):
1354+
m_re.search.return_value = pr_match
1355+
m_typing.Change.return_value = typing.Change("Test Change")
1356+
assert legacy._parse_line(line) == {
1357+
"area": area,
1358+
"change": m_typing.Change.return_value,
1359+
"pr": "12345"
1360+
}
13551361

13561362
assert (
13571363
line.__getitem__.call_args
@@ -1360,8 +1366,11 @@ def test_legacy_changelog__parse_line(patches):
13601366
line.__getitem__.return_value.split.call_args
13611367
== [(":", 1), {}])
13621368
assert (
1363-
m_dict.call_args
1364-
== [(), dict(area=area, change=m_typing.Change.return_value)])
1369+
m_re.search.call_args
1370+
== [(r"(?:PR |#)(\d+)", change), {}])
1371+
assert (
1372+
pr_match.group.call_args
1373+
== [(1,), {}])
13651374
assert (
13661375
m_typing.Change.call_args
13671376
== [(change.lstrip.return_value, ), {}])

envoy.base.utils/tests/test_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ def test_cd_and_return(path):
206206

207207
with utils.cd_and_return(path):
208208
assert pathlib.Path.cwd() != cwd
209-
assert pathlib.Path.cwd() == pathlib.Path("/tmp")
209+
# On macOS, /tmp is a symlink to /private/tmp
210+
assert pathlib.Path.cwd().resolve() == pathlib.Path("/tmp").resolve()
210211

211212
assert pathlib.Path.cwd() == cwd
212213

0 commit comments

Comments
 (0)