Skip to content

Commit

Permalink
Add detection of change level
Browse files Browse the repository at this point in the history
  • Loading branch information
relekang committed Jul 27, 2015
1 parent 4b80fab commit 06c5ac4
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 13 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -4,3 +4,4 @@ coverage
click==4.1
semver==2.2.0
invoke==0.10.1
pygit2==0.22.1
6 changes: 3 additions & 3 deletions semantic_release/cli.py
@@ -1,7 +1,7 @@
import click

from semantic_release.helpers import (evaluate_version_bump, get_current_version, get_new_version,
set_new_version)
from semantic_release.helpers import get_current_version, get_new_version, set_new_version
from semantic_release.history import evaluate_version_bump


@click.command()
Expand All @@ -17,7 +17,7 @@ def version(**kwargs):
click.echo('Creating new version..')
current_version = get_current_version()
click.echo('Current version: {0}'.format(current_version))
level_bump = evaluate_version_bump(kwargs['force_level'])
level_bump = evaluate_version_bump(current_version, kwargs['force_level'])
new_version = get_new_version(current_version, level_bump)
set_new_version(new_version)
click.echo('Bumping with a {0} version to {1}.'.format(level_bump, new_version))
Expand Down
25 changes: 18 additions & 7 deletions semantic_release/helpers.py
@@ -1,20 +1,22 @@
import configparser
import os
import re

import semver
from invoke import run
from pygit2 import Repository

DEFAULTS = {
'major_tag': ':boom:',
'minor_tag': ':sparkles:',
'patch_tag': ':bug:',
}


def get_current_version():
return run('python setup.py --version', hide=True).stdout.strip()


def evaluate_version_bump(force=None):
if force:
return force
return 'patch'


def get_new_version(current_version, level_bump):
return getattr(semver, 'bump_{0}'.format(level_bump))(current_version)

Expand All @@ -40,4 +42,13 @@ def load_config():
config = configparser.ConfigParser()
with open(os.path.join(os.getcwd(), 'setup.cfg')) as f:
config.read_file(f)
return config._sections['semantic_release']
settings = {}
settings.update(DEFAULTS)
settings.update(config._sections['semantic_release'])
return settings


def get_commit_log():
repo = Repository('.git')
for commit in repo.walk(repo.head.target):
yield commit.message
29 changes: 29 additions & 0 deletions semantic_release/history.py
@@ -0,0 +1,29 @@
from semantic_release.helpers import get_commit_log, load_config

LEVELS = {
1: 'patch',
2: 'minor',
3: 'major',
}


def evaluate_version_bump(current_version, force=None):
if force:
return force
bump = 'patch'

changes = []

for commit_message in get_commit_log():
if current_version in commit_message:
break
if load_config()['major_tag'] in commit_message:
changes.append(3)
elif load_config()['minor_tag'] in commit_message:
changes.append(2)
elif load_config()['patch_tag'] in commit_message:
changes.append(1)

if len(changes):
bump = LEVELS[max(changes)]
return bump
3 changes: 3 additions & 0 deletions setup.py
Expand Up @@ -29,6 +29,9 @@ def _read_long_description():
license='MIT',
install_requires=[
'click==4.1',
'semver==2.2.0',
'invoke==0.10.1',
'pygit2==0.22.1',
],
entry_points='''
[console_scripts]
Expand Down
8 changes: 5 additions & 3 deletions tests/test_cli.py
Expand Up @@ -16,16 +16,18 @@ def test_main_should_call_correct_function(self, mock_version):
self.assertEqual(result.exit_code, 0)
mock_version.assert_called_once()

@mock.patch('semantic_release.cli.get_new_version')
@mock.patch('semantic_release.cli.set_new_version')
@mock.patch('semantic_release.cli.get_new_version', return_value='2.0.0')
@mock.patch('semantic_release.cli.evaluate_version_bump', return_value='major')
@mock.patch('semantic_release.cli.get_current_version', return_value='1.2.3')
def test_version_should_call_correct_functions(self, mock_current_version, mock_evaluate_bump,
mock_new_version):
mock_new_version, mock_set_new_version):
result = self.runner.invoke(main, ['version'])
self.assertEqual(result.exit_code, 0)
mock_current_version.assert_called_once_with()
mock_evaluate_bump.assert_called_once_with(None)
mock_evaluate_bump.assert_called_once_with('1.2.3', None)
mock_new_version.assert_called_once_with('1.2.3', 'major')
mock_set_new_version.assert_called_once_with('2.0.0')

@mock.patch('semantic_release.cli.version')
def test_force_major(self, mock_version):
Expand Down
35 changes: 35 additions & 0 deletions tests/test_history.py
@@ -0,0 +1,35 @@
from unittest import TestCase, mock

from semantic_release.history import evaluate_version_bump

MAJOR = ':boom: Breaking changes'
MINOR = ':sparkles: Add awesome feature'
PATCH = ':bug: Fix the annoying bug'

ALL_KINDS_OF_COMMIT_MESSAGES = [MINOR, MAJOR, MINOR, PATCH]
MINOR_AND_PATCH_COMMIT_MESSAGES = [MINOR, PATCH]
PATCH_COMMIT_MESSAGES = [PATCH, PATCH]


class EvaluateVersionBumpTest(TestCase):
def test_major(self):
with mock.patch('semantic_release.history.get_commit_log',
lambda: ALL_KINDS_OF_COMMIT_MESSAGES):
self.assertEqual(evaluate_version_bump('0.0.0'), 'major')

def test_minor(self):
with mock.patch('semantic_release.history.get_commit_log',
lambda: MINOR_AND_PATCH_COMMIT_MESSAGES):
self.assertEqual(evaluate_version_bump('0.0.0'), 'minor')

def test_patch(self):
with mock.patch('semantic_release.history.get_commit_log', lambda: PATCH_COMMIT_MESSAGES):
self.assertEqual(evaluate_version_bump('0.0.0'), 'patch')

with mock.patch('semantic_release.history.get_commit_log', lambda: ['', '...']):
self.assertEqual(evaluate_version_bump('0.0.0'), 'patch')

def test_force(self):
self.assertEqual(evaluate_version_bump('0.0.0', 'major'), 'major')
self.assertEqual(evaluate_version_bump('0.0.0', 'minor'), 'minor')
self.assertEqual(evaluate_version_bump('0.0.0', 'patch'), 'patch')

0 comments on commit 06c5ac4

Please sign in to comment.