c4urself / bump2version

Version-bump your software with a single command
https://pypi.python.org/pypi/bump2version
MIT License
1.05k stars 134 forks source link

CalVer Support #200

Open JonZeolla opened 3 years ago

JonZeolla commented 3 years ago

I have been looking for a project that supports both calver and semver. I'd like to see what the interest would be to add calver features here, similar to those supported in bumpver

markmacode commented 3 years ago

I do not have as much knowledge on calver as I do on semver. Although I believe bump2version could still meet the requirements of a calver system. While it does not have features to automatically bump based on the calendar year, it also does not strictly enforce semver semantics.

Is there a specific area or feature where bump2version is failing to support a calver versioning system?

florisla commented 3 years ago

Bump2version can definitely be used for calver schemes. You have to tell it the current year and month though.

There is support for using now and utcnow but that's only used for serializing a version number, not defining it.

CalVer is not a very tight specification, so it's hard to say if we support all edge cases. Example: if the trailing .1 in 2021.02.1 is not a day number, then would that be a major, minor or micro part?

What's definitely missing in bump2version is documentation. We can add example configurations like was done here for semantic versioning: https://github.com/c4urself/bump2version/pull/177

@JonZeolla Do you have a specific scheme in mind? We can supply an example configuration.

florisla commented 3 years ago

This configuration supports the twisted scheme.

current_version = 20.3.0
parse = (?P<year>\d\d)\.(?P<month>\d\d?)\.(?P<minor>\d+)((?P<modifier>.+)(?P<micro>\d+))?
serialize =
    {year}.{month}.{minor}
    {year}.{month}.{minor}{modifier}{micro}

[bumpversion:part:modifier]
optional_value = release
values =
    beta
    rc
    release

[bumpversion:file:version.txt]

Allowing command bump2version --new-version=21.4.0rc1 boguspart --allow-dirty.

JonZeolla commented 3 years ago

Thanks @florisla I put together something very similar last night for my use case. I'm in the process of wrapping up my proof of concept and then I will provide an update here with pros/cons and gaps

JonZeolla commented 3 years ago

Ok, so I broke one item out to #201 but in general it would be nice to see documentation about kicking off bumpversion from python3 without using any kind of spawn or popen(if it's supported - see my approach below) and a generic CalVer example. Other than that, though, it worked much better than the alternative projects and I'm happy with the result.

It is also worth noting that the patterns defined here are quite useful, as you mentioned. I was able to re-implement the ones that applied to my situation, but I think this helper feature makes it more accessible.

Here is the initial setup.cfg config that I landed on:

[bumpversion]
current_version = 2021.02.00
parse = (?P<year>2[0-1]\d{2})\.(?P<month>(0\d|1[0-2]))(.(?P<increment>\d{2}))?
serialize =
  {year}.{month}
  {year}.{month}.{increment}
commit_message = "Automatically generated release {new_version}"
commit = True
tag = True
push = True

[bumpversion:file:testing/__init__.py]

[bumpversion:file:README.md]

[bumpversion:file:setup.cfg]

Which is managed via pyinvoke using the following:

from bumpversion.cli import main as bumpversion

def release(c):  # pylint: disable=unused-argument
    """Make a new release of Testing"""
    if REPO.head.is_detached:
        LOG.error("In detached HEAD state, refusing to release")
        sys.exit(1)
    elif REPO.active_branch.name != "main":
        LOG.error("Not on the main branch, refusing to release")
        sys.exit(1)
    # Get the current date info
    date_info = datetime.now().strftime("%Y.%m")

    # Our CalVer pattern which works until year 2200, up to 100 releases a
    # month (purposefully excludes builds)
    pattern = re.compile(r"v2[0-1][0-9]{2}.(0[0-9]|1[0-2]).[0-9]{2}")

    # Identify and set the increment
    for tag in reversed(REPO.tags):
        if pattern.fullmatch(tag.name):
            latest_release = tag.name
            break
    else:
        latest_release = None

    if latest_release and date_info == latest_release[:7]:
        increment = str(int(latest_release[8:]) + 1).zfill(2)
    else:
        increment = "01"

    new_version = date_info + "." + increment

    bumpversion(["--new-version", new_version, "unusedpart"])
florisla commented 3 years ago

Thanks for the feedback, that's really useful.

I'll spin off two issues for improving the documentation. Three in fact, because the invoke integration is really useful too.

Out of curiosity, which other tools did you try and what were the roadblocks there? Especially interested in tbump and `bumpvers.