peritus / bumpversion

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

allow multiple config sections per file #117

Closed chadawagner closed 3 years ago

chadawagner commented 8 years ago

Assuming it's ok to disallow ":" in filenames, this change would allow config section names for files to have trailing characters that are not interpreted as part of the filename, but that make the key unique in terms of config parsing, e.g.:

[bumpversion:file:myfile:0]
search = some context for {current_version}

[bumpversion:file:myfile:1]
search = another context for {current_version}

In our application, we have two different sets of parse/serialize/search/replace configs that need to be run on the same files (e.g. some versions appear as "major.minor.patch" while others appear as "major_minor_patch", and with different surrounding search context). This one minor change to bumpversion would make such a scenario possible by allowing multiple configuration sections and thus multiple independent search/replace passes per file.

peritus commented 8 years ago

I think : is a perfectly legit character in a filename.

I just tried what happens when I would configure bumpversion like this:

[bumpversion:file:myfile]
search = some context for {current_version}

[bumpversion:file:myfile]
search = another context for {current_version}

But ConfigParser gives

configparser.DuplicateSectionError:
While reading from '.bumpversion.cfg' [line  7]: section 'bumpversion:file:myfile' already exists

.. there's the strict option, which would disable this error, however, then the second section ("another ...") would overwrite the first one.

I support your usecase, but I think we'd have to find a better syntax regarding configuration.

chadawagner commented 8 years ago

Yeah, : is technically legit on some platforms but can still cause problems, but I can see where we would want to avoid any chance of breaking functionality or backward compatibility. If you can think of some other way to get at the issue cleanly, I'd be all for it. Seems like we'd have to somehow define unique keys, since duplicate keys will overwrite each other and would not result in multiple bumpversion processing passes anyway. Perhaps something extra before the filename, e.g.:

[bumpversion:file.0:myfile]

and corresponding re ^bumpversion:(file|part).*?:(.+) ?

peritus commented 8 years ago

I'd totally like to support this usecase, but the proposed configuration format change (or addition) in this pull request is just butt-ugly and workaround to ConfigParsers shortcomings (see my attempt in https://github.com/peritus/bumpversion/pull/117#issuecomment-152135365 ) .. I won't be merging this as it is.

I think there should be another abstraction layer between "file" and "version string occurrence" and a "file" could have many "version string occurrence"s like this:

[bumpversion:version_occurrence:some_context]
search = some context for {current_version}
file = myfile

[bumpversion:version_occurrence:another_context]
search = another context for {current_version}
file = myfile

.. and while I think this is very beautiful from the software architectural point of view and gets the abtractions right, it definitely adds another layer of complexity for the end user (who, in almost all cases would only want to bump one version occurrence per file).

Thanks for showing me that [bumpversion:file] is not the most granular config setting there is.

peritus commented 8 years ago

As I'm writing this, I find the idea tempting to re-architect bumpversion away from a file-centric to a version-occurrence-centric paradigm, while keeping backwards compatibility of course and make the above example part of a "advanced usage" section in the documentation.

lgiordani commented 8 years ago

@peritus may you expand on this version-occurrence-centric paradigm you mentioned? I'm interested but did not exactly catch it

chadawagner commented 8 years ago

Haha - well, I certainly didn't think my proposed hack was "beautiful" (that's why I let my previous comment sit for over a week for replies before committing ;-) ), but it adds support for my use case with a minimal change and without re-architecting the whole thing. I'd be down for whatever you think a good solution would be, and if we're opening it up for major surgery what I would ideally love is to have named sets of config settings (perhaps "version occurrence" as you suggest) that can then be applied to individual files and overridden as needed. So a single file can still have a single section, but could have multiple sets of config settings applied.

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

[bumpversion:special_config_1]
parse = (?P<major>\d+)_(?P<minor>\d+)_(?P<patch>\d+)(\-(?P<release>[a-z]+))?
serialize = 
    {major}_{minor}_{patch}-{release}
    {major}_{minor}_{patch}

[bumpversion:file:setup.py]

[bumpversion:file:other_file.py]
config_sets =
    global
    special_config_1

[bumpversion:file:another_file.py]
config_sets =
    special_config_1

or something like that. Not sure how the overriding might work, maybe that's too much to ask.

garyjohnson commented 8 years ago

Maybe there's a saner way to do this, but I needed this feature on an embedded project that for some bizarre reason stored the version number in multiple places in the project file. Also, on android, I treat the versionCode like a build number and the versionName like major.minor.patch, which means they're updated in different places. Here's my current workaround -- relative paths to the rescue:

[bumpversion]
current_version = 1.1.0.70
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.(?P<build>\d+)
serialize = {major}.{minor}.{patch}.{build}

[bumpversion:file:app/build.gradle]
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
serialize = {major}.{minor}.{patch}
search = versionName "{current_version}
replace = versionName "{new_version}

[bumpversion:file:./app/build.gradle]
parse = (?P<build>\d+)
serialize = {build}
search = versionCode {current_version}
replace = versionCode {new_version}

Yes you can just keep prepending the file with additional ./. Not my ideal solution but it gets the job done.

ashwoods commented 6 years ago

In addition to this, a condition that it only happens when a specific part is bumped would be nice.