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

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# -------------------------------------------------------------------------------------------------- 

10 

11import json 

12import re 

13import sys 

14from urllib.request import urlopen 

15 

16from packaging.version import parse 

17 

18from tsfpga.system_utils import create_file, read_file 

19 

20 

21# Contents of unreleased.rst when it is empty 

22UNRELEASED_EMPTY = "Nothing here yet.\n" 

23 

24 

25class VersionNumberHandler: 

26 

27 """ 

28 Class for handling the version number in __init__.py. 

29 """ 

30 

31 _version_regexp = re.compile(r"\n__version__ = \"(\S+?)\"\n") 

32 

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 

41 

42 def update(self, new_version): 

43 """ 

44 Set a new version number. 

45 

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 ) 

53 

54 self._set_new_version(new_version) 

55 

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 ) 

66 

67 self._set_new_version(new_version) 

68 

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}") 

73 

74 def _get_current_version(self): 

75 data = read_file(self._file_path) 

76 

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}") 

80 

81 version = match.group(1) 

82 return parse(version) 

83 

84 def _set_new_version(self, new_version): 

85 data = read_file(self._file_path) 

86 

87 updated_data = self._version_regexp.sub(f'\n__version__ = "{new_version}"\n', data) 

88 create_file(self._file_path, updated_data) 

89 

90 # Add file so that it gets included in upcoming commit 

91 self._repo.index.add(str(self._file_path.resolve())) 

92 

93 

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. 

98 

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") 

108 

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") 

111 

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") 

116 

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}") 

120 

121 return git_tag 

122 

123 

124def commit_and_tag_release(repo, version, git_tag): 

125 """ 

126 Make a git commit with a "release" message, and tag it. 

127 

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}") 

134 

135 repo.create_tag(git_tag) 

136 if git_tag not in repo.tags: 

137 sys.exit("Git tag failed") 

138 

139 

140def make_commit(repo, commit_message): 

141 """ 

142 Make a git commit, and check that it worked. 

143 

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")