Skip to content

Commit

Permalink
feat(history): Add generate_changelog function
Browse files Browse the repository at this point in the history
It generates a dict with changelog information to each of the given
section types.
  • Loading branch information
relekang committed Aug 18, 2015
1 parent 974ccda commit 347f21a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
35 changes: 35 additions & 0 deletions semantic_release/history/logs.py
@@ -1,3 +1,4 @@
import re
from ..errors import UnknownCommitMessageStyle
from ..settings import current_commit_parser
from ..settings import config
Expand All @@ -9,6 +10,10 @@
3: 'major',
}

CHANGELOG_SECTIONS = ['feature', 'fix', 'breaking', 'documentation']

re_breaking = re.compile('BREAKING CHANGE: (.*)')


def evaluate_version_bump(current_version, force=None):
"""
Expand Down Expand Up @@ -46,3 +51,33 @@ def evaluate_version_bump(current_version, force=None):
if config.getboolean('semantic_release', 'patch_without_tag') and commit_count:
bump = 'patch'
return bump


def generate_changelog(version):
"""
Generates a changelog for the given version.
:param version: a version string
:return: a dict with different changelog sections
"""

changes = {'feature': [], 'fix': [], 'documentation': [], 'refactor': [], 'breaking': []}

for commit_message in get_commit_log():
if version in commit_message:
break

try:
message = current_commit_parser()(commit_message)
changes[message[1]].append(message[3][0])

if message[3][1] and 'BREAKING CHANGE' in message[3][1]:
changes['breaking'].append(re_breaking.match(message[3][1]).group(1))

if message[3][2] and 'BREAKING CHANGE' in message[3][2]:
changes['breaking'].append(re_breaking.match(message[3][2]).group(1))

except UnknownCommitMessageStyle:
pass

return changes
28 changes: 28 additions & 0 deletions tests/test_history.py
Expand Up @@ -4,12 +4,17 @@
from semantic_release.history import evaluate_version_bump, get_current_version, get_new_version

from . import mock
from semantic_release.history.logs import generate_changelog

MAJOR = 'feat(x): Add super-feature\n\nBREAKING CHANGE: Uses super-feature as default instead of ' \
'dull-feature.'
MAJOR2 = 'feat(x): Add super-feature\n\nSome explanation\n\n' \
'BREAKING CHANGE: Uses super-feature as default instead of ' \
'dull-feature.'
MINOR = 'feat(x): Add non-breaking super-feature'
PATCH = 'fix(x): Fix bug in super-feature'
NO_TAG = 'docs(x): Add documentation for super-feature'
UNKNOWN_STYLE = 'random commits are the worst'

ALL_KINDS_OF_COMMIT_MESSAGES = [MINOR, MAJOR, MINOR, PATCH]
MINOR_AND_PATCH_COMMIT_MESSAGES = [MINOR, PATCH]
Expand Down Expand Up @@ -67,6 +72,29 @@ def test_should_return_none_without_commits(self):
with mock.patch('semantic_release.history.config.getboolean', lambda *x: False):
self.assertIsNone(evaluate_version_bump('1.1.0'))

class GenerateChangelogTests(TestCase):

def test_should_generate_all_sections(self):
with mock.patch('semantic_release.history.logs.get_commit_log',
lambda: ALL_KINDS_OF_COMMIT_MESSAGES + [MAJOR2, UNKNOWN_STYLE]):
changelog = generate_changelog('0.0.0')
self.assertIn('feature', changelog)
self.assertIn('fix', changelog)
self.assertIn('documentation', changelog)
self.assertIn('breaking', changelog)
self.assertGreater(len(changelog['feature']), 0)
self.assertGreater(len(changelog['fix']), 0)
self.assertGreater(len(changelog['breaking']), 0)

def test_should_only_read_until_given_version(self):
with mock.patch('semantic_release.history.logs.get_commit_log',
lambda: MAJOR_LAST_RELEASE_MINOR_AFTER):
changelog = generate_changelog('1.1.0')
self.assertGreater(len(changelog['feature']), 0)
self.assertEqual(len(changelog['fix']), 0)
self.assertEqual(len(changelog['documentation']), 0)
self.assertEqual(len(changelog['breaking']), 0)


class GetCurrentVersionTests(TestCase):
def test_should_return_correct_version(self):
Expand Down

0 comments on commit 347f21a

Please sign in to comment.