diff --git a/CHANGELOG.md b/CHANGELOG.md index ca4aac15..ef399acc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- add handling of PROJECT_DEV_VERSION in CMakeLists.txt if set [#32](https://github.com/greenbone/pontos/pull/32) ### Changed - set releasename to projectname version [#25](https://github.com/greenbone/pontos/pull/25) ### Deprecated diff --git a/poetry.lock b/poetry.lock index cfca50be..50f6761f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -144,11 +144,11 @@ description = "A Python utility / library to sort Python imports." name = "isort" optional = false python-versions = ">=3.6,<4.0" -version = "5.4.2" +version = "5.5.1" [package.extras] colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib", "tomlkit (>=0.5.3)"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] [[package]] @@ -376,8 +376,8 @@ idna = [ {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] isort = [ - {file = "isort-5.4.2-py3-none-any.whl", hash = "sha256:60a1b97e33f61243d12647aaaa3e6cc6778f5eb9f42997650f1cc975b6008750"}, - {file = "isort-5.4.2.tar.gz", hash = "sha256:d488ba1c5a2db721669cc180180d5acf84ebdc5af7827f7aaeaa75f73cf0e2b8"}, + {file = "isort-5.5.1-py3-none-any.whl", hash = "sha256:a200d47b7ee8b7f7d0a9646650160c4a51b6a91a9413fd31b1da2c4de789f5d3"}, + {file = "isort-5.5.1.tar.gz", hash = "sha256:92533892058de0306e51c88f22ece002a209dc8e80288aa3cec6d443060d584f"}, ] lazy-object-proxy = [ {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, diff --git a/pontos/release/release.py b/pontos/release/release.py index fd367926..10aab708 100644 --- a/pontos/release/release.py +++ b/pontos/release/release.py @@ -139,8 +139,13 @@ def parse(args=None): ) -def update_version(to: str, _version: version) -> Tuple[bool, str]: - executed, filename = _version.main(False, args=["--quiet", "update", to]) +def update_version( + to: str, _version: version, *, develop: bool +) -> Tuple[bool, str]: + develop_arg = '--develop' if develop else '' + executed, filename = _version.main( + False, args=["--quiet", develop_arg, "update", to] + ) if not executed: if filename == "": @@ -186,7 +191,9 @@ def prepare( if git_version.encode() in git_tags.stdout.splitlines(): raise ValueError('git tag {} is already taken.'.format(git_version)) - executed, filename = update_version(release_version, _version) + executed, filename = update_version( + release_version, _version, develop=False + ) if not executed: return False @@ -226,7 +233,7 @@ def prepare( release_text.write_text(changelog_text) # set to new version add skeleton - executed, filename = update_version(nextversion, _version) + executed, filename = update_version(nextversion, _version, develop=True) if not executed: return False diff --git a/pontos/version/cmake_version.py b/pontos/version/cmake_version.py index 174c4fc0..e3d1e7ce 100644 --- a/pontos/version/cmake_version.py +++ b/pontos/version/cmake_version.py @@ -56,6 +56,7 @@ def run(self, args=None) -> Union[int, str]: if commandline_arguments.command == 'update': self.update_version( commandline_arguments.version, + develop=commandline_arguments.develop, ) elif commandline_arguments.command == 'show': self.print_current_version() @@ -70,11 +71,11 @@ def __print(self, *args): if not self.__quiet: print(*args) - def update_version(self, version: str): + def update_version(self, version: str, *, develop: bool = False): content = self.__cmake_filepath.read_text() cmvp = CMakeVersionParser(content) previous_version = cmvp.get_current_version() - new_content = cmvp.update_version(version) + new_content = cmvp.update_version(version, develop=develop) self.__cmake_filepath.write_text(new_content) self.__print( 'Updated version from {} to {}'.format(previous_version, version) @@ -96,17 +97,20 @@ def verify_version(self, version: str): class CMakeVersionParser: def __init__(self, cmake_content_lines: str): - line_no, current_version = self._find_version_in_cmake( + line_no, current_version, pd_line_no, pd = self._find_version_in_cmake( cmake_content_lines ) self._cmake_content_lines = cmake_content_lines.split('\n') self._version_line_number = line_no self._current_version = current_version + self._project_dev_version_line_number = pd_line_no + self._project_dev_version = pd __cmake_scanner = re.Scanner( [ (r'#.*', lambda _, token: ("comment", token)), (r'"[^"]*"', lambda _, token: ("string", token)), + (r'"[0-9]+"', lambda _, token: ("number", token)), (r"\(", lambda _, token: ("open_bracket", token)), (r"\)", lambda _, token: ("close_bracket", token)), (r'[^ \t\r\n()#"]+', lambda _, token: ("word", token)), @@ -119,7 +123,7 @@ def __init__(self, cmake_content_lines: str): def get_current_version(self) -> str: return self._current_version - def update_version(self, new_version: str) -> str: + def update_version(self, new_version: str, *, develop: bool = False) -> str: if not is_version_pep440_compliant(new_version): raise VersionError( "version {} is not pep 440 compliant.".format(new_version) @@ -130,6 +134,15 @@ def update_version(self, new_version: str) -> str: self._cmake_content_lines[self._version_line_number] = updated self._current_version = new_version + if self._project_dev_version_line_number: + self._cmake_content_lines[ + self._project_dev_version_line_number + ] = self._cmake_content_lines[ + self._project_dev_version_line_number + ].replace( + str(int(not develop)), str(int(develop)) + ) + self._project_dev_version = str(int(develop)) return '\n'.join(self._cmake_content_lines) @@ -137,6 +150,15 @@ def _find_version_in_cmake(self, content: str) -> Tuple[int, str]: in_project = False in_version = False + version_line_no: int = None + version: str = None + + in_set = False + in_project_dev_version = False + + project_dev_version_line_no: int = None + project_dev_version: int = None + for lineno, token_type, value in self._tokenize(content): if token_type == 'word' and value == 'project': in_project = True @@ -145,11 +167,34 @@ def _find_version_in_cmake(self, content: str) -> Tuple[int, str]: elif in_version and ( token_type == 'word' or token_type == 'string' ): - return lineno, value + version_line_no = lineno + version = value + in_project = False + in_version = False + elif token_type == 'word' and value == 'set': + in_set = True + elif ( + in_set + and token_type == 'word' + and value == 'PROJECT_DEV_VERSION' + ): + in_project_dev_version = True + elif in_project_dev_version and ( + token_type == 'word' or token_type == 'number' + ): + project_dev_version_line_no = lineno + project_dev_version = value elif in_project and token_type == 'close_bracket': raise ValueError('unable to find cmake version in project.') - raise ValueError('unable to find cmake project.') + if not version or version_line_no is None: + raise ValueError('unable to find cmake version.') + return ( + version_line_no, + version, + project_dev_version_line_no, + project_dev_version, + ) def _tokenize( self, content: str diff --git a/pontos/version/version.py b/pontos/version/version.py index 12fa89fe..56e8ce1e 100644 --- a/pontos/version/version.py +++ b/pontos/version/version.py @@ -136,6 +136,11 @@ def initialize_default_parser() -> argparse.ArgumentParser: help="don't check if version is already set", action="store_true", ) + update_parser.add_argument( + '--develop', + help="indicates if it is a develop version", + action="store_true", + ) return parser @@ -291,10 +296,7 @@ def run(self, args=None) -> Union[int, str]: try: if args.command == 'update': - self.update_version( - args.version, - force=args.force, - ) + self.update_version(args.version, force=args.force) elif args.command == 'show': self.print_current_version() elif args.command == 'verify': diff --git a/tests/version/test_cmake_version.py b/tests/version/test_cmake_version.py index fbbaa82c..d3f0d123 100644 --- a/tests/version/test_cmake_version.py +++ b/tests/version/test_cmake_version.py @@ -3,6 +3,8 @@ from unittest.mock import MagicMock from pontos.version import CMakeVersionParser, VersionError, CMakeVersionCommand +# pylint: disable=W0212 + class CMakeVersionCommandTestCase(unittest.TestCase): def test_raise_exception_file_not_exists(self): @@ -61,12 +63,16 @@ def test_raise_update_version(self): fake_path = fake_path_class.return_value fake_path.__str__.return_value = 'CMakeLists.txt' fake_path.exists.return_value = True - fake_path.read_text.return_value = "project(VERSION 21)" + fake_path.read_text.return_value = ( + "project(VERSION 21)\nset(PROJECT_DEV_VERSION 0)" + ) CMakeVersionCommand(cmake_lists_path=fake_path).run( - args=['update', '22'] + args=['update', '22', '--develop'] ) fake_path.read_text.assert_called_with() - fake_path.write_text.assert_called_with('project(VERSION 22)') + fake_path.write_text.assert_called_with( + 'project(VERSION 22)\nset(PROJECT_DEV_VERSION 1)' + ) class CMakeVersionParserTestCase(unittest.TestCase): @@ -95,6 +101,45 @@ def test_get_current_version_multiline_project(self): under_test = CMakeVersionParser("project\n(\nVERSION\n\t 2.3.4)") self.assertEqual(under_test.get_current_version(), '2.3.4') + def test_find_project_dev_version(self): + test_cmake_lists = """ + project( + DESCRIPTION something + VERSION 41.41.41 + LANGUAGES c + ) + set( + PROJECT_DEV_VERSION 1 + ) + """ + under_test = CMakeVersionParser(test_cmake_lists) + self.assertEqual(under_test._project_dev_version_line_number, 7) + self.assertEqual(under_test._project_dev_version, '1') + + def test_update_project_dev_version(self): + test_cmake_lists = """ + project( + DESCRIPTION something + VERSION 41.41.41 + LANGUAGES c + ) + set( + PROJECT_DEV_VERSION 1 + ) + """ + under_test = CMakeVersionParser(test_cmake_lists) + + self.assertEqual(under_test._project_dev_version_line_number, 7) + self.assertEqual(under_test._project_dev_version, '1') + result = under_test.update_version('41.41.41', develop=False) + self.assertEqual(under_test._project_dev_version, '0') + self.assertEqual( + result, + test_cmake_lists.replace( + 'PROJECT_DEV_VERSION 1', 'PROJECT_DEV_VERSION 0' + ), + ) + def test_get_current_version_multiline_project_combined_token(self): under_test = CMakeVersionParser( "project\n(\nDESCRIPTION something VERSION 2.3.4 LANGUAGES c\n)" @@ -115,5 +160,5 @@ def test_raise_exception_no_project(self): ) self.assertEqual( - str(context.exception), 'unable to find cmake project.' + str(context.exception), 'unable to find cmake version.' )