Skip to content

Commit

Permalink
Do not fail when unknown placeholder received (#115)
Browse files Browse the repository at this point in the history
* # Do not fail when unknown placeholder received
- ActionInput now can hold static values.
- Improved unknown placeholder logic for detection and removing of them.
  • Loading branch information
miroslavpojer authored Nov 25, 2024
1 parent adeae67 commit 9191d81
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 41 deletions.
46 changes: 41 additions & 5 deletions release_notes_generator/action_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import logging
import os
import sys
import re

from release_notes_generator.utils.constants import (
GITHUB_REPOSITORY,
Expand All @@ -41,10 +42,10 @@
SKIP_RELEASE_NOTES_LABELS,
RELEASE_NOTES_TITLE,
RELEASE_NOTE_TITLE_DEFAULT,
SUPPORTED_ROW_FORMAT_KEYS,
)
from release_notes_generator.utils.enums import DuplicityScopeEnum
from release_notes_generator.utils.gh_action import get_action_input
from release_notes_generator.utils.utils import detect_row_format_invalid_keywords

logger = logging.getLogger(__name__)

Expand All @@ -55,6 +56,10 @@ class ActionInputs:
A class representing the inputs provided to the GH action.
"""

_row_format_issue = None
_row_format_pr = None
_row_format_link_pr = None

@staticmethod
def get_github_repository() -> str:
"""
Expand Down Expand Up @@ -171,14 +176,22 @@ def get_row_format_issue() -> str:
"""
Get the issue row format for the release notes.
"""
return get_action_input(ROW_FORMAT_ISSUE, "{number} _{title}_ in {pull-requests}").strip()
if ActionInputs._row_format_issue is None:
ActionInputs._row_format_issue = ActionInputs._detect_row_format_invalid_keywords(
get_action_input(ROW_FORMAT_ISSUE, "{number} _{title}_ in {pull-requests}").strip(), clean=True
)
return ActionInputs._row_format_issue

@staticmethod
def get_row_format_pr() -> str:
"""
Get the pr row format for the release notes.
"""
return get_action_input(ROW_FORMAT_PR, "{number} _{title}_").strip()
if ActionInputs._row_format_pr is None:
ActionInputs._row_format_pr = ActionInputs._detect_row_format_invalid_keywords(
get_action_input(ROW_FORMAT_PR, "{number} _{title}_").strip(), clean=True
)
return ActionInputs._row_format_pr

@staticmethod
def get_row_format_link_pr() -> bool:
Expand Down Expand Up @@ -236,13 +249,13 @@ def validate_inputs() -> None:
if not isinstance(row_format_issue, str) or not row_format_issue.strip():
errors.append("Issue row format must be a non-empty string.")

errors.extend(detect_row_format_invalid_keywords(row_format_issue))
ActionInputs._detect_row_format_invalid_keywords(row_format_issue)

row_format_pr = ActionInputs.get_row_format_pr()
if not isinstance(row_format_pr, str) or not row_format_pr.strip():
errors.append("PR Row format must be a non-empty string.")

errors.extend(detect_row_format_invalid_keywords(row_format_pr, row_type="PR"))
ActionInputs._detect_row_format_invalid_keywords(row_format_pr, row_type="PR")

row_format_link_pr = ActionInputs.get_row_format_link_pr()
ActionInputs.validate_input(row_format_link_pr, bool, "'row-format-link-pr' value must be a boolean.", errors)
Expand All @@ -266,3 +279,26 @@ def validate_inputs() -> None:
logger.debug("Warnings: %s", warnings)
logger.debug("Print empty chapters: %s", print_empty_chapters)
logger.debug("Release notes title: %s", release_notes_title)

@staticmethod
def _detect_row_format_invalid_keywords(row_format: str, row_type: str = "Issue", clean: bool = False) -> str:
"""
Detects invalid keywords in the row format.
@param row_format: The row format to be checked for invalid keywords.
@param row_type: The type of row format. Default is "Issue".
@return: If clean is True, the cleaned row format. Otherwise, the original row format.
"""
keywords_in_braces = re.findall(r"\{(.*?)\}", row_format)
invalid_keywords = [keyword for keyword in keywords_in_braces if keyword not in SUPPORTED_ROW_FORMAT_KEYS]
cleaned_row_format = row_format
for invalid_keyword in invalid_keywords:
logger.error(
"Invalid `{}` detected in `{}` row format keyword(s) found: {}. Will be removed from string.".format(
invalid_keyword, row_type, ", ".join(invalid_keywords)
)
)
if clean:
cleaned_row_format = cleaned_row_format.replace(f"{{{invalid_keyword}}}", "")

return cleaned_row_format
19 changes: 0 additions & 19 deletions release_notes_generator/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@
"""

import logging
import re

from typing import Optional

from github.GitRelease import GitRelease
from github.Repository import Repository

from release_notes_generator.utils.constants import SUPPORTED_ROW_FORMAT_KEYS

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -57,19 +54,3 @@ def get_change_url(
changelog_url = f"https://github.com/{repo.full_name}/compare/{rls.tag_name}...{tag_name}"

return changelog_url


def detect_row_format_invalid_keywords(row_format: str, row_type: str = "Issue") -> list[str]:
"""
Detects invalid keywords in the row format.
@param row_format: The row format to be checked for invalid keywords.
@param row_type: The type of row format. Default is "Issue".
@return: A list of errors if invalid keywords are found, otherwise an empty list.
"""
errors = []
keywords_in_braces = re.findall(r"\{(.*?)\}", row_format)
invalid_keywords = [keyword for keyword in keywords_in_braces if keyword not in SUPPORTED_ROW_FORMAT_KEYS]
if invalid_keywords:
errors.append(f"Invalid {row_type} row format keyword(s) found: {', '.join(invalid_keywords)}")
return errors
37 changes: 37 additions & 0 deletions tests/test_action_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
import logging

import pytest

Expand Down Expand Up @@ -43,6 +44,8 @@
("get_verbose", "not_bool", "Verbose logging must be a boolean."),
("get_duplicity_icon", "", "Duplicity icon must be a non-empty string and have a length of 1."),
("get_duplicity_icon", "Oj", "Duplicity icon must be a non-empty string and have a length of 1."),
("get_row_format_issue", "", "Issue row format must be a non-empty string."),
("get_row_format_pr", "", "PR Row format must be a non-empty string."),
]


Expand Down Expand Up @@ -163,3 +166,37 @@ def test_get_duplicity_scope_wrong_value(mocker):

assert ActionInputs.get_duplicity_scope() == "BOTH"
mock_error.assert_called_with("Error: '%s' is not a valid DuplicityType.", "HUH")


def test_detect_row_format_invalid_keywords_no_invalid_keywords(caplog):
caplog.set_level(logging.ERROR)
row_format = "{number} _{title}_ in {pull-requests}"
ActionInputs._detect_row_format_invalid_keywords(row_format)
assert len(caplog.records) == 0


def test_detect_row_format_invalid_keywords_with_invalid_keywords(caplog):
caplog.set_level(logging.ERROR)
row_format = "{number} _{title}_ in {pull-requests} {invalid_key} {another_invalid}"
ActionInputs._detect_row_format_invalid_keywords(row_format)
assert len(caplog.records) == 2
expected_errors = [
"Invalid `invalid_key` detected in `Issue` row format keyword(s) found: invalid_key, another_invalid. Will be removed from string.",
"Invalid `another_invalid` detected in `Issue` row format keyword(s) found: invalid_key, another_invalid. Will be removed from string."
]
actual_errors = [record.getMessage() for record in caplog.records]
assert actual_errors == expected_errors


def test_clean_row_format_invalid_keywords_no_keywords():
expected_row_format = "{number} _{title}_ in {pull-requests}"
actual_format = ActionInputs._detect_row_format_invalid_keywords(expected_row_format, clean=True)
assert expected_row_format == actual_format


def test_clean_row_format_invalid_keywords_nested_braces():
row_format = "{number} _{title}_ in {pull-requests} {invalid_key} {another_invalid}"
expected_format = "{number} _{title}_ in {pull-requests} "
actual_format = ActionInputs._detect_row_format_invalid_keywords(row_format, clean=True)
assert expected_format == actual_format

6 changes: 6 additions & 0 deletions tests/test_release_notes_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from release_notes_generator.generator import ReleaseNotesGenerator
from release_notes_generator.model.custom_chapters import CustomChapters
from release_notes_generator.utils.constants import ROW_FORMAT_ISSUE


# generate_release_notes tests
Expand Down Expand Up @@ -111,6 +112,11 @@ def test_generate_release_notes_latest_release_found_by_created_at(
mock_rate_limit.core.remaining = 1000
github_mock.get_rate_limit.return_value = mock_rate_limit

mock_get_action_input = mocker.patch("release_notes_generator.utils.gh_action.get_action_input")
mock_get_action_input.side_effect = lambda first_arg, **kwargs: (
"{number} _{title}_ in {pull-requests} {unknown} {another-unknown}" if first_arg == ROW_FORMAT_ISSUE else None
)

custom_chapters = CustomChapters(print_empty_chapters=True)

release_notes = ReleaseNotesGenerator(github_mock, custom_chapters).generate()
Expand Down
18 changes: 1 addition & 17 deletions tests/utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# limitations under the License.
#

from release_notes_generator.utils.utils import get_change_url, detect_row_format_invalid_keywords
from release_notes_generator.utils.utils import get_change_url


# get_change_url
Expand All @@ -33,19 +33,3 @@ def test_get_change_url_no_git_release(mock_repo):
def test_get_change_url_with_git_release(mock_repo, mock_git_release):
url = get_change_url(tag_name="v2.0.0", repository=mock_repo, git_release=mock_git_release)
assert url == "https://github.com/org/repo/compare/v1.0.0...v2.0.0"


# detect_row_format_invalid_keywords


def test_valid_row_format():
row_format = "{number} - {title} in {pull-requests}"
errors = detect_row_format_invalid_keywords(row_format)
assert not errors, "Expected no errors for valid keywords"


def test_multiple_invalid_keywords():
row_format = "{number} - {link} - {Title} and {Pull-requests}"
errors = detect_row_format_invalid_keywords(row_format)
assert len(errors) == 1
assert "Invalid Issue row format keyword(s) found: link, Title, Pull-requests" in errors[0]

0 comments on commit 9191d81

Please sign in to comment.