Skip to content

Commit 9e917b1

Browse files
committed
Add optional dependencies section
1 parent fcde501 commit 9e917b1

File tree

5 files changed

+128
-2
lines changed

5 files changed

+128
-2
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ pr_summary_regex = "^```release-note\\s*(?P<summary>[\\s\\S]*?\\w[\\s\\S]*?)\\s*
141141
# group named "label".
142142
pr_summary_label_regex = """{[^}]*?label=[\\"](?P<label>[^\\"]+)[^}]*?}"""
143143

144+
# Show the required Python version if `project.requires-python` is present
145+
# in the pyproject.toml at the last given revision.
146+
show_required_python = true
147+
148+
# Show the required dependencies if `project.dependencies` is present
149+
# in the pyproject.toml at the last given revision.
150+
show_required_dependencies = true
151+
152+
# Show the given optional dependencies if `project.optional-dependencies` is
153+
# present in the pyproject.toml at the last given revision.
154+
# E.g. ["test"]
155+
show_optional_dependencies = []
156+
144157
# If any of a pull request's labels matches one of the regexes on the left side
145158
# its summary will appear in the appropriate section with the title given on
146159
# the right side. If a pull request doesn't match one of these categories it is

src/changelist/_cli.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
from ._config import add_config_defaults, local_config, remote_config
1414
from ._format import MdFormatter, RstFormatter
1515
from ._objects import ChangeNote, Contributor
16-
from ._query import commits_between, contributors, pull_requests_from_commits
16+
from ._query import (
17+
commits_between,
18+
contributors,
19+
pull_requests_from_commits,
20+
pyproject_dependencies,
21+
)
1722

1823
logger = logging.getLogger(__name__)
1924

@@ -152,6 +157,29 @@ def main(
152157
pull_requests=lazy_tqdm(pull_requests, desc="Fetching reviewers"),
153158
)
154159

