diff --git a/README.md b/README.md index 0418a35b..7518221e 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,11 @@ Generate Release Notes action is dedicated to enhance the quality and organizati - **Default**: false - **Note**: If workflow run in debug regime, 'verbose' logging is activated. +### `release-notes-title` +- **Description**: The title of the release notes section in the PR description. +- **Required**: No +- **Default**: `[Rr]elease [Nn]otes:` + ### Feature controls ### `warnings` @@ -159,6 +164,7 @@ Add the following step to your GitHub workflow (in example are used non-default published-at: true skip-release-notes-label: 'ignore-in-release' # changing default value of label verbose: false + release-notes-title: '[Rr]elease Notes:' warnings: false print-empty-chapters: false diff --git a/action.yml b/action.yml index 41c27ee9..96ce3176 100644 --- a/action.yml +++ b/action.yml @@ -51,6 +51,10 @@ inputs: description: 'Print verbose logs.' required: false default: 'false' + release-notes-title: + description: 'The title of the release notes section in the PR body. Value supports regex.' + required: false + default: '[Rr]elease [Nn]otes:' row-format-issue: description: 'Format of the issue row in the release notes. Available placeholders: {number}, {title}, {pull-requests}. Placeholders are case-insensitive.' required: false @@ -118,6 +122,7 @@ runs: INPUT_SKIP_RELEASE_NOTES_LABEL: ${{ inputs.skip-release-notes-label }} INPUT_PRINT_EMPTY_CHAPTERS: ${{ inputs.print-empty-chapters }} INPUT_VERBOSE: ${{ inputs.verbose }} + INPUT_RELEASE_NOTES_TITLE: ${{ inputs.release-notes-title }} INPUT_GITHUB_REPOSITORY: ${{ github.repository }} INPUT_ROW_FORMAT_ISSUE: ${{ inputs.row-format-issue }} INPUT_ROW_FORMAT_PR: ${{ inputs.row-format-pr }} diff --git a/release_notes_generator/action_inputs.py b/release_notes_generator/action_inputs.py index a0fd326e..36d036a2 100644 --- a/release_notes_generator/action_inputs.py +++ b/release_notes_generator/action_inputs.py @@ -39,6 +39,8 @@ ROW_FORMAT_LINK_PR, ROW_FORMAT_ISSUE, ROW_FORMAT_PR, + RELEASE_NOTES_TITLE, + RELEASE_NOTE_TITLE_DEFAULT, ) from release_notes_generator.utils.enums import DuplicityScopeEnum from release_notes_generator.utils.gh_action import get_action_input @@ -122,6 +124,13 @@ def get_verbose() -> bool: """ return os.getenv(RUNNER_DEBUG, "0") == "1" or get_action_input(VERBOSE).lower() == "true" + @staticmethod + def get_release_notes_title() -> str: + """ + Get the release notes title from the action inputs. + """ + return get_action_input(RELEASE_NOTES_TITLE, RELEASE_NOTE_TITLE_DEFAULT) + # Features @staticmethod def get_warnings() -> bool: @@ -219,6 +228,10 @@ def validate_inputs(): verbose = ActionInputs.get_verbose() ActionInputs.validate_input(verbose, bool, "Verbose logging must be a boolean.", errors) + release_notes_title = ActionInputs.get_release_notes_title() + if not isinstance(release_notes_title, str) or len(release_notes_title) == 0: + errors.append("Release Notes title must be a non-empty string and have non-zero length.") + row_format_issue = ActionInputs.get_row_format_issue() if not isinstance(row_format_issue, str) or not row_format_issue.strip(): errors.append("Issue row format must be a non-empty string.") diff --git a/release_notes_generator/model/record.py b/release_notes_generator/model/record.py index e4780aca..571ba3a6 100644 --- a/release_notes_generator/model/record.py +++ b/release_notes_generator/model/record.py @@ -19,6 +19,8 @@ """ import logging +import re + from typing import Optional from github.Issue import Issue @@ -31,7 +33,6 @@ PR_STATE_CLOSED, ISSUE_STATE_CLOSED, ISSUE_STATE_OPEN, - RELEASE_NOTE_DETECTION_PATTERN, RELEASE_NOTE_LINE_MARKS, ) from release_notes_generator.utils.pull_reuqest_utils import extract_issue_numbers_from_body @@ -126,28 +127,26 @@ def labels(self) -> list[str]: return [label.name for label in self.__gh_issue.labels] - # TODO in Issue named 'Configurable regex-based Release note detection in the PR body' - # - 'Release notest:' as detection pattern default - can be defined by user - # - '-' as leading line mark for each release note to be used - def get_rls_notes( - self, detection_pattern=RELEASE_NOTE_DETECTION_PATTERN, line_marks=RELEASE_NOTE_LINE_MARKS - ) -> str: + def get_rls_notes(self, detection_pattern: str, line_marks: str = RELEASE_NOTE_LINE_MARKS) -> str: """ Gets the release notes of the record. - @param detection_pattern: The detection pattern to use. + @param detection_pattern: The detection pattern (regex allowed) to use. @param line_marks: The line marks to use. @return: The release notes of the record as a string. """ release_notes = "" + # Compile the regex pattern for efficiency + detection_regex = re.compile(detection_pattern) + # Iterate over all PRs for pull in self.__pulls: body_lines = pull.body.split("\n") if pull.body is not None else [] inside_release_notes = False for line in body_lines: - if detection_pattern in line: + if detection_regex.search(line): # Use regex search inside_release_notes = True continue @@ -167,7 +166,7 @@ def contains_release_notes(self) -> bool: if self.__is_release_note_detected: return self.__is_release_note_detected - rls_notes: str = self.get_rls_notes() + rls_notes: str = self.get_rls_notes(detection_pattern=ActionInputs.get_release_notes_title()) if any(mark in rls_notes for mark in RELEASE_NOTE_LINE_MARKS): self.__is_release_note_detected = True @@ -298,7 +297,7 @@ def to_chapter_row(self) -> str: row = f"{row_prefix}" + ActionInputs.get_row_format_issue().format(**format_values) if self.contains_release_notes: - row = f"{row}\n{self.get_rls_notes()}" + row = f"{row}\n{self.get_rls_notes(detection_pattern=ActionInputs.get_release_notes_title())}" return row diff --git a/release_notes_generator/utils/constants.py b/release_notes_generator/utils/constants.py index 5b4b3377..1cd45468 100644 --- a/release_notes_generator/utils/constants.py +++ b/release_notes_generator/utils/constants.py @@ -28,6 +28,7 @@ PUBLISHED_AT = "published-at" SKIP_RELEASE_NOTES_LABEL = "skip-release-notes-label" VERBOSE = "verbose" +RELEASE_NOTES_TITLE = "release-notes-title" RUNNER_DEBUG = "RUNNER_DEBUG" ROW_FORMAT_ISSUE = "row-format-issue" ROW_FORMAT_PR = "row-format-pr" @@ -48,7 +49,7 @@ ISSUE_STATE_ALL = "all" # Release notes comment constants -RELEASE_NOTE_DETECTION_PATTERN = "Release Notes:" +RELEASE_NOTE_TITLE_DEFAULT = "[Rr]elease [Nn]otes:" RELEASE_NOTE_LINE_MARKS = ["-", "*", "+"] # Service chapters titles diff --git a/tests/release_notes/model/test_record.py b/tests/release_notes/model/test_record.py index d7df6ee3..9aa3e81e 100644 --- a/tests/release_notes/model/test_record.py +++ b/tests/release_notes/model/test_record.py @@ -18,6 +18,7 @@ from github.Commit import Commit +from release_notes_generator.action_inputs import ActionInputs from release_notes_generator.utils.constants import ISSUE_STATE_CLOSED, PR_STATE_CLOSED @@ -67,7 +68,10 @@ def test_record_properties_authors_contributors(record_with_no_issue_one_pull_cl def test_get_rls_notes(record_with_no_issue_one_pull_closed): expected_notes = " - Fixed bug\n - Improved performance\n + More nice code\n * Awesome architecture" - assert record_with_no_issue_one_pull_closed.get_rls_notes() == expected_notes + assert record_with_no_issue_one_pull_closed.get_rls_notes(detection_pattern=ActionInputs.get_release_notes_title()) == expected_notes + +def test_get_rls_notes_not_detected(record_with_no_issue_one_pull_closed): + assert '' == record_with_no_issue_one_pull_closed.get_rls_notes(detection_pattern="XXX") # contains_release_notes