Repository: relekang/python-semantic-release (python)

Issue:
Optional auto capitalization on changelog
## Description

The automatic changelog seems to automatically capitalize the first letter, like this:

`feat: add amazing feature`

> ### Feature
> * Add amazing feature (`abc1234`)

That can be useful, but it can also be misleading, for example:

`fix: do_stuff now does stuff`

> ### Fix
> * Do_stuff now does stuff (`xyz9876`)

I've had it happen a couple of times, where the first word of a commit message happens to be a case-sensitive name, and the changelog changes its capitalization.

## Use cases

It'd be useful in order to avoid case-sensitive names having their capitalization changed automatically.

> ### Feature
> * add amazing feature (`abc1234`)
> ### Fix
> * do_stuff now does stuff (`xyz9876`)

## Possible implementation

Having the auto capitalization enabled by default is okay I think, so I was thinking it could be an option in [the changelog section in the configuration](https://python-semantic-release.readthedocs.io/en/latest/configuration.html#changelog), something like `changelog_capitalize`, that could be set to false to disable the automatic capitalization.


Pull request description:
feat: add changelog_capitalize configuration
Fixes #260


Patch:
diff --git a/docs/configuration.rst b/docs/configuration.rst
index dbb4d52..cbb2d9e 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -297,6 +297,12 @@ will be updated.
 
 Default: ``<!--next-version-placeholder-->``.
 
+``changelog_capitalize``
+-------------------------
+If set to false commit messages will not be automatically capitalized when generating the changelog.
+
+Default: ``True``.
+
 Distributions
 =============
 
diff --git a/semantic_release/history/logs.py b/semantic_release/history/logs.py
index d2fca9f..769c155 100644
--- a/semantic_release/history/logs.py
+++ b/semantic_release/history/logs.py
@@ -115,12 +115,15 @@ def generate_changelog(from_version: str, to_version: str = None) -> dict:
                 logger.debug(f"Creating new changelog section for {message.type} ")
                 changes[message.type] = list()
 
-            # Capialize the first letter of the message, leaving others as they were
+            # Capitalize the first letter of the message, leaving others as they were
             # (using str.capitalize() would make the other letters lowercase)
-            capital_message = (
+            formatted_message = (
                 message.descriptions[0][0].upper() + message.descriptions[0][1:]
             )
-            changes[message.type].append((_hash, capital_message))
+            if config.get('changelog_capitalize') is False:
+                formatted_message = message.descriptions[0]
+
+            changes[message.type].append((_hash, formatted_message))
 
             if message.breaking_descriptions:
                 # Copy breaking change descriptions into changelog


Test patch:
diff --git a/tests/history/test_changelog.py b/tests/history/test_changelog.py
index ef082c5..12d9177 100644
--- a/tests/history/test_changelog.py
+++ b/tests/history/test_changelog.py
@@ -4,6 +4,7 @@ import pytest
 from semantic_release.history.logs import generate_changelog
 
 from . import *
+from .. import wrapped_config_get
 
 
 def test_should_generate_necessary_sections():
@@ -74,10 +75,20 @@ def test_should_get_multiple_breaking_descriptions():
         assert changelog["breaking"][1][1] == "Breaking change 2"
 
 
-def test_messages_are_capitalized():
+@mock.patch(
+    "semantic_release.history.logs.get_commit_log",
+    lambda *a, **k: [("23", "fix(x): abCD")],
+)
+@pytest.mark.parametrize(
+    "config_setting,expected_description",
+    [
+        (True, "AbCD"),
+        (False, "abCD"),
+    ],
+)
+def test_message_capitalization_is_configurable(config_setting, expected_description):
     with mock.patch(
-        "semantic_release.history.logs.get_commit_log",
-        lambda *a, **k: [("23", "fix(x): abCD")],
+        "semantic_release.history.config.get", wrapped_config_get(changelog_capitalize=config_setting)
     ):
         changelog = generate_changelog("0.0.0")
-        assert changelog["fix"][0][1] == "AbCD"
+        assert changelog["fix"][0][1] == expected_description