Skip to content

Commit 9191d81

Browse files
Do not fail when unknown placeholder received (#115)
* # Do not fail when unknown placeholder received - ActionInput now can hold static values. - Improved unknown placeholder logic for detection and removing of them.
1 parent adeae67 commit 9191d81

File tree

5 files changed

+85
-41
lines changed

5 files changed

+85
-41
lines changed

release_notes_generator/action_inputs.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import logging
2323
import os
2424
import sys
25+
import re
2526

2627
from release_notes_generator.utils.constants import (
2728
GITHUB_REPOSITORY,
@@ -41,10 +42,10 @@
4142
SKIP_RELEASE_NOTES_LABELS,
4243
RELEASE_NOTES_TITLE,
4344
RELEASE_NOTE_TITLE_DEFAULT,
45+
SUPPORTED_ROW_FORMAT_KEYS,
4446
)
4547
from release_notes_generator.utils.enums import DuplicityScopeEnum
4648
from release_notes_generator.utils.gh_action import get_action_input
47-
from release_notes_generator.utils.utils import detect_row_format_invalid_keywords
4849

4950
logger = logging.getLogger(__name__)
5051

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

59+
_row_format_issue = None
60+
_row_format_pr = None
61+
_row_format_link_pr = None
62+
5863
@staticmethod
5964
def get_github_repository() -> str:
6065
"""
@@ -171,14 +176,22 @@ def get_row_format_issue() -> str:
171176
"""
172177
Get the issue row format for the release notes.
173178
"""
174-
return get_action_input(ROW_FORMAT_ISSUE, "{number} _{title}_ in {pull-requests}").strip()
179+
if ActionInputs._row_format_issue is None:
180+
ActionInputs._row_format_issue = ActionInputs._detect_row_format_invalid_keywords(
181+
get_action_input(ROW_FORMAT_ISSUE, "{number} _{title}_ in {pull-requests}").strip(), clean=True
182+
)
183+
return ActionInputs._row_format_issue
175184

176185
@staticmethod
177186
def get_row_format_pr() -> str:
178187
"""
179188
Get the pr row format for the release notes.
180189
"""
181-
return get_action_input(ROW_FORMAT_PR, "{number} _{title}_").strip()
190+
if ActionInputs._row_format_pr is None:
191+
ActionInputs._row_format_pr = ActionInputs._detect_row_format_invalid_keywords(
192+
get_action_input(ROW_FORMAT_PR, "{number} _{title}_").strip(), clean=True
193+
)
194+
return ActionInputs._row_format_pr
182195

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

239-
errors.extend(detect_row_format_invalid_keywords(row_format_issue))
252+
ActionInputs._detect_row_format_invalid_keywords(row_format_issue)
240253

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

245-
errors.extend(detect_row_format_invalid_keywords(row_format_pr, row_type="PR"))
258+
ActionInputs._detect_row_format_invalid_keywords(row_format_pr, row_type="PR")
246259

247260
row_format_link_pr = ActionInputs.get_row_format_link_pr()
248261
ActionInputs.validate_input(row_format_link_pr, bool, "'row-format-link-pr' value must be a boolean.", errors)
@@ -266,3 +279,26 @@ def validate_inputs() -> None:
266279
logger.debug("Warnings: %s", warnings)
267280
logger.debug("Print empty chapters: %s", print_empty_chapters)
268281
logger.debug("Release notes title: %s", release_notes_title)
282+
283+
@staticmethod
284+
def _detect_row_format_invalid_keywords(row_format: str, row_type: str = "Issue", clean: bool = False) -> str:
285+
"""
286+
Detects invalid keywords in the row format.
287+
288+
@param row_format: The row format to be checked for invalid keywords.
289+
@param row_type: The type of row format. Default is "Issue".
290+
@return: If clean is True, the cleaned row format. Otherwise, the original row format.
291+
"""
292+
keywords_in_braces = re.findall(r"\{(.*?)\}", row_format)
293+
invalid_keywords = [keyword for keyword in keywords_in_braces if keyword not in SUPPORTED_ROW_FORMAT_KEYS]
294+
cleaned_row_format = row_format
295+
for invalid_keyword in invalid_keywords:
296+
logger.error(
297+
"Invalid `{}` detected in `{}` row format keyword(s) found: {}. Will be removed from string.".format(
298+
invalid_keyword, row_type, ", ".join(invalid_keywords)
299+
)
300+
)
301+
if clean:
302+
cleaned_row_format = cleaned_row_format.replace(f"{{{invalid_keyword}}}", "")
303+
304+
return cleaned_row_format

release_notes_generator/utils/utils.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,12 @@
1919
"""
2020

2121
import logging
22-
import re
2322

2423
from typing import Optional
2524

2625
from github.GitRelease import GitRelease
2726
from github.Repository import Repository
2827

29-
from release_notes_generator.utils.constants import SUPPORTED_ROW_FORMAT_KEYS
30-
3128
logger = logging.getLogger(__name__)
3229

3330

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

5956
return changelog_url
60-
61-
62-
def detect_row_format_invalid_keywords(row_format: str, row_type: str = "Issue") -> list[str]:
63-
"""
64-
Detects invalid keywords in the row format.
65-
66-
@param row_format: The row format to be checked for invalid keywords.
67-
@param row_type: The type of row format. Default is "Issue".
68-
@return: A list of errors if invalid keywords are found, otherwise an empty list.
69-
"""
70-
errors = []
71-
keywords_in_braces = re.findall(r"\{(.*?)\}", row_format)
72-
invalid_keywords = [keyword for keyword in keywords_in_braces if keyword not in SUPPORTED_ROW_FORMAT_KEYS]
73-
if invalid_keywords:
74-
errors.append(f"Invalid {row_type} row format keyword(s) found: {', '.join(invalid_keywords)}")
75-
return errors

tests/test_action_inputs.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16+
import logging
1617

1718
import pytest
1819

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

4851

@@ -163,3 +166,37 @@ def test_get_duplicity_scope_wrong_value(mocker):
163166

164167
assert ActionInputs.get_duplicity_scope() == "BOTH"
165168
mock_error.assert_called_with("Error: '%s' is not a valid DuplicityType.", "HUH")
169+
170+
171+
def test_detect_row_format_invalid_keywords_no_invalid_keywords(caplog):
172+
caplog.set_level(logging.ERROR)
173+
row_format = "{number} _{title}_ in {pull-requests}"
174+
ActionInputs._detect_row_format_invalid_keywords(row_format)
175+
assert len(caplog.records) == 0
176+
177+
178+
def test_detect_row_format_invalid_keywords_with_invalid_keywords(caplog):
179+
caplog.set_level(logging.ERROR)
180+
row_format = "{number} _{title}_ in {pull-requests} {invalid_key} {another_invalid}"
181+
ActionInputs._detect_row_format_invalid_keywords(row_format)
182+
assert len(caplog.records) == 2
183+
expected_errors = [
184+
"Invalid `invalid_key` detected in `Issue` row format keyword(s) found: invalid_key, another_invalid. Will be removed from string.",
185+
"Invalid `another_invalid` detected in `Issue` row format keyword(s) found: invalid_key, another_invalid. Will be removed from string."
186+
]
187+
actual_errors = [record.getMessage() for record in caplog.records]
188+
assert actual_errors == expected_errors
189+
190+
191+
def test_clean_row_format_invalid_keywords_no_keywords():
192+
expected_row_format = "{number} _{title}_ in {pull-requests}"
193+
actual_format = ActionInputs._detect_row_format_invalid_keywords(expected_row_format, clean=True)
194+
assert expected_row_format == actual_format
195+
196+
197+
def test_clean_row_format_invalid_keywords_nested_braces():
198+
row_format = "{number} _{title}_ in {pull-requests} {invalid_key} {another_invalid}"
199+
expected_format = "{number} _{title}_ in {pull-requests} "
200+
actual_format = ActionInputs._detect_row_format_invalid_keywords(row_format, clean=True)
201+
assert expected_format == actual_format
202+

tests/test_release_notes_generator.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from release_notes_generator.generator import ReleaseNotesGenerator
2323
from release_notes_generator.model.custom_chapters import CustomChapters
24+
from release_notes_generator.utils.constants import ROW_FORMAT_ISSUE
2425

2526

2627
# generate_release_notes tests
@@ -111,6 +112,11 @@ def test_generate_release_notes_latest_release_found_by_created_at(
111112
mock_rate_limit.core.remaining = 1000
112113
github_mock.get_rate_limit.return_value = mock_rate_limit
113114

115+
mock_get_action_input = mocker.patch("release_notes_generator.utils.gh_action.get_action_input")
116+
mock_get_action_input.side_effect = lambda first_arg, **kwargs: (
117+
"{number} _{title}_ in {pull-requests} {unknown} {another-unknown}" if first_arg == ROW_FORMAT_ISSUE else None
118+
)
119+
114120
custom_chapters = CustomChapters(print_empty_chapters=True)
115121

116122
release_notes = ReleaseNotesGenerator(github_mock, custom_chapters).generate()

tests/utils/test_utils.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# limitations under the License.
1515
#
1616

17-
from release_notes_generator.utils.utils import get_change_url, detect_row_format_invalid_keywords
17+
from release_notes_generator.utils.utils import get_change_url
1818

1919

2020
# get_change_url
@@ -33,19 +33,3 @@ def test_get_change_url_no_git_release(mock_repo):
3333
def test_get_change_url_with_git_release(mock_repo, mock_git_release):
3434
url = get_change_url(tag_name="v2.0.0", repository=mock_repo, git_release=mock_git_release)
3535
assert url == "https://github.com/org/repo/compare/v1.0.0...v2.0.0"
36-
37-
38-
# detect_row_format_invalid_keywords
39-
40-
41-
def test_valid_row_format():
42-
row_format = "{number} - {title} in {pull-requests}"
43-
errors = detect_row_format_invalid_keywords(row_format)
44-
assert not errors, "Expected no errors for valid keywords"
45-
46-
47-
def test_multiple_invalid_keywords():
48-
row_format = "{number} - {link} - {Title} and {Pull-requests}"
49-
errors = detect_row_format_invalid_keywords(row_format)
50-
assert len(errors) == 1
51-
assert "Invalid Issue row format keyword(s) found: link, Title, Pull-requests" in errors[0]

0 commit comments

Comments
 (0)