Coverage for tsfpga/tools/version_number_handler.py: 0%
60 statements
« prev ^ index » next coverage.py v6.4, created at 2022-05-28 04:01 +0000
« prev ^ index » next coverage.py v6.4, created at 2022-05-28 04:01 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the tsfpga project.
5# https://tsfpga.com
6# https://gitlab.com/tsfpga/tsfpga
7# --------------------------------------------------------------------------------------------------
8# A set of tools for versions and releases. Should be reusable between projects.
9# --------------------------------------------------------------------------------------------------
11import json
12import re
13import sys
14from urllib.request import urlopen
16from packaging.version import parse
18from tsfpga.system_utils import create_file, read_file
21# Contents of unreleased.rst when it is empty
22UNRELEASED_EMPTY = "Nothing here yet.\n"
25class VersionNumberHandler:
27 """
28 Class for handling the version number in __init__.py.
29 """
31 _version_regexp = re.compile(r"\n__version__ = \"(\S+?)\"\n")
33 def __init__(self, repo, version_file_path):
34 """
35 Arguments:
36 repo (`git.Repo`): The git repository to work with.
37 version_file_path (pathlib.Path): The ``__init__.py`` file that shall be modified.
38 """
39 self._repo = repo
40 self._file_path = version_file_path
42 def update(self, new_version):
43 """
44 Set a new version number.
46 Arguments:
47 new_version (str): Version number.
48 """
49 old_version = self._get_current_version()
50 self._verify_that_newer_version_number_is_greater_than_older(
51 older_version=old_version, newer_version=new_version
52 )
54 self._set_new_version(new_version)
56 def bump_to_prelease(self):
57 """
58 Bump to next version number. E.g. go from 8.0.2 to 8.0.3-dev.
59 """
60 current_version = self._get_current_version()
61 (major, minor, patch) = current_version.release
62 new_version = f"{major}.{minor}.{patch + 1}-dev"
63 self._verify_that_newer_version_number_is_greater_than_older(
64 older_version=current_version, newer_version=new_version
65 )
67 self._set_new_version(new_version)
69 @staticmethod
70 def _verify_that_newer_version_number_is_greater_than_older(older_version, newer_version):
71 if older_version >= parse(newer_version):
72 sys.exit(f"New version {newer_version} is not greater than old version {older_version}")
74 def _get_current_version(self):
75 data = read_file(self._file_path)
77 match = self._version_regexp.search(data)
78 if match is None:
79 raise RuntimeError(f"Could not find version value in {self._file_path}")
81 version = match.group(1)
82 return parse(version)
84 def _set_new_version(self, new_version):
85 data = read_file(self._file_path)
87 updated_data = self._version_regexp.sub(f'\n__version__ = "{new_version}"\n', data)
88 create_file(self._file_path, updated_data)
90 # Add file so that it gets included in upcoming commit
91 self._repo.index.add(str(self._file_path.resolve()))
94def verify_new_version_number(repo, pypi_project_name, new_version, unreleased_notes_file):
95 """
96 Verify that the new version number is sane for this project. Will check git log and PyPI
97 release history.
99 Arguments:
100 repo (`git.Repo`): The git repository to work with.
101 pypi_project_name (str): The name of this project on PyPI.
102 version (str): New version.
103 unreleased_notes_file (pathlib.Path): Path to the "unreleased.rst" release notes file.
104 Must not be empty.
105 """
106 if repo.is_dirty():
107 sys.exit("Must make release from clean repo")
109 if read_file(unreleased_notes_file) in ["", UNRELEASED_EMPTY]:
110 sys.exit(f"The unreleased notes file {unreleased_notes_file} should not be empty")
112 with urlopen(f"https://pypi.python.org/pypi/{pypi_project_name}/json") as file_handle:
113 json_data = json.load(file_handle)
114 if new_version in json_data["releases"]:
115 sys.exit(f"Release {new_version} already exists in PyPI")
117 git_tag = f"v{new_version}"
118 if git_tag in repo.tags:
119 sys.exit(f"Git release tag already exists: {git_tag}")
121 return git_tag
124def commit_and_tag_release(repo, version, git_tag):
125 """
126 Make a git commit with a "release" message, and tag it.
128 Arguments:
129 repo (`git.Repo`): The git repository to work with.
130 version (str): New version.
131 git_tag (str): New git tag.
132 """
133 make_commit(repo=repo, commit_message=f"Release version {version}")
135 repo.create_tag(git_tag)
136 if git_tag not in repo.tags:
137 sys.exit("Git tag failed")
140def make_commit(repo, commit_message):
141 """
142 Make a git commit, and check that it worked.
144 Arguments:
145 repo (`git.Repo`): The git repository to work with.
146 commit_message (str): Commit message to use.
147 """
148 repo.index.commit(commit_message)
149 if repo.is_dirty():
150 sys.exit("Git commit failed")