Detailed tests of vcs.py ======================== .. :doctest: .. :setup: zest.releaser.tests.functional.setup .. :teardown: zest.releaser.tests.functional.teardown Some initial imports: >>> from zest.releaser import vcs >>> import os BaseVersionControl is the base class for subversion/mercurial/git support. It handles some base cases and has a bunch of NotImplementedError methods. When started, it stores the current working directory: >>> svnsourcedir 'TESTTEMP/tha.example-svn' >>> os.chdir(svnsourcedir) >>> checkout = vcs.BaseVersionControl() >>> checkout.workingdir 'TESTTEMP/tha.example-svn' Methods that must be implemented in subclasses ---------------------------------------------- >>> checkout.name() Traceback (most recent call last): ... NotImplementedError >>> checkout.available_tags() Traceback (most recent call last): ... NotImplementedError >>> checkout.prepare_checkout_dir('prefix') Traceback (most recent call last): ... NotImplementedError >>> checkout.tag_url('arg') Traceback (most recent call last): ... NotImplementedError >>> checkout.cmd_diff() Traceback (most recent call last): ... NotImplementedError >>> checkout.cmd_commit('arg') Traceback (most recent call last): ... NotImplementedError >>> checkout.cmd_diff_last_commit_against_tag('arg') Traceback (most recent call last): ... NotImplementedError >>> checkout.cmd_create_tag('arg') Traceback (most recent call last): ... NotImplementedError Tag handling ------------ Extraction of tags is handled by the subclasses. The one thing that the baseclass does is to check if a tag has already been made earlier: >>> def mock_available_tags(): ... return ['0.1', '0.2'] >>> checkout.available_tags = mock_available_tags >>> checkout.tag_exists('1.0') False >>> checkout.tag_exists('0.2') True Version handling ---------------- Create a project with a ``version.txt`` in it like often found in old zope products: >>> versiontxtproject = os.path.join(tempdir, 'vp') >>> os.mkdir(versiontxtproject) >>> os.chdir(versiontxtproject) >>> dont_care = open('version.txt', 'w').write('1.0 dev') We need some version control marker (like an ``.svn`` dir): >>> os.mkdir('.marker') >>> checkout = vcs.BaseVersionControl() >>> checkout.internal_filename = '.marker' Open the project with the BaseVersionControl and it finds the version file and returns the cleaned-up version: >>> checkout.get_version_txt_version() '1.0dev' Setting the version works also with version.txt files (the setup.py scenario is tested in the other tests). >>> checkout.version = '1.1' >>> print(open('version.txt').read()) 1.1 In old Plone products, the setup.py often reads the version.txt and uses that as the version value. In those cases, the version must be written to the version.txt and the setup.py must be left unmolested. >>> lines = [ ... "from setuptools import setup", ... "setup(name='urgh', version=open('version.txt').read().strip())"] >>> dont_care = open('setup.py', 'w').write('\n'.join(lines)) >>> checkout.version = '1.2' >>> print(open('version.txt').read()) 1.2 >>> print(open('setup.py').read()) from setuptools import setup setup(name='urgh', version=open('version.txt').read().strip()) If the setup.py version is different, this takes precedence and the version.txt is the one left as-is. >>> lines = [ ... "from setuptools import setup", ... "setup(name='urgh',", ... " version='1.3',", ... " )"] >>> dont_care = open('setup.py', 'w').write('\n'.join(lines)) >>> checkout.version = '1.4' >>> print(open('version.txt').read()) # Still at 1.2 1.2 >>> print(open('setup.py').read()) # Modified into 1.4 from setuptools import setup setup(name='urgh', version='1.4', ) The version writing breaks down if there's more than just a "version=" on that line. The 99.9% case works, though. Another option is a ``__version__`` marker in a Python file. We cannot reliably figure out the right Python file to look in, so this file needs to be specified explicitly. As `PEP 396 `_ specifies, the ``__version__`` attribute and the ``setup.py`` version need to be derived one from the other, so zest.releaser only looks at one version source. If a ``__version__`` marker file is specified, that's where we'll look and otherwise not. Create a Python file with ``__version__`` without configuring it. This won't change a thing: >>> lines = [ ... "import something", ... "__version__ = '2.0'", ... "print('something.else')"] >>> dont_care = open('some_file.py', 'w').write('\n'.join(lines)) >>> checkout.version '1.4' Add a ``setup.cfg`` with a pointer at the Python file and its version gets picked up: >>> lines = [ ... "[zest.releaser]", ... "python-file-with-version = some_file.py"] >>> dont_care = open('setup.cfg', 'w').write('\n'.join(lines)) >>> checkout.get_python_file_version() '2.0' >>> checkout.version '2.0' Setting it sets it in the correct Python file: >>> checkout.version = '2.1' >>> print(open('some_file.py').read()) import something __version__ = '2.1' print('something.else') Version corner cases -------------------- Version files can also be called ``VERSION`` instead of ``version.txt`` (or ``VERSION.TXT``): >>> versiontxtproject = os.path.join(tempdir, 'vp2') >>> os.mkdir(versiontxtproject) >>> os.chdir(versiontxtproject) >>> dont_care = open('VERSION', 'w').write('1.0 dev') We need some version control marker (like an ``.svn`` dir): >>> os.mkdir('.marker') >>> checkout = vcs.BaseVersionControl() >>> checkout.internal_filename = '.marker' Open the project with the BaseVersionControl and it finds the version file and returns the cleaned-up version: >>> checkout.get_version_txt_version() '1.0dev' Setting the version works also with ``VERSION`` files: >>> checkout.version = '1.1' >>> print(open('VERSION').read()) 1.1 Same with a ``VERSION.txt``: >>> os.remove('VERSION') >>> dont_care = open('VERSION.txt', 'w').write('22.3') >>> checkout.get_version_txt_version() '22.3' >>> checkout.version = '22.4' >>> print(open('VERSION.txt').read()) 22.4 Version files can also be called ``version.rst`` (or .md or so) instead of ``version.txt``: >>> os.remove('VERSION.txt') >>> dont_care = open('version.rst', 'w').write('25.0') >>> checkout.get_version_txt_version() '25.0'