Repository: Colin-b/keepachangelog

Issue:
Allow to retrieve unreleased information
As an option deactivated by default

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 205430e..2249674 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Added
+- It is now possible to retrieve "Unreleased" information thanks to the `show_unreleased` parameter.
+
 ## [0.1.0] - 2020-02-17
 ### Added
 - `keepachangelog.starlette.add_changelog_endpoint` function to add a changelog endpoint to a [Starlette](https://www.starlette.io) application.
diff --git a/README.md b/README.md
index a74cab6..ba23a57 100644
--- a/README.md
+++ b/README.md
@@ -112,6 +112,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 [1.0.0]: https://github.test_url/test_project/releases/tag/v1.0.0
 ```
 
+`show_unreleased` parameter can be specified in order to include `Unreleased` section information.
+Note that `release_date` will be set to None in such as case.
+
 ## Endpoint
 
 ### Starlette
diff --git a/keepachangelog/_changelog.py b/keepachangelog/_changelog.py
index ae8adce..1c3bce4 100644
--- a/keepachangelog/_changelog.py
+++ b/keepachangelog/_changelog.py
@@ -2,11 +2,14 @@ import re
 from typing import Dict, List
 
 # Release pattern should match lines like: "## [0.0.1] - 2020-12-31"
-release_pattern = re.compile(r"^## \[(.*)\] - (.*)$")
+release_pattern = re.compile(r"^## \[(.*)\](?: - (.*))?$")
 
 
-def is_release(line: str) -> bool:
-    return release_pattern.fullmatch(line) is not None
+def is_release(line: str, show_unreleased: bool) -> bool:
+    match = release_pattern.fullmatch(line)
+    if match and (not show_unreleased and match.group(1) == 'Unreleased'):
+        return False
+    return match is not None
 
 
 def add_release(changes: Dict[str, dict], line: str) -> dict:
@@ -47,7 +50,7 @@ def add_information(category: List[str], line: str):
     category.append(line)
 
 
-def to_dict(changelog_path: str) -> Dict[str, dict]:
+def to_dict(changelog_path: str, *, show_unreleased: bool = False) -> Dict[str, dict]:
     changes = {}
     with open(changelog_path) as change_log:
         release = {}
@@ -55,7 +58,7 @@ def to_dict(changelog_path: str) -> Dict[str, dict]:
         for line in change_log:
             line = line.strip(" \n")
 
-            if is_release(line):
+            if is_release(line, show_unreleased):
                 release = add_release(changes, line)
             elif is_category(line):
                 category = add_category(release, line)


Test patch:
diff --git a/tests/test_changelog_unreleased.py b/tests/test_changelog_unreleased.py
new file mode 100644
index 0000000..61104ae
--- /dev/null
+++ b/tests/test_changelog_unreleased.py
@@ -0,0 +1,119 @@
+import os
+import os.path
+
+import pytest
+
+import keepachangelog
+
+
+@pytest.fixture
+def changelog(tmpdir):
+    changelog_file_path = os.path.join(tmpdir, "CHANGELOG.md")
+    with open(changelog_file_path, "wt") as file:
+        file.write(
+            """# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+### Changed
+- Release note 1.
+- Release note 2.
+
+### Added
+- Enhancement 1
+- sub enhancement 1
+- sub enhancement 2
+- Enhancement 2
+
+### Fixed
+- Bug fix 1
+- sub bug 1
+- sub bug 2
+- Bug fix 2
+
+### Security
+- Known issue 1
+- Known issue 2
+
+### Deprecated
+- Deprecated feature 1
+- Future removal 2
+
+### Removed
+- Deprecated feature 2
+- Future removal 1
+
+## [1.1.0] - 2018-05-31
+### Changed
+- Enhancement 1 (1.1.0)
+- sub enhancement 1
+- sub enhancement 2
+- Enhancement 2 (1.1.0)
+
+## [1.0.1] - 2018-05-31
+### Fixed
+- Bug fix 1 (1.0.1)
+- sub bug 1
+- sub bug 2
+- Bug fix 2 (1.0.1)
+
+## [1.0.0] - 2017-04-10
+### Deprecated
+- Known issue 1 (1.0.0)
+- Known issue 2 (1.0.0)
+
+[Unreleased]: https://github.test_url/test_project/compare/v1.1.0...HEAD
+[1.1.0]: https://github.test_url/test_project/compare/v1.0.1...v1.1.0
+[1.0.1]: https://github.test_url/test_project/compare/v1.0.0...v1.0.1
+[1.0.0]: https://github.test_url/test_project/releases/tag/v1.0.0
+"""
+        )
+    return changelog_file_path
+
+
+def test_changelog_with_versions_and_all_categories(changelog):
+    assert keepachangelog.to_dict(changelog, show_unreleased=True) == {
+        'Unreleased': {
+            'version': 'Unreleased',
+            'release_date': None,
+            'changed': ['- Release note 1.', '- Release note 2.'],
+            'added': [
+                '- Enhancement 1',
+                '- sub enhancement 1',
+                '- sub enhancement 2',
+                '- Enhancement 2',
+            ],
+            'fixed': ['- Bug fix 1', '- sub bug 1', '- sub bug 2', '- Bug fix 2'],
+            'security': ['- Known issue 1', '- Known issue 2'],
+            'deprecated': ['- Deprecated feature 1', '- Future removal 2'],
+            'removed': ['- Deprecated feature 2', '- Future removal 1'],
+        },
+        '1.1.0': {
+            'version': '1.1.0',
+            'release_date': '2018-05-31',
+            'changed': [
+                '- Enhancement 1 (1.1.0)',
+                '- sub enhancement 1',
+                '- sub enhancement 2',
+                '- Enhancement 2 (1.1.0)',
+            ],
+        },
+        '1.0.1': {
+            'version': '1.0.1',
+            'release_date': '2018-05-31',
+            'fixed': [
+                '- Bug fix 1 (1.0.1)',
+                '- sub bug 1',
+                '- sub bug 2',
+                '- Bug fix 2 (1.0.1)',
+            ],
+        },
+        '1.0.0': {
+            'version': '1.0.0',
+            'release_date': '2017-04-10',
+            'deprecated': ['- Known issue 1 (1.0.0)', '- Known issue 2 (1.0.0)'],
+        },
+    }