diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3b77ccb..d735eb5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,11 @@ Changelog Drop ``get_branch_tags`` function which was deprecated since ``1.8.0``. + .. change:: + :tags: core, breaking + + ``version_file`` option now have precedence over any tags in the current branch. + 1.13 ---- diff --git a/docs/options/version_file.rst b/docs/options/version_file.rst index ec2688e..0440a05 100644 --- a/docs/options/version_file.rst +++ b/docs/options/version_file.rst @@ -5,10 +5,6 @@ Version file path template for :ref:`version-file` versioning schema. -.. note:: - - This option is completely ignored if :ref:`tag-release` schema is used. - .. note:: This option conflicts with :ref:`version-callback-option`, only one of them can be set. diff --git a/docs/schemas/file/dev_release_file.rst b/docs/schemas/file/dev_release_file.rst index dc90312..09b46a3 100644 --- a/docs/schemas/file/dev_release_file.rst +++ b/docs/schemas/file/dev_release_file.rst @@ -19,9 +19,6 @@ For example, current repo state is: | ... -**And there are no tags in the current branch** (``dev``), **all -of them are placed in the** ``master`` **branch.** - If you want to create development releases (prereleases) for the next planned version ``1.1.0``, so every commit to ``dev`` branch should produce version number like ``1.1.0.dev123`` (just plain increment) or even ``1.1.0.dev123+git.sha`` (to describe which commit was used for this exact version). @@ -39,16 +36,17 @@ Then update your config file: .. code:: python - import os + # you can use os.path instead of pathlib + from pathlib import Path - HERE = os.path.dirname(__file__) - VERSION_FILE = os.path.join(HERE, "VERSION.txt") + root_path = Path(__file__).parent + version_file = root_path / "VERSION.txt" setuptools.setup( ..., setuptools_git_versioning={ "enabled": True, - "version_file": VERSION_FILE, + "version_file": version_file, "count_commits_from_version_file": True, # enable commits tracking "dev_template": "{tag}.dev{ccount}", # suffix for versions will be .dev "dirty_template": "{tag}.dev{ccount}", # same thing here @@ -66,22 +64,16 @@ Then update your config file: dev_template = "{tag}.dev{ccount}" dirty_template = "{tag}.dev{ccount}" -In case of next release version ``1.1.0`` the third commit to ``dev`` branch will produce +In case of next release version ``1.1.0``, the third commit to ``dev`` branch will produce version number ``1.1.0.dev3``, and so on. Release process -"""""""""""""""" +""""""""""""""" - Merge ``dev`` branch into ``master`` branch. -- Tag commit in the ``master`` branch with next release version (e.g. ``1.1.0``). Tag will be used as a version number for the release. - - .. warning:: - - Do not place any tags in the ``dev`` branch! - +- Tag commit in the ``master`` branch, and publis a repease from code on this branch. - Checkout back to ``dev`` branch - Save next release version (e.g. ``1.2.0``) in ``VERSION`` or ``VERSION.txt`` file in the ``dev`` branch. - - Next commits to a ``dev`` branch will lead to returning this next release version plus dev suffix, like ``1.2.0.dev1`` or so. - ``N`` in ``.devN`` suffix is a number of commits since the last change of a certain file. @@ -109,7 +101,7 @@ For example, if the branch name is something like ``alpha``, ``beta``, ..., setuptools_git_versioning={ "enabled": True, - "version_file": VERSION_FILE, + "version_file": version_file, "count_commits_from_version_file": True, "dev_template": "{tag}.{branch}{ccount}", "dirty_template": "{tag}.{branch}{ccount}", @@ -149,7 +141,7 @@ It is also possible to use branch names like ``1.0-alpha`` or ``1.1.beta``: "count_commits_from_version_file": True, "dev_template": "{branch}{ccount}", "dirty_template": "{branch}{ccount}", - "version_file": VERSION_FILE, + "version_file": version_file, }, ) @@ -172,7 +164,7 @@ If branch name is not :pep:`440` compliant, use :ref:`branch-formatter-option` o .. note:: - Although ``VERSION`` file content is not used in this case, you still need to update it + Although ``VERSION`` file content is not used in this particular example, you still need to update it while changing your next release version. Otherwise this tool will not be able to properly calculate version number. diff --git a/docs/schemas/file/version_file.rst b/docs/schemas/file/version_file.rst index 0a6ba0c..95d2489 100644 --- a/docs/schemas/file/version_file.rst +++ b/docs/schemas/file/version_file.rst @@ -19,9 +19,6 @@ For example, current repo state is: | ... -**And there are no tags in the current branch** (``dev``), **all -of them are placed in the** ``master`` **branch.** - By default, when you try to get current version, you'll receive some initial value (see :ref:`starting-version-option` option). @@ -64,8 +61,7 @@ Then place it in both the branches and update your config file: When you'll try to get current version in non-master branch, the content of this file (``1.0.0``) will be returned instead default version number. -**Please take into account that version_file is ignored if any tag -is present in the current branch.** +**Please take into account that any tags in the repo are ignored if this option is being used.** See also """"""""" diff --git a/setuptools_git_versioning.py b/setuptools_git_versioning.py index fe21a68..1447bba 100644 --- a/setuptools_git_versioning.py +++ b/setuptools_git_versioning.py @@ -506,6 +506,9 @@ def version_from_git( ) return _get_version_from_callback(version_callback, package_name, root=root) + head_sha = get_sha(root=root) + log.log(INFO, "HEAD SHA-256: %r", head_sha) + filter_callback = None if tag_filter: filter_callback = _callable_factory( @@ -516,16 +519,22 @@ def version_from_git( root=root, ) - from_file = False log.log(INFO, "Getting latest tag") log.log(DEBUG, "Sorting tags by %r", sort_by) tag = get_tag(sort_by=sort_by, root=root, filter_callback=filter_callback) + if not tag: + log.log(INFO, "No tags found") + tag_sha = None + on_tag = False + else: + tag_sha = get_sha(tag, root=root) + log.log(INFO, "Tag SHA-256: %r", tag_sha) - if tag is None: - log.log(INFO, "No tag, checking for 'version_file'") - if version_file is None: - log.log(INFO, "No 'version_file' set, return starting_version %r", starting_version) - return _sanitize_version(starting_version) + on_tag = head_sha is not None and head_sha == tag_sha + log.log(INFO, "HEAD is tagged: %r", on_tag) + + if version_file: + log.log(INFO, "Checking for 'version_file'") if not Path(version_file).exists(): log.log( @@ -534,26 +543,30 @@ def version_from_git( version_file, starting_version, ) - return _sanitize_version(starting_version) + tag = None + else: + log.log(INFO, "Reading version_file '%s' content", version_file) + tag = _read_version_from_file(version_file, root=root) or None - log.log(INFO, "version_file '%s' does exist, reading its content", version_file) - from_file = True - tag = _read_version_from_file(version_file, root=root) + if not tag: + log.log(INFO, "File %r is empty", version_file) + else: + log.log(DEBUG, "File content: %r", tag) + if not count_commits_from_version_file: + return _sanitize_version(tag) - if not tag: - log.log(INFO, "File is empty, return starting_version %r", version_file, starting_version) - return _sanitize_version(starting_version) + file_sha = get_latest_file_commit(version_file, root=root) + log.log(DEBUG, "File SHA-256: %r", file_sha) - log.log(DEBUG, "File content: %r", tag) - if not count_commits_from_version_file: - return _sanitize_version(tag) + ccount = count_since(file_sha, root=root) if file_sha is not None else None + log.log(INFO, "Commits count between HEAD and last version file change: %r", ccount) - tag_sha = get_latest_file_commit(version_file, root=root) - log.log(DEBUG, "File SHA-256: %r", tag_sha) - else: - log.log(INFO, "Latest tag: %r", tag) - tag_sha = get_sha(tag, root=root) - log.log(INFO, "Tag SHA-256: %r", tag_sha) + elif not head_sha: + log.log(INFO, "Not a git repo, or repo without any branch") + + elif tag_sha: + ccount = count_since(tag_sha, root=root) + log.log(INFO, "Commits count between HEAD and last tag: %r", ccount) if tag_formatter is not None: tag_format_callback = _callable_factory( @@ -567,19 +580,13 @@ def version_from_git( tag = tag_format_callback(tag) log.log(DEBUG, "Tag after formatting: %r", tag) + if not tag: + log.log(INFO, "No source for version, return starting_version %r", starting_version) + return _sanitize_version(starting_version) + dirty = is_dirty(root=root) log.log(INFO, "Is dirty: %r", dirty) - head_sha = get_sha(root=root) - log.log(INFO, "HEAD SHA-256: %r", head_sha) - - full_sha = head_sha if head_sha is not None else "" - ccount = count_since(tag_sha, root=root) if tag_sha is not None else None - log.log(INFO, "Commits count between HEAD and latest tag: %r", ccount) - - on_tag = head_sha is not None and head_sha == tag_sha and not from_file - log.log(INFO, "HEAD is tagged: %r", on_tag) - branch = get_branch(root=root) log.log(INFO, "Current branch: %r", branch) @@ -605,6 +612,7 @@ def version_from_git( log.log(INFO, "Using template from 'template' option") t = template + full_sha = head_sha if head_sha is not None else "" version = _resolve_substitutions(t, sha=full_sha[:8], tag=tag, ccount=ccount, branch=branch, full_sha=full_sha) log.log(INFO, "Version number after resolving substitutions: %r", version) return _sanitize_version(version) diff --git a/tests/test_integration/test_version_callback.py b/tests/test_integration/test_version_callback.py index e73d8a0..3479493 100644 --- a/tests/test_integration/test_version_callback.py +++ b/tests/test_integration/test_version_callback.py @@ -205,7 +205,7 @@ def test_version_callback_not_a_repo(repo_dir, create_config): assert get_version_module(os.getcwd(), args=[repo_dir]) == version -def test_version_callback_has_more_priority_than_tag(repo, create_config): +def test_version_callback_has_higher_priority_than_tag(repo, create_config): version = "1.0.0" create_file(repo, "version.py", VERSION_PY.format(version=version), commit=False) diff --git a/tests/test_integration/test_version_file.py b/tests/test_integration/test_version_file.py index 27b6624..119f06c 100644 --- a/tests/test_integration/test_version_file.py +++ b/tests/test_integration/test_version_file.py @@ -64,11 +64,10 @@ def test_version_file_count_commits(repo, create_config, template, subst): "count_commits_from_version_file": True, } if template: - # template is not ignored + # template is ignored config["dev_template"] = template create_config(repo, config) - create_file(repo, "VERSION.txt", "1.0.0") full_sha = get_full_sha(repo) @@ -177,7 +176,7 @@ def test_version_file_wrong_version_number(repo, version, create_config, count_c @pytest.mark.flaky(reruns=3) # sha and full_sha can start with 0 which are removed, just try again -def test_version_file_tag_is_preferred(repo, create_config): +def test_version_file_tagged_history(repo, create_config): create_tag(repo, "1.2.3") create_file(repo, "VERSION.txt", "1.0.0") @@ -190,7 +189,24 @@ def test_version_file_tag_is_preferred(repo, create_config): ) sha = get_sha(repo) - assert get_version(repo) == f"1.2.3.post2+git.{sha}" + assert get_version(repo) == f"1.0.0.post1+git.{sha}" + + +@pytest.mark.flaky(reruns=3) # sha and full_sha can start with 0 which are removed, just try again +def test_version_file_tagged_head(repo, create_config): + create_file(repo, "VERSION.txt", "1.0.0") + create_config( + repo, + { + "version_file": "VERSION.txt", + "count_commits_from_version_file": True, + }, + ) + create_tag(repo, "1.2.3") + + # template is for release, because commit is tagged + # but version_file content is up to user + assert get_version(repo) == "1.0.0" @pytest.mark.parametrize("starting_version, version", [(None, "0.0.1"), ("1.2.3", "1.2.3")])