160+
python_dep = None
161+
required_deps = []
162+
optional_deps = {}
163+
if config.keys() & {
164+
"show_required_python",
165+
"show_required_dependencies",
166+
"show_optional_dependencies",
167+
}:
168+
print("Fetching dependencies...", file=sys.stderr)
169+
python_dep, required_deps, optional_deps = pyproject_dependencies(
170+
gh, org_repo, stop_rev
171+
)
172+
if not config["show_required_python"]:
173+
python_dep = None
174+
if not config["show_required_dependencies"]:
175+
required_deps = []
176+
if config["show_optional_dependencies"]:
177+
optional_deps = {
178+
key: value
179+
for key, value in optional_deps.items()
180+
if key in config["show_optional_dependencies"]
181+
}
182+
155183
print("Formatting notes...", file=sys.stderr)
156184
change_notes = ChangeNote.from_pull_requests(
157185
pull_requests,
@@ -165,6 +193,9 @@ def main(
165193
change_notes=change_notes,
166194
authors=Contributor.from_named_users(authors),
167195
reviewers=Contributor.from_named_users(reviewers),
196+
required_python=python_dep,
197+
required_dependencies=required_deps,
198+
optional_dependencies=optional_deps,
168199
version=version,
169200
title_template=config["title_template"],
170201
intro_template=config["intro_template"],

src/changelist/_format.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class MdFormatter:
1717
change_notes: set[ChangeNote]
1818
authors: set[Contributor]
1919
reviewers: set[Contributor]
20+
required_python: str
21+
required_dependencies: Iterable[str]
22+
optional_dependencies: dict[str, Iterable[str]]
2023

2124
version: str
2225
title_template: str
@@ -51,6 +54,11 @@ def iter_lines(self) -> Iterable[str]:
5154
yield from self._format_intro()
5255
for title, notes in self._notes_by_section.items():
5356
yield from self._format_change_section(title, notes)
57+
yield from self._format_dependencies_section(
58+
required_python=self.required_python,
59+
required_dependencies=self.required_dependencies,
60+
optional_dependencies=self.optional_dependencies,
61+
)
5462
yield from self._format_contributor_section(self.authors, self.reviewers)
5563
yield from self._format_outro()
5664

@@ -146,6 +154,39 @@ def _format_contributor_section(
146154
yield from sorted(reviewers_lines, key=lambda s: s.lower())
147155
yield "\n"
148156

157+
def _format_dependencies_section(
158+
self, required_python, required_dependencies, optional_dependencies
159+
):
160+
if required_python or required_dependencies or optional_dependencies:
161+
yield from self._format_section_title("Dependencies", level=2)
162+
yield "\n"
163+
164+
if required_python:
165+
yield f"Python `{required_python}` is required.\n"
166+
yield "\n"
167+
168+
if required_dependencies:
169+
yield "Required dependencies:\n"
170+
yield "\n"
171+
for dep in sorted(required_dependencies, key=lambda x: x.lower()):
172+
line = f"`{dep}`"
173+
line = self._sanitize_text(line)
174+
yield f"- {line}\n"
175+
yield "\n"
176+
177+
if optional_dependencies:
178+
yield "Optional dependencies:\n"
179+
yield "\n"
180+
for name, deps in optional_dependencies.items():
181+
line = f"`{name}`"
182+
line = self._sanitize_text(line)
183+
yield f"- {line}\n"
184+
for dep in sorted(deps, key=lambda x: x.lower()):
185+
line = f"`{dep}`"
186+
line = self._sanitize_text(line)
187+
yield f" - {line}\n"
188+
yield "\n"
189+
149190
def _format_intro(self):
150191
intro = self.intro_template.format(
151192
repo_name=self.repo_name, version=self.version

src/changelist/_query.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
44
from collections.abc import Iterable
55
from dataclasses import dataclass
66

7+
try:
8+
import tomllib
9+
except ModuleNotFoundError:
10+
import tomli as tomllib
11+
712
import requests
8-
from github import Github
13+
from github import Github, UnknownObjectException
914
from github.Commit import Commit
1015
from github.NamedUser import NamedUser
1116
from github.PullRequest import PullRequest
@@ -174,3 +179,26 @@ def contributors(
174179
reviewers.add(review.user)
175180

176181
return authors, reviewers
182+
183+
184+
def pyproject_dependencies(
185+
gh: Github,
186+
org_repo: str,
187+
rev: str,
188+
) -> tuple[str | None, list[str], dict[str, list[str]]]:
189+
"""Fetch dependencies from pyproject.toml at the given revision."""
190+
repo = gh.get_repo(org_repo)
191+
try:
192+
file = repo.get_contents("pyproject.toml", ref=rev)
193+
logger.debug("found pyproject.toml in %s@%s", org_repo, rev)
194+
content = file.decoded_content.decode()
195+
except UnknownObjectException:
196+
content = ""
197+
pyproject = tomllib.loads(content)
198+
pyproject = pyproject.get("project", {})
199+
200+
python_dep = pyproject.get("requires-python")
201+
runtime_deps = pyproject.get("dependencies", [])
202+
extra_deps = pyproject.get("optional-dependencies", {})
203+
204+
return python_dep, runtime_deps, extra_deps

src/changelist/default_config.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ pr_summary_regex = "^```release-note\\s*(?P<summary>[\\s\\S]*?\\w[\\s\\S]*?)\\s*
6060
# group named "label".
6161
pr_summary_label_regex = """{[^}]*?label=[\\"](?P<label>[^\\"]+)[^}]*?}"""
6262

63+
# Show the required Python version if `project.requires-python` is present
64+
# in the pyproject.toml at the last given revision.
65+
show_required_python = true
66+
67+
# Show the required dependencies if `project.dependencies` is present
68+
# in the pyproject.toml at the last given revision.
69+
show_required_dependencies = true
70+
71+
# Show the given optional dependencies if `project.optional-dependencies` is
72+
# present in the pyproject.toml at the last given revision.
73+
# E.g. ["test"]
74+
show_optional_dependencies = []
75+
6376
# If any of a pull request's labels matches one of the regexes on the left side
6477
# its summary will appear in the appropriate section with the title given on
6578
# the right side. If a pull request doesn't match one of these categories it is

0 commit comments

Comments
 (0)