From ec9eecc050eeb3caa55fc6b8275864f277c5e0d6 Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Tue, 9 Sep 2025 11:32:39 +0200 Subject: [PATCH] #162 - Introduce presence of Release Notes to Issues - Add support for Release notes on Issue. --- .../model/commit_record.py | 2 +- release_notes_generator/model/issue_record.py | 20 +++++++++++++------ .../model/pull_request_record.py | 2 +- release_notes_generator/model/record.py | 8 +++++--- .../utils/github_rate_limiter.py | 2 +- tests/conftest.py | 4 ++++ .../test_release_notes_builder.py | 16 +++++++++++++++ 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/release_notes_generator/model/commit_record.py b/release_notes_generator/model/commit_record.py index e9813078..3fe666cf 100644 --- a/release_notes_generator/model/commit_record.py +++ b/release_notes_generator/model/commit_record.py @@ -52,7 +52,7 @@ def commit(self) -> Commit: # methods - override Record methods def to_chapter_row(self) -> str: - self.added_into_chapters() + super().to_chapter_row() row_prefix = f"{ActionInputs.get_duplicity_icon()} " if self.present_in_chapters() > 1 else "" # collecting values for formatting diff --git a/release_notes_generator/model/issue_record.py b/release_notes_generator/model/issue_record.py index 27d31d94..1b4c351c 100644 --- a/release_notes_generator/model/issue_record.py +++ b/release_notes_generator/model/issue_record.py @@ -79,7 +79,7 @@ def issue_type(self) -> Optional[str]: # methods - override Record methods def to_chapter_row(self) -> str: - self.added_into_chapters() + super().to_chapter_row() row_prefix = f"{ActionInputs.get_duplicity_icon()} " if self.present_in_chapters() > 1 else "" format_values: dict[str, Any] = {} @@ -115,6 +115,10 @@ def get_rls_notes(self, line_marks: Optional[list[str]] = None) -> str: # Code Rabbit detection regex cr_active: bool = ActionInputs.is_coderabbit_support_active() + # Get release notes from Issue + if self._issue.body and detection_regex.search(self._issue.body): + release_notes += self._get_rls_notes_default(self._issue, line_marks, detection_regex) + # Iterate over all PRs for pull in self._pull_requests.values(): if pull.body and detection_regex.search(pull.body): @@ -213,21 +217,25 @@ def get_pr_links(self) -> list[str]: return res - def _get_rls_notes_default(self, pull: PullRequest, line_marks: list[str], detection_regex: re.Pattern[str]) -> str: + def _get_rls_notes_default( + self, record: Issue | PullRequest, line_marks: list[str], detection_regex: re.Pattern[str] + ) -> str: """ Extracts release notes from the pull request body based on the provided line marks and detection regex. Parameters: - pull (PullRequest): The pull request from which to extract release notes. + record (Issue or PullRequest): The issue or pull request from which to extract release notes. line_marks (list[str]): A list of characters that indicate the start of a release notes section. detection_regex (re.Pattern[str]): A regex pattern to detect the start of the release notes section. Returns: str: The extracted release notes as a string. If no release notes are found, returns an empty string. """ # TODO - this code will be changes soon, there is wish from project to manage different release notes - if not pull.body: - return "" + match record.body: + case None | "": + return "" + case str() as body: + lines = body.splitlines() - lines = pull.body.splitlines() release_notes_lines = [] found_section = False diff --git a/release_notes_generator/model/pull_request_record.py b/release_notes_generator/model/pull_request_record.py index e3fc8953..005ded8f 100644 --- a/release_notes_generator/model/pull_request_record.py +++ b/release_notes_generator/model/pull_request_record.py @@ -107,7 +107,7 @@ def contributors(self) -> list[str]: # methods - override Record methods def to_chapter_row(self) -> str: - self.added_into_chapters() + super().to_chapter_row() row_prefix = f"{ActionInputs.get_duplicity_icon()} " if self.present_in_chapters() > 1 else "" format_values: dict[str, Any] = {} diff --git a/release_notes_generator/model/record.py b/release_notes_generator/model/record.py index 0e6bda90..250789d5 100644 --- a/release_notes_generator/model/record.py +++ b/release_notes_generator/model/record.py @@ -101,14 +101,16 @@ def authors(self) -> list[str]: list[str]: A list of authors associated with the record. """ - # abstract methods - - @abstractmethod + # to be overridden by subclasses and called via super() as the first line def to_chapter_row(self) -> str: """ Converts the record to a string row in a chapter. @return: The record as a row string. """ + self.added_into_chapters() + return "" + + # abstract methods @abstractmethod def get_rls_notes(self, line_marks: Optional[list[str]] = None) -> str: diff --git a/release_notes_generator/utils/github_rate_limiter.py b/release_notes_generator/utils/github_rate_limiter.py index 599ce7d5..018549e8 100644 --- a/release_notes_generator/utils/github_rate_limiter.py +++ b/release_notes_generator/utils/github_rate_limiter.py @@ -21,7 +21,7 @@ import logging import time from datetime import datetime -from typing import Optional, Callable, Any, cast +from typing import Optional, Callable, Any from github import Github logger = logging.getLogger(__name__) diff --git a/tests/conftest.py b/tests/conftest.py index 28c6592e..cb2a179d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -129,6 +129,7 @@ def mock_issue_open(mocker): issue.number = 122 issue.title = "I1 open" issue.state_reason = None + issue.body = "I1 open" label1 = mocker.Mock(spec=MockLabel) label1.name = "label1" @@ -146,6 +147,7 @@ def mock_issue_open_2(mocker): issue.number = 123 issue.title = "I2 open" issue.state_reason = None + issue.body = "I2 open" label1 = mocker.Mock(spec=MockLabel) label1.name = "label1" @@ -162,6 +164,7 @@ def mock_issue_closed(mocker): issue.state = IssueRecord.ISSUE_STATE_CLOSED issue.title = "Fix the bug" issue.number = 121 + issue.body = "Some issue body text" label1 = mocker.Mock(spec=MockLabel) label1.name = "label1" @@ -178,6 +181,7 @@ def mock_issue_closed_i1_bug(mocker): issue.state = IssueRecord.ISSUE_STATE_CLOSED issue.title = "I1+bug" issue.number = 122 + issue.body = "Some issue body text\nRelease Notes:\n- Fixed bug\n- Improved performance\n+ More nice code\n * Awesome architecture" label1 = mocker.Mock(spec=MockLabel) label1.name = "label1" diff --git a/tests/release_notes/test_release_notes_builder.py b/tests/release_notes/test_release_notes_builder.py index b02595c0..3eeaaef3 100644 --- a/tests/release_notes/test_release_notes_builder.py +++ b/tests/release_notes/test_release_notes_builder.py @@ -140,6 +140,10 @@ def __init__(self, name): RELEASE_NOTES_DATA_CUSTOM_CHAPTERS_ONE_LABEL = """### Chapter 1 🛠 - #122 _I1+bug_ in #101, #102 + - Fixed bug + - Improved performance + + More nice code + * Awesome architecture - PR 101 1st release note - PR 101 2nd release note - PR 102 1st release note @@ -151,6 +155,10 @@ def __init__(self, name): RELEASE_NOTES_DATA_CUSTOM_CHAPTERS_MORE_LABELS_DUPLICITY_REDUCTION_ON = """### Chapter 1 🛠 - #122 _I1+bug-enhancement_ in #101, #102 + - Fixed bug + - Improved performance + + More nice code + * Awesome architecture - PR 101 1st release note - PR 101 2nd release note - PR 102 1st release note @@ -237,6 +245,10 @@ def __init__(self, name): RELEASE_NOTES_DATA_CLOSED_ISSUE_WITH_PR_WITHOUT_USER_LABELS = """### Closed Issues without User Defined Labels ⚠️ - #122 _I1_ in #101, #102 + - Fixed bug + - Improved performance + + More nice code + * Awesome architecture - PR 101 1st release note - PR 101 2nd release note - PR 102 1st release note @@ -293,6 +305,10 @@ def __init__(self, name): - #122 _I1+bug_ in #123 - Fixed bug - Improved performance + + More nice code + * Awesome architecture + - Fixed bug + - Improved performance #### Full Changelog http://example.com/changelog