peritus / bumpversion

Version-bump your software with a single command
https://pypi.python.org/pypi/bumpversion
MIT License
1.5k stars 148 forks source link

support prereleases #128

Open dmerejkowsky opened 8 years ago

dmerejkowsky commented 8 years ago

Here is the workflow I'm following for my project (assuming last release is 3.11) 'master' branch is for stable releases, 'next' is for development.

On 'next':

On 'master';

This version scheme is modeled after PEP440

Here's what I've tried:

[bumpversion]
current_version = 3.12a1
files = setup.py cmake/qibuild/version.cmake doc/source/conf.in.py python/qisys/main.py
message = qibuild {new_version}
commit = True
tag = True
parse = (?P<major>\d+)                             # major: 3.12 -> 3
        \.
        (?P<minor>\d+)                             # minor 3.12 -> 12
        (\.(?P<patch>\d+))?                        # either a maintenance release 3.12.1 ...
        ((?P<release>a|rc)(?P<rel_num>\d+))?       # or a rc, or an alpha 3.12a1, 3.12rc2
serialize =
  {major}.{minor}
  {major}.{minor}.{patch}
  {major}.{minor}{release}{rel_num}

[bumpversion:part:release]
values =
  a
  rc

But then I get:

$ bump_version rel_num
Parsing version '3.12a1' using regexp '(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+))?((?P<release>a|rc)(?P<rel_num>\d+))?'
Parsed the following values: major=3, minor=12, patch=0, rel_num=1, release=a
Attempting to increment part 'rel_num'
Values are now: major=3, minor=12
Did not find key u'patch' in <bumpversion.Version:major=3, minor=12> when serializing version number
Opportunistic finding of new_version failed: Did not find key u'patch' in <bumpversion.Version:major=3, minor=12> when serializing version number
...
bumpversion: error: argument --new-version is required

Digging in the source code, I suspect the problem is somewhere near:

class VersionConfig(object):

    # ....

    def order(self):
        # currently, order depends on the first given serialization format
        # this seems like a good idea because this should be the most complete format
        return self._labels_for_format(self.serialize_formats[0])

But maybe there's something I've missed in the documentation...

twall commented 8 years ago

I've found that this almost works (presumably you could add any number of "release" part values rather than "dev"):

[bumpversion]
current_version = 0.1.0
parse = (?P<major>\d+)
        \.(?P<minor>\d+)
        \.(?P<patch>\d+)
        ((?P<release>[a-z]+)(?P<num>\d+))?
serialize =
        {major}.{minor}.{patch}{release}{num}
        {major}.{minor}.{patch}

[bumpversion:part:release]
optional_value = placeholder
first_value = dev
values =
        dev
        placeholder

The only problem I have ATM is that if you specify "num" as the part to increment when it doesn't already exist, the resulting version is 0.1.001. Not difficult to work around, just ensure you specify "patch" instead of "num" as the first bump after a release.

dmerejkowsky commented 8 years ago

Yeah but in my use case there's no 'patch' component when I'm making a prerelease

constantinius commented 8 years ago

I'm having the same issue (also like to omit "patch" on a prerelease). Is there a workaround?

dacox commented 7 years ago

@twall So I'm doing what you're doing, and it fits my use case quite nicely. However, I am experiencing something weird and I'm not quite sure why.

I took your solution and I added

[bumpversion:part:num]
first_value = 1

so that the numbering would start at 1 instead of 0 (I'm going for 1.0.0rc1, 1.0.0rc2, 1.0.0)

When I do this, however, the text placeholder appears when I run bumpversion release. This only happens when I try to change the first_value for num.

webyneter commented 7 years ago

The weird thing is, given

[bumpversion]
current_version = 0.1.0
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<pre>\d+)\.(?P<prenum>\d+))?
serialize =
    {major}.{minor}.{patch}-{pre}.{prenum}
    {major}.{minor}.{patch}

(note the absence of explicit pre and prenum parts declaration, hence both are being implicitly set to default numeric part definitions under the hood), I can

0.1.0bumpversion pre0.1.0-1.0bumpversion prenum0.1.0-1.1bumpversion prenum0.1.0-1.2bumpversion major1.0.0.

However, whenever custom values are set in any of extra part definitions, -{pre}.{prenum} gets appended no matter what part is bumped.

TimOrme commented 7 years ago

@webyneter

I ran into this same issue. I was able to get it to work properly by specifying the first_value field to the optional one. I'm not 100% sure why this works, but it seems to:

[bumpversion]
commit = True
tag = True
current_version = 4.1.7
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<releaselevel>[a-z]+)\.(?P<preversion>\d+))?
serialize = 
    {major}.{minor}.{patch}-{releaselevel}.{preversion}
    {major}.{minor}.{patch}

[bumpversion:part:releaselevel]
first_value = final
optional_value = final
values = 
    alpha
    beta
    final

