Skip to content

Commit

Permalink
Merge pull request #162 from zestsoftware/maurits-bumpversion
Browse files Browse the repository at this point in the history
Added bump version command
  • Loading branch information
mauritsvanrees committed Jan 29, 2016
2 parents 00d56e5 + beef14b commit 8c7489a
Show file tree
Hide file tree
Showing 14 changed files with 430 additions and 33 deletions.
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Changelog for zest.releaser
6.6 (unreleased)
----------------

- Added ``bumpversion`` command. Options ``--feature`` and
``--breaking``. Issue #160. The exact behavior might change in
future versions after more practical experience. Try it out and
report any issues you find. [maurits]

- Fixed possible encoding problems when writing files. This is
especially for an ascii file to which we add non ascii characters,
like in the ``addchangelogentry`` command. [maurits]
Expand Down
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,8 @@ There are some additional tools:
is indented and the first line is started with a dash. The command
detects it if you use for example a star as first character of an
entry.

- **bumpversion**: do not release, only bump the version. A
development marker is kept when it is there. With ``--feature`` we
update the minor version. With option ``--breaking`` we update the
major version.
48 changes: 48 additions & 0 deletions doc/source/entrypoints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,51 @@ reporoot

workingdir
Original working directory

Bumpversion data dict items
---------------------------

breaking
True if we handle a breaking (major) change

commit_msg
Message template used when committing.

feature
True if we handle a feature (minor) change

headings
Extracted headings from the history file

history_encoding
The detected encoding of the history file

history_file
Filename of history/changelog file (when found)

history_header
Header template used for 1st history header

history_insert_line_here
Line number where an extra changelog entry can be inserted.

history_last_release
Full text of all history entries of the current release

history_lines
List with all history file lines (when found)

name
Name of the project being released

new_version
New development version (so 1.1)

release
Type of release: breaking, feature, normal

reporoot
Root of the version control repository

workingdir
Original working directory
6 changes: 6 additions & 0 deletions doc/source/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Or on multiple lines::

This was difficult."

The ``bumpversion`` command accepts two mutually exclusive options:

- With ``--feature`` we update the minor version.

- With option ``--breaking`` we update the major version.


Global options
--------------
Expand Down
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def read(filename):
'lasttagdiff = zest.releaser.lasttagdiff:main',
'lasttaglog = zest.releaser.lasttaglog:main',
'addchangelogentry = zest.releaser.addchangelogentry:main',
'bumpversion = zest.releaser.bumpversion:main',
],
# The datachecks are implemented as entry points to be able to check
# our entry point implementation.
Expand All @@ -97,6 +98,9 @@ def read(filename):
'zest.releaser.addchangelogentry.middle': [
'datacheck = zest.releaser.addchangelogentry:datacheck',
],
'zest.releaser.bumpversion.middle': [
'datacheck = zest.releaser.bumpversion:datacheck',
],
# Documentation generation
'zest.releaser.prereleaser.before': [
'preparedocs = ' +
Expand Down
8 changes: 8 additions & 0 deletions zest/releaser/baserelease.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ def _check_required(self):
default=False):
sys.exit(1)

def _write_version(self):
if self.data['new_version'] != self.data['original_version']:
# self.vcs.version writes it to the file it got the version from.
self.vcs.version = self.data['new_version']
logger.info("Changed version from %s to %s",
self.data['original_version'],
self.data['new_version'])

def _write_history(self):
"""Write previously-calculated history lines back to the file"""
if self.data['history_file'] is None:
Expand Down
152 changes: 152 additions & 0 deletions zest/releaser/bumpversion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"""Do the checks and tasks that have to happen after doing a release.
"""
from __future__ import unicode_literals

import logging
import sys

from zest.releaser import baserelease
from zest.releaser import utils

logger = logging.getLogger(__name__)

HISTORY_HEADER = '%(new_version)s (unreleased)'
COMMIT_MSG = 'Bumped version for %(release)s release.'

DATA = {
# Documentation for self.data. You get runtime warnings when something is
# in self.data that is not in this list. Embarrasment-driven
# documentation!
'workingdir': 'Original working directory',
'reporoot': 'Root of the version control repository',
'name': 'Name of the project being released',
'new_version': 'New development version (so 1.1)',
'commit_msg': 'Message template used when committing.',
'headings': 'Extracted headings from the history file',
'history_file': 'Filename of history/changelog file (when found)',
'history_last_release': (
'Full text of all history entries of the current release'),
'history_header': 'Header template used for 1st history header',
'history_lines': 'List with all history file lines (when found)',
'history_encoding': 'The detected encoding of the history file',
'history_insert_line_here': (
'Line number where an extra changelog entry can be inserted.'),
'original_version': 'Version before bump (e.g. 1.0.dev0)',
'breaking': 'True if we handle a breaking (major) change',
'feature': 'True if we handle a feature (minor) change',
'release': 'Type of release: breaking, feature, normal',
}


class BumpVersion(baserelease.Basereleaser):
"""Add a changelog entry.
self.data holds data that can optionally be changed by plugins.
"""

def __init__(self, vcs=None, breaking=False, feature=False):
baserelease.Basereleaser.__init__(self, vcs=vcs)
# Prepare some defaults for potential overriding.
if breaking:
release = 'breaking'
elif feature:
release = 'feature'
else:
release = 'normal'
self.data.update(dict(
history_header=HISTORY_HEADER,
breaking=breaking,
feature=feature,
release=release,
commit_msg=COMMIT_MSG))

def prepare(self):
"""Prepare self.data by asking about new dev version"""
print('Checking version bump for {} release.'.format(
self.data['release']))
if not utils.sanity_check(self.vcs):
logger.critical("Sanity check failed.")
sys.exit(1)
self._grab_version(initial=True)
self._grab_history()
# Grab and set new version.
self._grab_version()

