diff --git a/get_releasenote.py b/get_releasenote.py index 3cfd8c5..4eb93cf 100755 --- a/get_releasenote.py +++ b/get_releasenote.py @@ -85,6 +85,7 @@ def parse_changes( return _parse_changes( changes=changes, + changes_file=changes_file, version=ctx.version, start_line=start_line, head_line=head_line, @@ -96,6 +97,7 @@ def parse_changes( def _parse_changes( *, changes: str, + changes_file: str, version: str, start_line: str, head_line: str, @@ -105,7 +107,10 @@ def _parse_changes( ) -> str: top, sep, msg = changes.partition(start_line) if not sep: - raise ValueError(f"Cannot find TOWNCRIER start mark ({start_line!r})") + raise ValueError( + f"Cannot find TOWNCRIER start mark ({start_line!r}) " + "in file '{changes_file}'" + ) msg = msg.strip() head_re = re.compile( @@ -119,11 +124,11 @@ def _parse_changes( match = head_re.match(msg) if match is None: raise ValueError( - f"Cannot find TOWNCRIER version head mark ({head_re.pattern!r})" + f"Cannot find TOWNCRIER version head mark ({head_re.pattern!r}) " + f"in file '{changes_file}'" ) found_version = match.group("version") - if version != found_version: - raise ValueError(f"Version check mismatch: {version} != {found_version}") + check_changes_version(version, found_version, changes_file) match2 = head_re.search(msg, match.end()) if match2 is not None: @@ -138,6 +143,29 @@ def _parse_changes( return msg.strip() +def check_changes_version( + declared_version: str, found_version: str, changes_file: str +) -> None: + if declared_version == found_version: + return + dver = parse_version(declared_version) + fver = parse_version(found_version) + + if dver < fver: + raise ValueError( + f"The distribution version {dver} is older than " + f"{fver} (from '{changes_file}').\n" + "Hint: push git tag with the latest version." + ) + + else: + raise ValueError( + f"The distribution version {dver} is younger than " + f"{fver} (from '{changes_file}').\n" + "Hint: run 'towncrier' again." + ) + + VERSION_RE = re.compile( "^{version} *= *{spec}".format( version="(?:__version__|version)", diff --git a/tests/test_parse_changes.py b/tests/test_parse_changes.py new file mode 100644 index 0000000..1f18e83 --- /dev/null +++ b/tests/test_parse_changes.py @@ -0,0 +1,247 @@ +from textwrap import dedent + +import pytest + +from get_releasenote import _parse_changes + +START_LINE = ".. towncrier release notes start" + + +def test_parse_no_start_line() -> None: + with pytest.raises(ValueError, match="Cannot find TOWNCRIER start mark"): + _parse_changes( + changes="text", + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + + +def test_parse_no_head_line() -> None: + CHANGES = dedent( + f"""\ + {START_LINE} + NO-VERSION + """ + ) + with pytest.raises(ValueError, match="Cannot find TOWNCRIER version head mark"): + _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + + +def test_parse_version_older() -> None: + CHANGES = dedent( + f"""\ + {START_LINE} + + 1.2.4 (2020-12-16) + ================== + + """ + ) + with pytest.raises( + ValueError, match="The distribution version 1.2.3 is older than 1.2.4" + ): + _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + + +def test_parse_version_younger() -> None: + CHANGES = dedent( + f"""\ + {START_LINE} + + 1.2.4 (2020-12-16) + ================== + + """ + ) + with pytest.raises( + ValueError, match="The distribution version 1.2.5 is younger than 1.2.4" + ): + _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.5", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + + +def test_parse_single_changes() -> None: + CHANGES = dedent( + f"""\ + Header + {START_LINE} + + 1.2.3 (2020-12-16) + ================== + + Features + -------- + + - Feature 1 (#1024) + + - Feature 2 (#1025) + + """ + ) + ret = _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + assert ret == dedent( + """\ + Features + -------- + + - Feature 1 (#1024) + + - Feature 2 (#1025)""" + ) + + +def test_parse_multi_changes() -> None: + CHANGES = dedent( + f"""\ + Header + {START_LINE} + + 1.2.3 (2020-12-16) + ================== + + Features + -------- + + - Feature 1 (#1024) + + - Feature 2 (#1025) + + + + 1.2.2 (2020-12-15) + ================== + + Bugfixes + -------- + """ + ) + ret = _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + assert ret == dedent( + """\ + Features + -------- + + - Feature 1 (#1024) + + - Feature 2 (#1025)""" + ) + + +def test_parse_fix_issues() -> None: + CHANGES = dedent( + f"""\ + Header + {START_LINE} + + 1.2.3 (2020-12-16) + ================== + + Features + -------- + + - Feature 1 `#4603 `_ + """ + ) + ret = _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="{version} \\({date}\\)\n=====+\n?", + fix_issue_regex=( + "\n?\\s*`#(\\d+) `_" + ), + fix_issue_repl=" (#\\1)", + name="name", + ) + assert ret == dedent( + """\ + Features + -------- + + - Feature 1 (#4603)""" + ) + + +def test_parse_with_name() -> None: + CHANGES = dedent( + f"""\ + Header + {START_LINE} + + Project 1.2.3 (2020-12-16) + ========================== + + Features + -------- + + - Feature 1 (#1024) + + """ + ) + ret = _parse_changes( + changes=CHANGES, + changes_file="CHANGES.rst", + version="1.2.3", + start_line=START_LINE, + head_line="Project {version} \\({date}\\)\n=====+\n?", + fix_issue_regex="", + fix_issue_repl="", + name="name", + ) + assert ret == dedent( + """\ + Features + -------- + + - Feature 1 (#1024)""" + ) diff --git a/tests/test_simple.py b/tests/test_simple.py index 08fff79..4422001 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -1,12 +1,10 @@ import pathlib -from textwrap import dedent import pytest from get_releasenote import ( Context, DistInfo, - _parse_changes, analyze_dists, check_fix_issue, find_version, @@ -18,9 +16,6 @@ def root() -> pathlib.Path: return pathlib.Path(__file__).parent -START_LINE = ".. towncrier release notes start" - - ################# @@ -109,212 +104,3 @@ def test_find_version_not_found(ctx: Context) -> None: (ctx.root / "file.py").write_text("not_a_version = '0.0.7'") with pytest.raises(ValueError, match="Unable to determine version"): find_version(ctx, "file.py", "") - - -################## - - -def test_parse_no_start_line() -> None: - with pytest.raises(ValueError, match="Cannot find TOWNCRIER start mark"): - _parse_changes( - changes="text", - version="1.2.3", - start_line=START_LINE, - head_line="{version} \\({date}\\)\n=====+\n?", - fix_issue_regex="", - fix_issue_repl="", - name="name", - ) - - -def test_parse_no_head_line() -> None: - CHANGES = dedent( - f"""\ - {START_LINE} - NO-VERSION - """ - ) - with pytest.raises(ValueError, match="Cannot find TOWNCRIER version head mark"): - _parse_changes( - changes=CHANGES, - version="1.2.3", - start_line=START_LINE, - head_line="{version} \\({date}\\)\n=====+\n?", - fix_issue_regex="", - fix_issue_repl="", - name="name", - ) - - -def test_parse_version_mismatch() -> None: - CHANGES = dedent( - f"""\ - {START_LINE} - - 1.2.4 (2020-12-16) - ================== - - """ - ) - with pytest.raises(ValueError, match="Version check mismatch"): - _parse_changes( - changes=CHANGES, - version="1.2.3", - start_line=START_LINE, - head_line="{version} \\({date}\\)\n=====+\n?", - fix_issue_regex="", - fix_issue_repl="", - name="name", - ) - - -def test_parse_single_changes() -> None: - CHANGES = dedent( - f"""\ - Header - {START_LINE} - - 1.2.3 (2020-12-16) - ================== - - Features - -------- - - - Feature 1 (#1024) - - - Feature 2 (#1025) - - """ - ) - ret = _parse_changes( - changes=CHANGES, - version="1.2.3", - start_line=START_LINE, - head_line="{version} \\({date}\\)\n=====+\n?", - fix_issue_regex="", - fix_issue_repl="", - name="name", - ) - assert ret == dedent( - """\ - Features - -------- - - - Feature 1 (#1024) - - - Feature 2 (#1025)""" - ) - - -def test_parse_multi_changes() -> None: - CHANGES = dedent( - f"""\ - Header - {START_LINE} - - 1.2.3 (2020-12-16) - ================== - - Features - -------- - - - Feature 1 (#1024) - - - Feature 2 (#1025) - - - - 1.2.2 (2020-12-15) - ================== - - Bugfixes - -------- - """ - ) - ret = _parse_changes( - changes=CHANGES, - version="1.2.3", - start_line=START_LINE, - head_line="{version} \\({date}\\)\n=====+\n?", - fix_issue_regex="", - fix_issue_repl="", - name="name", - ) - assert ret == dedent( - """\ - Features - -------- - - - Feature 1 (#1024) - - - Feature 2 (#1025)""" - ) - - -def test_parse_fix_issues() -> None: - CHANGES = dedent( - f"""\ - Header - {START_LINE} - - 1.2.3 (2020-12-16) - ================== - - Features - -------- - - - Feature 1 `#4603 `_ - """ - ) - ret = _parse_changes( - changes=CHANGES, - version="1.2.3", - start_line=START_LINE, - head_line="{version} \\({date}\\)\n=====+\n?", - fix_issue_regex=( - "\n?\\s*`#(\\d+) `_" - ), - fix_issue_repl=" (#\\1)", - name="name", - ) - assert ret == dedent( - """\ - Features - -------- - - - Feature 1 (#4603)""" - ) - - -def test_parse_with_name() -> None: - CHANGES = dedent( - f"""\ - Header - {START_LINE} - - Project 1.2.3 (2020-12-16) - ========================== - - Features - -------- - - - Feature 1 (#1024) - - """ - ) - ret = _parse_changes( - changes=CHANGES, - version="1.2.3", - start_line=START_LINE, - head_line="Project {version} \\({date}\\)\n=====+\n?", - fix_issue_regex="", - fix_issue_repl="", - name="name", - ) - assert ret == dedent( - """\ - Features - -------- - - - Feature 1 (#1024)""" - )