Edit*: I do agree that there should be a better way to do this though. The current way is a bit finicky.

dmarcelino commented 6 years ago

Hi! Does anyone know if bump2version or ADVbumpversion have made improvements in supporting pre-releases?

dmerejkowsky commented 6 years ago

In case this helps, we've built an alternative called tbump

Prelease support looks like this:

[version]
current = "1.6.0"

regex = '''
  (?P<major>\d+)
  \.
  (?P<minor>\d+)
  \.
  (?P<patch>\d+)
  (
    -
    (?P<lifecycle>alpha|beta|r)
    (?P<release>\d+)
  )?

And then you can use tbump 1.6.1. or tbump 1.6.0-r1

Cons: you have to type the whole version number on the command line instead of the 'part' you want to bump

Pros: the implementation is much simpler and supports many use cases.

adamgranthendry commented 3 years ago

@dacox FWIW, the bumpversion docs state that the default value for optional_value is actually The first entry in values =, not the last. I think bumpversion should be updated to handle traversing entries in any order, but I imagine this would get complicated if the user were to unexpectedly put placeholder in a spot not at the beginning or end of a values array of length greater than 2.

Instead, put placeholder at the beginning rather than the end and remove optional_value (or leave it in so you don't forget that that is what placeholder is).

As an example, the following .bumpversion.cfg works well for me:

[bumpversion]
current_version = 0.0.0
tag = False
tag_name = {new_version}
commit = True
parse =
    (?P<major>\d+)
    \.
    (?P<minor>\d+)
    \.
    (?P<patch>\d+)
    (\-(?P<pre>[a-z]+)\.(?P<prenum>\d+))?
serialize =
    {major}.{minor}.{patch}-{pre}.{prenum}
    {major}.{minor}.{patch}

[bumpversion:part:pre]
optional_value = placeholder
values =
    placeholder
    alpha
    beta
    rc

[bumpversion:part:prenum]
first_value = 1

[bumpversion:file:pyproject.toml]

In your case, see if this

[bumpversion]
current_version = 0.1.0
parse = (?P<major>\d+)
        \.(?P<minor>\d+)
        \.(?P<patch>\d+)
        ((?P<release>[a-z]+)(?P<num>\d+))?
serialize =
        {major}.{minor}.{patch}{release}{num}
        {major}.{minor}.{patch}

[bumpversion:part:release]
values =
        placeholder
        dev

or this

[bumpversion]
current_version = 0.1.0
parse = (?P<major>\d+)
        \.(?P<minor>\d+)
        \.(?P<patch>\d+)
        ((?P<release>[a-z]+)(?P<num>\d+))?
serialize =
        {major}.{minor}.{patch}{release}{num}
        {major}.{minor}.{patch}

[bumpversion:part:release]
optional_value = placeholder
values =
        placeholder
        dev

suits your needs (where in the latter case we are just being explicit about the fact that placeholder is in fact an optional_value),

adamgranthendry commented 3 years ago

@peritus and @c4urself As a followup to the above, would it be prudent to update bump2version to use list slicing, search for the optional_value, and traverse the array from here through the rest of the values? In addition, adding another flag traverse_reversed = True/False # default: False might help as well.

adamgranthendry commented 3 years ago

@dacox As another item, when going from rapid-development (0.x.y) or final major releases (#.x.y) to the next pre-release (#+1.x.y-alpha.1), if you have bumpversion set to commit with each bump, you'll want to override that on the commandline so you can bump both the major part and the pre-release part, like this:

bumpversion --no-comit major
bumpversion pre --message 'Bump version: {0.x.y} → {new_version}'

replacing x and y obviously with the last version (or N.x.y, as appropriate).

se7entyse7en commented 2 years ago

I used bumpversion in mostly all my projects, but dealing with prereleases became frustrating. Basically, I wanted something like:

0.1.0 -> 0.2.0-dev.1 -> 0.2.0-dev.2 -> 0.2.0-dev.3 -> 0.2.0

and it required some gymnastics to achieve it and I ended up using custom scripts. Also, I wanted to bump some files only for non-prereleases (e.g. I wanted the CHANGELOG file to be updated only for non-prereleases), and this also required some custom scripting.

I ended up writing semver. The approach that I adopted is to let the user specify a custom JS function in the configuration on how to bump the prerelease part of the version.

You can have a look at the configuration used by semver itself here. In particular, you can see the JS function:

[semver.prerelease]
bump_script = '''
var PREFIX = "dev.";
function bump(version) {
  var counter = !version.prerelease ? 0 : parseInt(version.prerelease.slice(PREFIX.length));
  return `${PREFIX}${counter + 1}`;
}
'''

As an example, let's say that the starting version is 0.1.0:

Though, semver only works with versions that comply with semver specification.