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

Issue:
Option to show changelog as a table
## Description

Add an option to display the changelog in table format, rather than using headings.

![image](https://user-images.githubusercontent.com/28959268/81698565-1944d700-945e-11ea-95e1-119a1a6a1d3f.png)

## Use cases

- Could look nice with [emojis](https://github.com/relekang/python-semantic-release/pull/238) as type of change
- The list is more compact, which is good for releasing many commits at once - e.g. on a weekly cron

## Possible implementation

- Insert a fixed header of:
  ```
  | Type | Change |
  |------|--------|
  ```
- Each section is of the format:
  ```
  | <heading text> | <commits> |
  ```
- Use `<br>` to get a new line between commits
- However, lists cannot be used in a table


Pull request description:
Add changelog_table component
Add an alternative changelog component (`semantic_release.changelog.changelog_table`) which displays each section as a row in a table, like this:

| Type | Change |
| --- | --- |
| Feature | Commit 1 (sha)<br>Commit 2 (sha) |
| Fix | Commit 3 (sha) |

Fixes #237.

Patch:
diff --git a/docs/configuration.rst b/docs/configuration.rst
index e17185d..a58f367 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -204,6 +204,11 @@ The following components are included in Python Semantic Release:
   List of commits between this version and the previous one, with sections and
   headings for each type of change present in the release.
 
+- :py:func:`semantic_release.changelog.changelog_table`
+
+  List of commits between this version and the previous one, dsplayed in a
+  table.
+
 - :py:func:`semantic_release.changelog.compare_url`
 
   Link to view a comparison between this release and the previous one on
diff --git a/semantic_release/changelog/__init__.py b/semantic_release/changelog/__init__.py
index c9063c2..5879be2 100644
--- a/semantic_release/changelog/__init__.py
+++ b/semantic_release/changelog/__init__.py
@@ -3,7 +3,7 @@ import logging
 from ..helpers import LoggedFunction
 from ..settings import config, current_changelog_components
 
-from .changelog import changelog_headers  # noqa isort:skip
+from .changelog import changelog_headers, changelog_table  # noqa isort:skip
 from .compare import compare_url  # noqa isort:skip
 
 logger = logging.getLogger(__name__)
diff --git a/semantic_release/changelog/changelog.py b/semantic_release/changelog/changelog.py
index 80ed54d..4daeb70 100644
--- a/semantic_release/changelog/changelog.py
+++ b/semantic_release/changelog/changelog.py
@@ -28,3 +28,17 @@ def changelog_headers(
             output += "* {0} ({1})\n".format(item[1], item[0])
 
     return output
+
+
+def changelog_table(
+    changelog: dict, changelog_sections: list, **kwargs
+) -> str:
+    output = "| Type | Change |\n| --- | --- |\n"
+
+    for section in get_changelog_sections(changelog, changelog_sections):
+        items = "<br>".join([
+            f"{item[0]} ({item[1]})" for item in changelog[section]
+        ])
+        output += f"| {section.title()} | {items} |\n"
+
+    return output


Test patch:
diff --git a/tests/test_changelog.py b/tests/test_changelog.py
index a36c803..e256519 100644
--- a/tests/test_changelog.py
+++ b/tests/test_changelog.py
@@ -1,7 +1,7 @@
 import mock
 
 from semantic_release.changelog import markdown_changelog
-from semantic_release.changelog.changelog import get_changelog_sections
+from semantic_release.changelog.changelog import get_changelog_sections, changelog_table
 from semantic_release.changelog.compare import compare_url, get_github_compare_url
 
 
@@ -38,6 +38,18 @@ def test_markdown_changelog():
     )
 
 
+def test_changelog_table():
+    assert changelog_table({
+        "feature": [("commit1", "sha1"), ("commit2", "sha2")],
+        "fix": [("commit3", "sha3")]
+    }, ["section1", "section2"]) == (
+        "| Type | Change |\n"
+        "| --- | --- |\n"
+        "| Feature | commit1 (sha1)<br>commit2 (sha2) |\n"
+        "| Fix | commit3 (sha3) |\n"
+    )
+
+
 def test_should_not_output_heading():
     assert "v1.0.1" not in markdown_changelog("1.0.1", {},)