Detailed tests of svn.py ======================== .. :doctest: .. :setup: zest.releaser.tests.functional.setup .. :teardown: zest.releaser.tests.functional.teardown Some initial imports: >>> from zest.releaser import svn >>> from zest.releaser.utils import execute_command >>> import os Project name ------------ The prepared svn project has a setup.py, so the name in there is used: >>> os.chdir(svnsourcedir) >>> checkout = svn.Subversion() >>> checkout.name 'tha.example' When the setup.py doesn't exist or doesn't return a proper name, we fall back to the name in the svn url before trunk/tags: >>> orig = checkout.get_setup_py_name >>> checkout.get_setup_py_name= lambda: None # Hack >>> checkout.name 'tha.example' >>> checkout.get_setup_py_name = orig # Restore hack Diff and commit --------------- Make a change: >>> setup_py = os.path.join(svnsourcedir, 'setup.py') >>> dont_care = open(setup_py, 'a').write('\na = 2\n') >>> cmd = checkout.cmd_diff() >>> cmd 'svn diff' >>> print(execute_command(cmd)) Index: ... --- setup.py (revision 3) +++ setup.py (working copy) @@ -36,3 +36,5 @@ 'console_scripts': [ ]}, ) + +a = 2 Commit it: >>> cmd = checkout.cmd_commit('small tweak') >>> cmd 'svn commit -m "small tweak"' >>> print(execute_command(cmd)) Sending setup.py Transmitting file data... Committed revision 5. Tags ---- Originally there are no tags: >>> checkout.available_tags() [] The name of the /tags directory (so: a plural) is succesfully detected: >>> checkout._tags_name 'tags' Create a tag and it will show up: >>> cmd = checkout.cmd_create_tag('0.1') >>> cmd 'svn cp file://TESTREPO/tha.example/trunk file://TESTREPO/tha.example/tags/0.1 -m "Tagging 0.1"' >>> dont_care = execute_command(cmd) >>> checkout.available_tags() ['0.1'] A tag url is important for subversion: >>> checkout.tag_url('holadijee') 'file://TESTREPO/tha.example/tags/holadijee' Make and commit a small change: >>> dont_care = open(setup_py, 'a').write('\nb = 3\n') >>> cmd = checkout.cmd_commit('small tweak') >>> print(execute_command(cmd)) Sending setup.py Transmitting file data . Committed revision 7. Now we can request the changes since a specific tag. Note that we use the ``--non-interactive`` option to make sure it can be run from cronjobs or post-commit hooks: >>> cmd = checkout.cmd_diff_last_commit_against_tag('0.1') >>> cmd 'svn --non-interactive diff file://TESTREPO/tha.example/tags/0.1 file://TESTREPO/tha.example/trunk' >>> print(execute_command(cmd)) Index: setup.py =================================================================== --- setup.py (.../tags/0.1) (revision 7) +++ setup.py (.../trunk) (revision 7) @@ -38,3 +38,5 @@ ) a = 2 + +b = 3 Making a tag checkout --------------------- For checking out a tag, we first need a temp folder to do the checkout in: >>> temp = checkout.prepare_checkout_dir('somename') >>> temp 'TMPDIR/somename...' >>> os.path.isdir(temp) True The tag checkout command makes a checkout in that tempdir: >>> cmd = checkout.cmd_checkout_from_tag('0.1', temp) >>> cmd 'svn co file://TESTREPO/tha.example/tags/0.1 TMPDIR/somename...' >>> print('\n'.join(sorted(execute_command(cmd).splitlines()))) A TMPDIR/somename.../CHANGES.txt A TMPDIR/somename.../README.txt A TMPDIR/somename.../TODO.txt A TMPDIR/somename.../bootstrap.py A TMPDIR/somename.../buildout.cfg A TMPDIR/somename.../grok-1.0a4.cfg A TMPDIR/somename.../setup.cfg A TMPDIR/somename.../setup.py A TMPDIR/somename.../src A TMPDIR/somename.../src/tha A TMPDIR/somename.../src/tha/__init__.py A TMPDIR/somename.../src/tha/example A TMPDIR/somename.../src/tha/example/USAGE.txt A TMPDIR/somename.../src/tha/example/__init__.py A TMPDIR/somename.../src/tha/example/tests A TMPDIR/somename.../src/tha/example/tests/__init__.py A TMPDIR/somename.../src/tha/example/tests/sample.txt A TMPDIR/somename.../src/tha/example/tests/test.py Checked out revision 7. The checkout is done directly in that temporary directory, so not in a newly created subdirectory of it: >>> sorted(os.listdir(temp)) ['.svn', 'CHANGES.txt', ...] Tag corner cases ---------------- Both corner cases do a ``sys.exit()``. This method has been monkey patched by the test setup. >>> import sys >>> sys.exit(1) Traceback (most recent call last): ... RuntimeError: SYSTEM EXIT (code=1) The information on tags is stored on the server, not locally. So a network connection is needed. When there's a network problem, it is reported: >>> # Internal-detail hack >>> orig = checkout._cached_url >>> checkout._cached_url = 'http://non.existing/nonexisting/trunk' >>> # Actual call >>> checkout.available_tags() Traceback (most recent call last): ... RuntimeError: SYSTEM EXIT (code=1) >>> checkout._cached_url = orig Subversion stores tags in the /tags directory. Just a convention. Sometimes projects have only a /trunk set up and no tag directory yet. Set up a new sample project in the repository: >>> repo_url 'file://TESTREPO' >>> cmd = 'svn mkdir %s/sample -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) >>> cmd = 'svn mkdir %s/sample/trunk -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) Make a checkout: >>> os.chdir(tempdir) >>> cmd = 'svn co %s/sample/trunk sample' % repo_url >>> dont_care = execute_command(cmd) >>> os.chdir('sample') Now look up the tags. This asks us to create the tags/ directory. For the answering, set up the answer test mode: >>> from zest.releaser import utils >>> utils.TESTMODE = True >>> sample_checkout = svn.Subversion() There is no tags dir yet, so the tags name detection (/tag or /tags) returns None: >>> print(sample_checkout._tags_name) None Answer 'no' the first time we get asked to create the directory. This means zest.releaser has no business with this project, so exit. >>> utils.AUTO_RESPONSE False >>> utils.test_answer_book.set_answers(['n']) >>> sample_checkout.available_tags() Traceback (most recent call last): ... RuntimeError: SYSTEM EXIT (code=0) Answer 'yes' and the tags dir gets created. The available tags result is obviously an empty list: >>> print(sample_checkout._tags_name) None >>> utils.test_answer_book.set_answers(['y']) >>> sample_checkout.available_tags() tags dir does not exist at file://TESTREPO/sample/tags Question: Shall I create it (Y/n)? Our reply: y Committed revision 10. [] >>> print(sample_checkout._tags_name) tags >>> cmd = 'svn list %s/sample' % repo_url >>> print(execute_command(cmd)) tags/ trunk/ Singular /tag instead of /tags dir ---------------------------------- Subversion stores tags in the /tags directory. Just a convention. But for instance on codespeak, the singular /tag (and /branch) is the convention. Zest.releaser supports that. Set up a new sample project in the repository: >>> repo_url 'file://TESTREPO' >>> cmd = 'svn mkdir %s/singular -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) >>> cmd = 'svn mkdir %s/singular/trunk -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) And make a /tag directory. We don't support adding one ourselves (we always suggest /tags, make a /tag dir yourself if you really really need it), but we *do* detect and use one: >>> cmd = 'svn mkdir %s/singular/tag -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) Make a checkout: >>> os.chdir(tempdir) >>> cmd = 'svn co %s/singular/trunk singular' % repo_url >>> dont_care = execute_command(cmd) >>> os.chdir('singular') Now look up the tags. This asks us to create the tags/ directory. For the answering, set up the answer test mode: >>> from zest.releaser import utils >>> utils.TESTMODE = True Fire up zest.releaser's subversion support. The _tags_name() method figures out the correct name: >>> singular_checkout = svn.Subversion() >>> singular_checkout._tags_name 'tag' There are no tags yet: >>> singular_checkout.available_tags() [] Tag urls are formed correctly with the singular name: >>> singular_checkout.tag_url('0.1') 'file://TESTREPO/singular/tag/0.1' Tag and checkout commands also use the singular: >>> cmd = singular_checkout.cmd_checkout_from_tag('0.1', temp) >>> cmd 'svn co file://TESTREPO/singular/tag/0.1 TMPDIR/somename...' >>> cmd = singular_checkout.cmd_create_tag('0.1') >>> cmd 'svn cp file://TESTREPO/singular/trunk file://TESTREPO/singular/tag/0.1 -m "Tagging 0.1"' If we have branch checkout, the base url is still extracted correctly, even if the singular /tag and /branch is used: >>> cmd = 'svn mkdir %s/singular/branch -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) >>> cmd = 'svn mkdir %s/singular/branch/mybranch -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) >>> cmd = 'svn mkdir %s/singular/tag/mytag -m "mkdir"' % repo_url >>> dont_care = execute_command(cmd) >>> os.chdir(tempdir) >>> cmd = 'svn co %s/singular/branch/mybranch mysingularbranch' % repo_url >>> dont_care = execute_command(cmd) >>> cmd = 'svn co %s/singular/tag/mytag mysingulartag' % repo_url >>> dont_care = execute_command(cmd) >>> os.chdir(tempdir) >>> os.chdir('mysingularbranch') >>> singular_checkout = svn.Subversion() >>> singular_checkout._base_from_svn() 'file://TESTREPO/singular/' >>> os.chdir(tempdir) >>> os.chdir('mysingulartag') >>> singular_checkout = svn.Subversion() >>> singular_checkout._base_from_svn() 'file://TESTREPO/singular/' Pushing changes --------------- For svn, committing is enough, no need to push stuff to the server as that happens automatically: >>> checkout.push_commands() [] Tags within a trunk -------------------- Some legacy projects, often converted from CVS, have multiple subprojects under a single trunk. This creates URLs that contain a regular svn layout within an top level trunk. For example:: trunk/ projectA/ trunk/ tags/ branches/ projectB trunk/ tags/ branches/ Create trunk/ for both projects: >>> repo_url 'file://TESTREPO' >>> cmd = 'svn mkdir --parents %s/trunk/projectA/trunk -m"mk projectA"' % repo_url >>> dont_care = execute_command(cmd) >>> cmd = 'svn mkdir %s/trunk/projectB/trunk -m "mkdir projectB"' % repo_url >>> dont_care = execute_command(cmd) Make a checkout: >>> os.chdir(tempdir) >>> cmd = 'svn co %s/trunk' % repo_url >>> dont_care = execute_command(cmd) Now check that we try to create the proper trunk/projectA/tags directory >>> os.chdir('trunk/projectA/trunk') >>> from zest.releaser import utils >>> utils.TESTMODE = True >>> sample_checkout = svn.Subversion() >>> utils.test_answer_book.set_answers(['y']) >>> sample_checkout.available_tags() tags dir does not exist at file://TESTREPO/trunk/projectA/tags Question: Shall I create it (Y/n)? Our reply: y Committed revision 18. [] >>> cmd = 'svn list -R %s/trunk' % repo_url >>> print(execute_command(cmd)) projectA/ projectA/tags/ projectA/trunk/