From 633d8d005ac2508ee7196a9273bcf29e2f263495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Fri, 6 Dec 2024 08:56:26 +0100 Subject: [PATCH] `micromamba/mamba --version` displays pre-release version names + establishes pre-release versions name scheme (#3639) --- libmamba/include/mamba/version.hpp | 21 +++---- libmamba/include/mamba/version.hpp.tmpl | 20 +++---- libmambapy/src/libmambapy/version.py | 5 +- libmambapy/src/libmambapy/version.py.tmpl | 3 + micromamba/src/version.hpp | 21 +++---- micromamba/src/version.hpp.tmpl | 19 +++--- releaser.py | 37 +++++++----- update_changelog.py | 3 +- version_scheme.py | 72 +++++++++++++++++++++++ 9 files changed, 144 insertions(+), 57 deletions(-) create mode 100644 version_scheme.py diff --git a/libmamba/include/mamba/version.hpp b/libmamba/include/mamba/version.hpp index 2f765bbb99..a02335ae67 100644 --- a/libmamba/include/mamba/version.hpp +++ b/libmamba/include/mamba/version.hpp @@ -12,27 +12,28 @@ #define LIBMAMBA_VERSION_MAJOR 2 #define LIBMAMBA_VERSION_MINOR 0 -#define LIBMAMBA_VERSION_PATCH 4 +#define LIBMAMBA_VERSION_PATCH 5 +#define LIBMAMBA_VERSION_IS_PRERELEASE 1 +#if LIBMAMBA_VERSION_IS_PRERELEASE == 1 +#define LIBMAMBA_VERSION_PRERELEASE_NAME "dev0" +#endif + +#define LIBMAMBA_VERSION_STRING "2.0.5.dev0" +#define LIBMAMBA_VERSION \ + (LIBMAMBA_VERSION_MAJOR * 10000 + LIBMAMBA_VERSION_MINOR * 100 + LIBMAMBA_VERSION_PATCH) // Binary version #define LIBMAMBA_BINARY_CURRENT 2 #define LIBMAMBA_BINARY_REVISION 0 #define LIBMAMBA_BINARY_AGE 0 -#define __LIBMAMBA_STRINGIZE_IMPL(s) #s -#define __LIBMAMBA_STRINGIZE(s) __LIBMAMBA_STRINGIZE_IMPL(s) - -#define LIBMAMBA_VERSION \ - (LIBMAMBA_VERSION_MAJOR * 10000 + LIBMAMBA_VERSION_MINOR * 100 + LIBMAMBA_VERSION_PATCH) -#define LIBMAMBA_VERSION_STRING \ - __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MAJOR) \ - "." __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MINOR) "." __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_PATCH) - namespace mamba { std::string version(); + [[deprecated("will be replaced in a future minor version")]] std::array version_arr(); + } #endif diff --git a/libmamba/include/mamba/version.hpp.tmpl b/libmamba/include/mamba/version.hpp.tmpl index 415be2fd65..b978b55b66 100644 --- a/libmamba/include/mamba/version.hpp.tmpl +++ b/libmamba/include/mamba/version.hpp.tmpl @@ -13,27 +13,27 @@ #define LIBMAMBA_VERSION_MAJOR {{ version_major }} #define LIBMAMBA_VERSION_MINOR {{ version_minor }} #define LIBMAMBA_VERSION_PATCH {{ version_patch }} +#define LIBMAMBA_VERSION_IS_PRERELEASE {{ version_is_prerelease }} +#if LIBMAMBA_VERSION_IS_PRERELEASE == 1 +#define LIBMAMBA_VERSION_PRERELEASE_NAME "{{ version_prerelease_name }}" +#endif + +#define LIBMAMBA_VERSION_STRING "{{ version_name }}" +#define LIBMAMBA_VERSION \ + (LIBMAMBA_VERSION_MAJOR * 10000 + LIBMAMBA_VERSION_MINOR * 100 + LIBMAMBA_VERSION_PATCH) // Binary version #define LIBMAMBA_BINARY_CURRENT 2 #define LIBMAMBA_BINARY_REVISION 0 #define LIBMAMBA_BINARY_AGE 0 -#define __LIBMAMBA_STRINGIZE_IMPL(s) #s -#define __LIBMAMBA_STRINGIZE(s) __LIBMAMBA_STRINGIZE_IMPL(s) - -#define LIBMAMBA_VERSION \ - (LIBMAMBA_VERSION_MAJOR * 10000 + LIBMAMBA_VERSION_MINOR * 100 + LIBMAMBA_VERSION_PATCH) -#define LIBMAMBA_VERSION_STRING \ - __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MAJOR) \ - "." __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MINOR) "." __LIBMAMBA_STRINGIZE( \ - LIBMAMBA_VERSION_PATCH) - namespace mamba { std::string version(); + [[deprecated("will be replaced in a future minor version")]] std::array version_arr(); + } #endif diff --git a/libmambapy/src/libmambapy/version.py b/libmambapy/src/libmambapy/version.py index bba7506976..d6f8f065d8 100644 --- a/libmambapy/src/libmambapy/version.py +++ b/libmambapy/src/libmambapy/version.py @@ -1,2 +1,5 @@ -version_info = ("2", "0", "4") +version_info = ("2", "0", "5") +version_prerelease = "dev0" __version__ = ".".join(map(str, version_info)) +if version_prerelease != "": + __version__ = "{}.{}".format(__version__, version_prerelease) diff --git a/libmambapy/src/libmambapy/version.py.tmpl b/libmambapy/src/libmambapy/version.py.tmpl index cfde257b58..14ae29a173 100644 --- a/libmambapy/src/libmambapy/version.py.tmpl +++ b/libmambapy/src/libmambapy/version.py.tmpl @@ -1,2 +1,5 @@ version_info = ("{{ version_major }}", "{{ version_minor }}", "{{ version_patch }}") +version_prerelease = "{{ version_prerelease_name }}" __version__ = ".".join(map(str, version_info)) +if version_prerelease != "": + __version__ = "{}.{}".format(__version__, version_prerelease) diff --git a/micromamba/src/version.hpp b/micromamba/src/version.hpp index 5c9021739e..d77de33b45 100644 --- a/micromamba/src/version.hpp +++ b/micromamba/src/version.hpp @@ -12,27 +12,28 @@ #define UMAMBA_VERSION_MAJOR 2 #define UMAMBA_VERSION_MINOR 0 -#define UMAMBA_VERSION_PATCH 4 +#define UMAMBA_VERSION_PATCH 5 +#define UMAMBA_VERSION_IS_PRERELEASE 1 +#if UMAMBA_VERSION_IS_PRERELEASE == 1 +#define UMAMBA_VERSION_PRERELEASE_NAME "dev0" +#endif + +#define UMAMBA_VERSION_STRING "2.0.5.dev0" +#define UMAMBA_VERSION \ + (UMAMBA_VERSION_MAJOR * 10000 + UMAMBA_VERSION_MINOR * 100 + UMAMBA_VERSION_PATCH) // Binary version #define UMAMBA_BINARY_CURRENT 1 #define UMAMBA_BINARY_REVISION 0 #define UMAMBA_BINARY_AGE 0 -#define __UMAMBA_STRINGIZE_IMPL(s) #s -#define __UMAMBA_STRINGIZE(s) __UMAMBA_STRINGIZE_IMPL(s) - -#define UMAMBA_VERSION \ - (UMAMBA_VERSION_MAJOR * 10000 + UMAMBA_VERSION_MINOR * 100 + UMAMBA_VERSION_PATCH) -#define UMAMBA_VERSION_STRING \ - __UMAMBA_STRINGIZE(UMAMBA_VERSION_MAJOR) \ - "." __UMAMBA_STRINGIZE(UMAMBA_VERSION_MINOR) "." __UMAMBA_STRINGIZE(UMAMBA_VERSION_PATCH) - namespace umamba { std::string version(); + [[deprecated("will be replaced in a future minor version")]] std::array version_arr(); + } #endif diff --git a/micromamba/src/version.hpp.tmpl b/micromamba/src/version.hpp.tmpl index 93d8f8d422..5845cf593f 100644 --- a/micromamba/src/version.hpp.tmpl +++ b/micromamba/src/version.hpp.tmpl @@ -13,26 +13,27 @@ #define UMAMBA_VERSION_MAJOR {{ version_major }} #define UMAMBA_VERSION_MINOR {{ version_minor }} #define UMAMBA_VERSION_PATCH {{ version_patch }} +#define UMAMBA_VERSION_IS_PRERELEASE {{ version_is_prerelease }} +#if UMAMBA_VERSION_IS_PRERELEASE == 1 +#define UMAMBA_VERSION_PRERELEASE_NAME "{{ version_prerelease_name }}" +#endif + +#define UMAMBA_VERSION_STRING "{{ version_name }}" +#define UMAMBA_VERSION \ + (UMAMBA_VERSION_MAJOR * 10000 + UMAMBA_VERSION_MINOR * 100 + UMAMBA_VERSION_PATCH) // Binary version #define UMAMBA_BINARY_CURRENT 1 #define UMAMBA_BINARY_REVISION 0 #define UMAMBA_BINARY_AGE 0 -#define __UMAMBA_STRINGIZE_IMPL(s) #s -#define __UMAMBA_STRINGIZE(s) __UMAMBA_STRINGIZE_IMPL(s) - -#define UMAMBA_VERSION \ - (UMAMBA_VERSION_MAJOR * 10000 + UMAMBA_VERSION_MINOR * 100 + UMAMBA_VERSION_PATCH) -#define UMAMBA_VERSION_STRING \ - __UMAMBA_STRINGIZE(UMAMBA_VERSION_MAJOR) \ - "." __UMAMBA_STRINGIZE(UMAMBA_VERSION_MINOR) "." __UMAMBA_STRINGIZE(UMAMBA_VERSION_PATCH) - namespace umamba { std::string version(); + [[deprecated("will be replaced in a future minor version")]] std::array version_arr(); + } #endif diff --git a/releaser.py b/releaser.py index 6ddc5c16cf..2b85d677a5 100644 --- a/releaser.py +++ b/releaser.py @@ -4,6 +4,7 @@ import copy import datetime import re +from version_scheme import version_info template = {"version": None, "changes": []} @@ -14,7 +15,26 @@ } -def apply_changelog(name, version, changes): +def apply_changelog(name, version_name, changes): + version = version_info(version_name) + + def template_substitute(contents): + x = contents.replace("{{ version_major }}", version.major) + x = x.replace("{{ version_minor }}", version.minor) + x = x.replace("{{ version_patch }}", version.patch) + x = x.replace("{{ version_is_prerelease }}", "1" if version.pre_release else "0") + x = x.replace("{{ version_prerelease_name }}", version.pre_release) + x = x.replace("{{ version_name }}", version_name) + return x + + if name in templates: + template = templates[name] + with open(template, "r") as fi: + final = template_substitute(fi.read()) + with open(template[: -len(".tmpl")], "w") as fo: + fo.write(final) + + # version has been processed, we can now produce the changes res = "" today = datetime.date.today() fmt_today = today.strftime("%B %d, %Y") @@ -38,21 +58,6 @@ def apply_changelog(name, version, changes): with open(cl_file, "w") as fo: fo.write(res + prev_cl) - version_major, version_minor, version_patch = version.split(".") - - def template_substitute(contents): - x = contents.replace("{{ version_major }}", version_major) - x = x.replace("{{ version_minor }}", version_minor) - x = x.replace("{{ version_patch }}", version_patch) - return x - - if name in templates: - template = templates[name] - with open(template, "r") as fi: - final = template_substitute(fi.read()) - with open(template[: -len(".tmpl")], "w") as fo: - fo.write(final) - def commands(changes): commit_msg = ", ".join([f"{x} {changes[x]['version']}" for x in changes]) diff --git a/update_changelog.py b/update_changelog.py index 917ddd00a0..01885f8ef4 100644 --- a/update_changelog.py +++ b/update_changelog.py @@ -21,6 +21,7 @@ import json import re import subprocess +from version_scheme import version_info def validate_date(date_str): @@ -88,7 +89,7 @@ def main(): "Enter the starting date of commits to be included in the release in the format YYYY-MM-DD: " ) validate_date(commits_starting_date) - release_version = input("Enter the version to be released: ") + release_version = version_info(input("Enter the version to be released: ")) # Get commits to include in the release log_cmd = "git log --since=" + commits_starting_date diff --git a/version_scheme.py b/version_scheme.py new file mode 100644 index 0000000000..4bdd794cb4 --- /dev/null +++ b/version_scheme.py @@ -0,0 +1,72 @@ +# Parses and validates the version scheme chosen for mamba versions. +# Specifically, we use a dot to separate pre-release names and use complete names for `alpha` and `beta`. +# +# See: +# - discussion in https://github.com/mamba-org/mamba/issues/3638 +# - https://conda-forge.org/docs/maintainer/knowledge_base/#pre-release-version-sorting +# - https://github.com/conda/conda/blob/cc21508563912268649f207723fd5114fa21b906/conda/models/version.py#L115-L143 +class version_info: + major = "" + minor = "" + patch = "" + pre_release = "" + name = "" + + def __init__(self, version: str): + if "-" in version: + raise ValueError( + "'{}' is not a valid version name : `-` is reserved for another usage in conda packages version names".format( + version + ) + ) + + VALID_VERSION_PRERELEASE_TYPES = ("alpha", "beta", "rc", "dev") + version_fields = version.split(".") + version_fields_count = len(version_fields) + if version_fields_count < 3: + raise ValueError( + "'{}' is not a valid version name : valid version scheme contains 3 or more dots-separated fields, the pre-release name starting with the 4th field (valid examples: 1.2.3, 0.1.2.alpha3, 0.1.2.alpha.3)".format( + version + ) + ) + + self.major = version_fields[0] + self.minor = version_fields[1] + self.patch = version_fields[2] + self.pre_release = "" + if version_fields_count > 3: + # we assume here that all the additional dot-separated values are part of the pre-release name + self.pre_release = ".".join(version_fields[3:]) + + version_errors = [] + + if not self.major.isdigit(): + version_errors.append("'{}' is not a valid major version number".format(self.major)) + if not self.minor.isdigit(): + version_errors.append("'{}' is not a valid minor version number".format(self.minor)) + if not self.patch.isdigit(): + version_errors.append("'{}' is not a valid patch version number".format(self.patch)) + + if self.pre_release != "" and not self.pre_release.startswith( + VALID_VERSION_PRERELEASE_TYPES + ): + version_errors.append( + "'{}' is not a valid pre-release name, pre-release names must start with either : {} ".format( + self.pre_release, VALID_VERSION_PRERELEASE_TYPES + ) + ) + + if len(version_errors) > 0: + error_message = "'{}' is not a valid version name:".format(version) + for error in version_errors: + error_message += "\n - {}".format(error) + hint = ( + "examples of valid versions: 1.2.3, 0.1.2, 1.2.3.alpha0, 1.2.3.beta1, 3.4.5.beta.2" + ) + error_message += "\n{}".format(hint) + raise ValueError(error_message) + + self.name = version + + def __str__(self): + return self.name