Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#57 - Configurable regex-based Release note detection in the PR body #112

Merged
merged 5 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,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`
Expand Down Expand Up @@ -163,6 +168,7 @@ Add the following step to your GitHub workflow (in example are used non-default
published-at: true
skip-release-notes-labels: 'ignore-in-release' # changing default value of label
verbose: false
release-notes-title: '[Rr]elease Notes:'

warnings: false
print-empty-chapters: false
Expand Down
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -118,6 +122,7 @@ runs:
INPUT_SKIP_RELEASE_NOTES_LABELS: ${{ inputs.skip-release-notes-labels }}
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 }}
Expand Down
21 changes: 18 additions & 3 deletions release_notes_generator/action_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
ROW_FORMAT_ISSUE,
ROW_FORMAT_PR,
SKIP_RELEASE_NOTES_LABELS,
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
Expand Down Expand Up @@ -109,7 +111,7 @@ def get_published_at() -> bool:
return get_action_input(PUBLISHED_AT, "false").lower() == "true"

@staticmethod
def get_skip_release_notes_labels() -> list[str]:
def get_skip_release_notes_labels() -> str:
"""
Get the skip release notes label from the action inputs.
"""
Expand All @@ -125,6 +127,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:
Expand Down Expand Up @@ -179,10 +188,11 @@ def get_row_format_link_pr() -> bool:
return get_action_input(ROW_FORMAT_LINK_PR, "true").lower() == "true"

@staticmethod
def validate_inputs():
def validate_inputs() -> None:
"""
Validates the inputs provided for the release notes generator.
Logs any validation errors and exits if any are found.
@return: None
"""
errors = []

Expand Down Expand Up @@ -218,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.")
Expand All @@ -243,11 +257,12 @@ def validate_inputs():
logger.error(error)
sys.exit(1)

logging.debug("Repository: %s/%s", owner, repo_name)
logger.debug("Repository: %s/%s", owner, repo_name)
logger.debug("Tag name: %s", tag_name)
logger.debug("Chapters JSON: %s", chapters_json)
logger.debug("Published at: %s", published_at)
logger.debug("Skip release notes labels: %s", ActionInputs.get_skip_release_notes_labels())
logger.debug("Verbose logging: %s", verbose)
logger.debug("Warnings: %s", warnings)
logger.debug("Print empty chapters: %s", print_empty_chapters)
logger.debug("Release notes title: %s", release_notes_title)
21 changes: 10 additions & 11 deletions release_notes_generator/model/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"""

import logging
import re

from typing import Optional

from github.Issue import Issue
Expand All @@ -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
Expand Down Expand Up @@ -132,28 +133,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

Expand All @@ -173,7 +172,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

Expand Down Expand Up @@ -304,7 +303,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

Expand Down
3 changes: 2 additions & 1 deletion release_notes_generator/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
PUBLISHED_AT = "published-at"
SKIP_RELEASE_NOTES_LABELS = "skip-release-notes-labels"
VERBOSE = "verbose"
RELEASE_NOTES_TITLE = "release-notes-title"
RUNNER_DEBUG = "RUNNER_DEBUG"
ROW_FORMAT_ISSUE = "row-format-issue"
ROW_FORMAT_PR = "row-format-pr"
Expand All @@ -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
Expand Down
6 changes: 5 additions & 1 deletion tests/release_notes/model/test_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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
Expand Down