def execute(self):
"""Make the changes and offer a commit"""
self._change_header()
self._write_version()
self._write_history()
self._diff_and_commit()

def _grab_version(self, initial=False):
"""Grab the version.
When initial is False, ask the user for a non-development
version. When initial is True, grab the current suggestion.
"""
original_version = self.vcs.version
logger.debug("Extracted version: %s", original_version)
if original_version is None:
logger.critical('No version found.')
sys.exit(1)
suggestion = new_version = self.data.get('new_version')
if not new_version:
# Get a suggestion.
breaking = self.data['breaking']
feature = self.data['feature']
# Compare the suggestion for the last tag with the current version.
# The wanted version bump may already have been done.
last_tag_version = utils.get_last_tag(self.vcs, allow_missing=True)
if last_tag_version is None:
print("No tag found. No version bump needed.")
sys.exit(0)
else:
print("Last tag: {}".format(last_tag_version))
print("Current version: {}".format(original_version))
minimum_version = utils.suggest_version(
last_tag_version, feature=feature, breaking=breaking)
if minimum_version <= original_version:
print("No version bump needed.")
sys.exit(0)
# A bump is needed. Get suggestion for next version.
suggestion = utils.suggest_version(
original_version, feature=feature, breaking=breaking)
if not initial:
new_version = utils.ask_version(
"Enter version", default=suggestion)
if not new_version:
new_version = suggestion
self.data['original_version'] = original_version
self.data['new_version'] = new_version


def datacheck(data):
"""Entrypoint: ensure that the data dict is fully documented"""
utils.is_data_documented(data, documentation=DATA)


def main():
parser = utils.base_option_parser()
parser.add_argument(
"--feature",
action="store_true",
dest="feature",
default=False,
help="Bump for feature release (increase minor version)")
parser.add_argument(
"--breaking",
action="store_true",
dest="breaking",
default=False,
help="Bump for breaking release (increase major version)")
options = utils.parse_options(parser)
if options.breaking and options.feature:
print('Cannot have both breaking and feature options.')
sys.exit(1)
utils.configure_logging()
bumpversion = BumpVersion(
breaking=options.breaking, feature=options.feature)
bumpversion.run()
19 changes: 1 addition & 18 deletions zest/releaser/postrelease.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,7 @@ def _ask_for_new_dev_version(self):
current = self.vcs.version
# Clean it up to a non-development version.
current = utils.cleanup_version(current)
# Try to make sure that the suggestion for next version after
# 1.1.19 is not 1.1.110, but 1.1.20.
current_split = current.split('.')
major = '.'.join(current_split[:-1])
minor = current_split[-1]
try:
minor = int(minor) + 1
suggestion = '.'.join([major, str(minor)])
except ValueError:
# Fall back on simply updating the last character when it is
# an integer.
try:
last = int(current[-1]) + 1
suggestion = current[:-1] + str(last)
except ValueError:
logger.warn("Version does not end with a number, so we can't "
"calculate a suggestion for a next version.")
suggestion = None
suggestion = utils.suggest_version(current)
print("Current version is %s" % current)
q = "Enter new development version ('.dev0' will be appended)"
version = utils.ask_version(q, default=suggestion)
Expand Down
2 changes: 2 additions & 0 deletions zest/releaser/preparedocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os

from zest.releaser import addchangelogentry
from zest.releaser import bumpversion
from zest.releaser import prerelease
from zest.releaser import release
from zest.releaser import postrelease
Expand Down Expand Up @@ -34,6 +35,7 @@ def prepare_entrypoint_documentation(data):
('release', release.DATA),
('postrelease', postrelease.DATA),
('addchangelogentry', addchangelogentry.DATA),
('bumpversion', bumpversion.DATA),
):
heading = '%s data dict items' % name.capitalize()
result.append(heading)
Expand Down
10 changes: 1 addition & 9 deletions zest/releaser/prerelease.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
'Text that must be present in the changelog. Can be a string or a '
'list, for example ["New:", "Fixes:"]. For a list, only one of them '
'needs to be present.'),
'original_version': 'Version before prereleasing (e.g. 1.0dev)',
'original_version': 'Version before prereleasing (e.g. 1.0.dev0)',
'commit_msg': 'Message template used when committing',
'history_header': 'Header template used for 1st history header',
}
Expand Down Expand Up @@ -115,14 +115,6 @@ def _grab_version(self, initial=False):
self.data['original_version'] = original_version
self.data['new_version'] = new_version

def _write_version(self):
if self.data['new_version'] != self.data['original_version']:
# self.vcs.version writes it to the file it got the version from.
self.vcs.version = self.data['new_version']
logger.info("Changed version from %s to %s",
self.data['original_version'],
self.data['new_version'])


def datacheck(data):
"""Entrypoint: ensure that the data dict is fully documented"""
Expand Down
6 changes: 3 additions & 3 deletions zest/releaser/tests/addchangelogentry.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Detailed tests of prerelease.py
===============================
Detailed tests of addchangelogentry.py
======================================

.. :doctest:
.. :setup: zest.releaser.tests.functional.setup
Expand Down Expand Up @@ -45,7 +45,7 @@ commit::
Question: OK to commit this (Y/n)?
Our reply: <ENTER>

The changelog and setup.py are at 0.1 and indicate a release date:
The changelog and setup.py are at 0.1 and have the message::

>>> contents = (open('CHANGES.txt').read())
>>> print(contents)
Expand Down
Loading

0 comments on commit 8c7489a

Please sign in to comment.