From 029533115f87fd6b58090b65f89fc526210fc98a Mon Sep 17 00:00:00 2001 From: Etienne Trimaille Date: Wed, 28 Apr 2021 10:05:17 +0700 Subject: [PATCH] Add release next version command --- docs/usage/cli_changelog.md | 10 +++++++++ qgispluginci/release.py | 40 +++++++++++++++++++++++++++++++----- qgispluginci/utils.py | 9 ++++++++ qgispluginci/version_note.py | 33 +++++++++++++++++++++++++++++ test/test_release.py | 30 ++++++++++++++++++++++++++- test/test_utils.py | 16 +++++++++++++++ 6 files changed, 132 insertions(+), 6 deletions(-) diff --git a/docs/usage/cli_changelog.md b/docs/usage/cli_changelog.md index 5e71f9af..43c464b4 100644 --- a/docs/usage/cli_changelog.md +++ b/docs/usage/cli_changelog.md @@ -3,6 +3,8 @@ Manipulate `CHANGELOG.md` file, extracting relevant information. Used within the [package](cli_package) and [release](cli_release) commands to populate the `metadata.txt` and the GitHub Release description. +It also provides two keywords `next` and `latest` instead of using a version number when creating a zip. + ## Command help ```bash @@ -25,6 +27,14 @@ The `CHANGELOG.md` file must follow the convention [Keep A Changelog](https://ke - Extract the `CHANGELOG.md` content and copy it into the `changelog` section within plugin `metadata.txt` - Extract the `n` latest versions from `CHANGELOG.md` into `metadata.txt` - Get the latest version release note +- When packaging or releasing, you can use these keywords : + - `latest` will make a package of the latest tag described in the changelog file. + - `next` will make a package of the possible smallest higher tag : + - `3.4.0` -> `3.4.1-alpha` + - `3.4.0-alpha` -> `3.4.1-alpha.1` + - `3.4.0-alpha1` -> `3.4.1-alpha2` + +Be careful when you use the `next` command. It is designed to make a package which is not based on a specific version (on CI mainly). You should be careful with the tag you are creating if you have some packages delivered as well with the `next` command otherwise QGIS Plugin manager might not warn users about possible new release. ## Examples diff --git a/qgispluginci/release.py b/qgispluginci/release.py index f74bd287..16d7f9cd 100644 --- a/qgispluginci/release.py +++ b/qgispluginci/release.py @@ -30,7 +30,7 @@ ) from qgispluginci.parameters import Parameters from qgispluginci.translation import Translation -from qgispluginci.utils import configure_file, parse_tag, replace_in_file +from qgispluginci.utils import add_in_file, configure_file, parse_tag, replace_in_file def create_archive( @@ -101,6 +101,20 @@ def create_archive( "version={}".format(release_version), ) + # Git SHA1 + add_in_file( + "{}/metadata.txt".format(parameters.plugin_path), + "git_sha1={}".format(repo.head.object.hexsha), + ) + + # Date/time in UTC + add_in_file( + "{}/metadata.txt".format(parameters.plugin_path), + "date_time={}".format( + datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + ), + ) + # set the plugin as experimental on a pre-release if is_prerelease: replace_in_file( @@ -372,6 +386,25 @@ def upload_plugin_to_osgeo(username: str, password: str, archive: str): sys.exit(1) +def check_release_keywords(release_version: str) -> str: + """ Check if we are releasing some special version shortcut. """ + if release_version not in ("latest", "next"): + return release_version + + parser = ChangelogParser() + if not parser.has_changelog(): + raise Exception( + "Not possible to determine the latest tag without a changelog file." + ) + + if release_version == "latest": + return parser.latest_version() + + # Next tags + latest_version = parse_tag(parser.latest_version()) + return latest_version.next_version().version + + def release( parameters: Parameters, release_version: str, @@ -414,10 +447,7 @@ def release( disable_submodule_update If omitted, a git submodule is updated. If specified, git submodules will not be updated/initialized before packaging. """ - - if release_version == "latest": - parser = ChangelogParser() - release_version = parser.latest_version() + release_version = check_release_keywords(release_version) if transifex_token is not None: tr = Translation( diff --git a/qgispluginci/utils.py b/qgispluginci/utils.py index 11642240..551aa0c5 100644 --- a/qgispluginci/utils.py +++ b/qgispluginci/utils.py @@ -13,6 +13,15 @@ def replace_in_file(file_path: str, pattern, new: str, encoding: str = "utf8"): f.write(content) +def add_in_file(file_path: str, new_line: str, encoding: str = "utf8"): + """ Add a line in a file. """ + with open(file_path, "r", encoding=encoding) as f: + content = f.read() + content += "{}\n".format(new_line) + with open(file_path, "w", encoding=encoding) as f: + f.write(content) + + def configure_file(source_file: str, dest_file: str, replace: dict): with open(source_file, "r", encoding="utf-8") as f: content = f.read() diff --git a/qgispluginci/version_note.py b/qgispluginci/version_note.py index fb5d7f0b..5095e931 100644 --- a/qgispluginci/version_note.py +++ b/qgispluginci/version_note.py @@ -29,3 +29,36 @@ def version(self) -> str: return f"{self.major}.{self.minor}.{self.patch}-{self.prerelease}" else: return f"{self.major}.{self.minor}.{self.patch}" + + def increment_pre_release(self) -> str: + """ Increment the pre-release string. """ + items = self.prerelease.split(".") + + numbers = "".join([i for i in self.prerelease if i.isdigit()]) + + if len(items) == 1: + if numbers: + return f"{self.prerelease[0:-len(numbers)]}{int(numbers) + 1}" + else: + return f"{self.prerelease}.1" + + return f"{items[0]}.{int(numbers) + 1}" + + def next_version(self) -> NamedTuple: + """ Increment the pre-release string or the patch. """ + # "pre" is not supported by QGIS + # https://github.com/qgis/QGIS/blob/master/python/pyplugin_installer/version_compare.py + if not self.prerelease: + return VersionNote( + major=self.major, + minor=self.minor, + patch=str(int(self.patch) + 1), + prerelease="alpha", + ) + + return VersionNote( + major=self.major, + minor=self.minor, + patch=self.patch, + prerelease=self.increment_pre_release(), + ) diff --git a/test/test_release.py b/test/test_release.py index c553d9d3..75b1b657 100644 --- a/test/test_release.py +++ b/test/test_release.py @@ -19,7 +19,7 @@ from qgispluginci.changelog import ChangelogParser from qgispluginci.exceptions import GithubReleaseNotFound from qgispluginci.parameters import DASH_WARNING, Parameters -from qgispluginci.release import release +from qgispluginci.release import check_release_keywords, release from qgispluginci.translation import Translation from qgispluginci.utils import replace_in_file @@ -179,6 +179,34 @@ def test_release_changelog(self): f"changelog detection failed in release: {data}", ) + def test_release_latest(self): + """ Test releasing the latest version. """ + release(self.parameters, "latest") + archive_name = self.parameters.archive_name( + self.parameters.plugin_path, check_release_keywords("latest") + ) + with ZipFile(archive_name, "r") as zip_file: + data = zip_file.read("qgis_plugin_CI_testing/metadata.txt") + self.assertEqual( + data.find(b"version=latest"), -1 + ) # Version is the one in __about__.py + self.assertGreater(data.find(b"git_sha1="), 0) + self.assertGreater(data.find(b"date_time="), 0) + + def test_release_next(self): + """ Test releasing the next version. """ + release(self.parameters, "next") + archive_name = self.parameters.archive_name( + self.parameters.plugin_path, check_release_keywords("next") + ) + with ZipFile(archive_name, "r") as zip_file: + data = zip_file.read("qgis_plugin_CI_testing/metadata.txt") + self.assertEqual( + data.find(b"version=next"), -1 + ) # Version is the one in __about__.py + self.assertGreater(data.find(b"git_sha1="), 0) + self.assertGreater(data.find(b"date_time="), 0) + if __name__ == "__main__": unittest.main() diff --git a/test/test_utils.py b/test/test_utils.py index 10f2aa66..b93a23ae 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -49,6 +49,22 @@ def test_version_note_from_tag(self): self.assertIsNone(version.prerelease) self.assertFalse(version.is_prerelease) + def test_next_version(self): + """ Test to guess the next version. """ + self.assertEqual(parse_tag("10.1.0").next_version().version, "10.1.1-alpha") + self.assertEqual( + parse_tag("10.1.0-beta").next_version().version, "10.1.0-beta.1" + ) + self.assertEqual( + parse_tag("10.1.0-beta1").next_version().version, "10.1.0-beta2" + ) + self.assertEqual( + parse_tag("10.1.0-beta.2").next_version().version, "10.1.0-beta.3" + ) + self.assertEqual( + parse_tag("10.1.0-rc.10").next_version().version, "10.1.0-rc.11" + ) + if __name__ == "__main__": unittest.main()