c4urself / bump2version

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

How to restrict search/parse to a single instance in presence of suffixes? #164

Open gimbo opened 4 years ago

gimbo commented 4 years ago

Hi there — I could really do with some help. I'm trying to get bump2version to bump only the string I want in some file, but I can't prevent it from also bumping some "false suffix matches" (I'll explain what I mean by that below).

(BTW: all this is vs py3.7.7 and the current master branch version of bump2version, i.e. 8e6db237).

Context

Consider the following pyproject.toml:

[tool.poetry]
name = "myproject"
version = "1.0.0"
description = "My project"
authors = ["Andy Gimblett <gimbo@gimbo.org.uk>"]
license = "MIT"

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]
fredversion = "1.0.0"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

Things to note:

  1. In the [tool.poetry] section we have version = "1.0.0" — this is what I want to bump.
  2. In [tool.poetry.dev-dependencies] we have fredversion = "1.0.0" — a fictional package name, but critically it has the same version number as my project right now, and the package name ends in the word version.

    This is what I mean by a "false suffix match": version = "1.0.0" (the project version string, which I want to bump) exists on this line as a suffix.

Idea 1: Naive first attempt

Then I might hope that this .bumpversion.cfg would do what I want:

[bumpversion]
current_version = 1.0.1

[bumpversion:file:pyproject.toml]
search = version = "{current_version}"
replace = version = "{new_version}"

Alas, when I bump2version patch, that bumps both; I can understand why it does that: search is doing a substring search, and there's nothing there saying "entire line" or "pin to start of line". Fair enough.

Idea 2: Multi-line search string?

README.md says of search:

Can be multiple lines, templated using Python Format String Syntax

So I wondered about using a multi-line search, matching vs name = "myproject"\nversion="1.0.0", but that doesn't seem to work, e.g. this:

[bumpversion:file:pyproject.toml]
search = name = "myproject"\nversion = "{current_version}"
replace = name = "myproject"\nversion = "{new_version}"

fails to match at all, falling back on the default value for search, alas, and utterly mangling pyproject.toml; in that issue, @florisla comments that:

It looks like one can not use whitespace after a newline in the search expression (at least when it's defined in an INI-like config file).

so maybe that's the problem I'm hitting here; is there an alternative to specifying the config in an INI-like file? I'm not aware of one.

Or am I just specifying a multi-line search in a wrong way?

Idea 3: regexes to the rescue?

My understanding is that search can't use regexes, but parse can. I've tried and failed in two ways there:

First, I tried pinning to line start using ^, and following a pattern suggested by @florisla here, so we have:

[bumpversion:file:pyproject.toml]
parse = ^version\s*=\s*['"](?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)['"]
serialize = version = "{major}.{minor}.{patch}"

Unfortunately, this has the same result as "Idea 1" above: it correctly bumps my project version, but also bumps the fredversion version. This confused me initially because I was trying to understand how regex operations could fail in that way, but then I noticed that a totally broken parse (e.g. if I start with ^XXXversionXXX, say) has the same result! So it seems again there's a weird fallback trap here, just like in issue #127, but for parse. :-/

I tried simplifying the parse regex, e.g. to the following:

parse = ^version = "(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)"

but this has the same behaviour; I guess it's falling back so basically right now I really don't know what I'm doing wrong here...

My second thought about regexes was to try a multiline thing including the name = "myproject" line again, but I obviously couldn't get that to work either.

Conclusion

This feels like it should be easy; what am I missing or doing wrong? It seems to me like search/parse work well in most simple cases but TBH "match vs the whole line" doesn't feel like it should be as hard as this... And the presence of default fallbacks when things fail makes this much much harder to debug than it should be.

I'd really appreciate any help or insight anyone can offer into this; I'd like to use bump2version but right now I can't trust it at all to only bump what I want, meaning the --commit and --tag options are useless to me. It's a minor frustration in the scheme of things, but OTOH the whole point of the tool is to streamline these minor frustrations, right? :-)

Many thanks to anyone who has read this far, and to everyone who's contributed to this project.

balrok commented 4 years ago

Hello @gimbo, in maven we have a similar problem where dependencies as well as our software are inside the <version> xml-tag. Our solution to this is to modify our xml a bit: <version>{current_version}</version><!--ourversion-->. You can do something similar inside the toml by writing version = "1.0.0" # managed by bump2version

gimbo commented 4 years ago

@balrok Thanks - that's a good idea, and it looks like that strategy is working for me. Much appreciated!

harpalsahota commented 6 months ago

@gimbo - bit of a long shot. Can you share your solution? I've run into the exact same problem.