Product versions
It is important to know which version of your product is installed. This especially helps with bug reports. Is someone using 1.0 from your tar ball? A bug fix release from a branch? The cutting edge version from trunk? Read on for some advice on version strings and source code control with subversion.
Version strings
You have just finished ShinyNewProduct and think it is ready to take the market by storm. Great! Let's release it then. Of course you have developed your product in a source code control system. The favourite among Plone developers seems to be subversion, or svn for short. This tutorial will focus on that, but the concepts should be applicable to CVS (Concurrent Versioning System) or other systems. For tips on using CVS instead of subversion, see this tutorial.
Plone versions 3.0, 3.1 and 3.2 incorrectly used the GenericSetup profile version as specified in metadata.xml as package version. This was corrected in Plone 3.3. In Plone 3.3, for eggified packages, the version from the setup.py file of the egg is taken. If the product is not eggified, or the version variable from the egg could not be found, the version.txt file is used instead.
You can argue a lot about the numbers that need to go in there, but your ShinyNewProduct feels like a 1.0 release, so let's just put that in the setup.py file:
version = '1.0'
and commit the change:
commit -m 'Prepare release 1.0'
You should choose a numbering sheme compatible with setuptools, as stated in this doc.
Branches, tags and trunk
Let's say you have your product in http://localhost/svn/ShinyNewProduct. Your actual code should be in a directory called trunk. If you don't have that, it is beyond the scope of this tutorial to help you change that. What I will do is show you how to add two more directories. If you already have them, great!
svn mkdir http://localhost/svn/ShinyNewProduct/branches svn mkdir http://localhost/svn/ShinyNewProduct/tags
The main development is done on trunk. You could choose to develop only on branches instead. In fact, for big changes that take longer than a day to finish, this should be standard practice. It is easy to copy the trunk to a branch, develop code there, merge the changes back to trunk when you're happy and possibly remove the branch again.
Anyway, assume for now that your latest greatest code is in trunk. Now, when people start using your product, they will probably find bugs. That's okay, bugs thrive on software, so it's to be expected. There's no need to be ashamed of yourself. Just fix the bugs. But your users will not only find bugs, they will also come up with feature requests; and if not, then you yourself will. You made the decision to develop new features on trunk. But when you fix a bug your users want to be able to use version 1.0 plus the bug fix, without any new features which may be buggier still (or so they think). So then where do the bug fixes go?
Bugs will need to be fixed in your latest code and in the code that you just released as version 1.0. So at release time you copy your trunk to a branch:
svn copy http://localhost/svn/ShinyNewProduct/trunk \ http://localhost/svn/ShinyNewProduct/branches/1.0
When bugs surface you can fix them on that branch and merge the changes back to trunk.
Sometimes you want to be able to go back to the exact version of your product at release time. Your clever bug fix may have broken something so this branch is unusable at the moment. That's when the tags subdirectory comes into play. At release time you should do:
svn copy http://localhost/svn/ShinyNewProduct/branches/1.0 \ http://localhost/svn/ShinyNewProduct/tags/1.0
Whether you copy trunk to branches to tags or trunk to tags to branches shouldn't really matter, as long as you don't commit anything in the mean time. Note that committing changes to a tag is a violation of best practices. Anyone should be able to count on the fact that tags/1.0 really contains the code as it was when version 1.0 was released, without any bug fixes or other changes. There are ways to actually prevent committing to an existing tag, but that's beyond the scope of this tutorial.
Now is a good time to change the setup.py file in branches and trunk to signal the new state of the software. After the first release, the setup.py file should contain what follows:
- In tags/1.0:
- version = 1.0
- In branches/1.0:
- version = 1.0dev
- In trunk:
- version = 1.1dev
After you commit changes to the branch or trunk you can increase the version in the setup.py file to signal the change. Note that we have given trunk a version number starting with 1.1. You do want to continue developing don't you?
Make a tar file for downloading
Now you can prepare a tar file that people can download from a website when they don't want to use subversion. Best is to make an export from the tag. An export instead of a checkout ensures that there are no subversion directories or old .pyc or backup files lying around. Double check to make sure the version number in version.txt is plainly 1.0.
svn export http://localhost/svn/ShinyNewProduct/tags/1.0 \ ShinyNewProduct tar czf ShinyNewProduct-1.0.tar.gz ShinyNewProduct
Okay, you now have a trunk, tags and branches with version numbers to match and you have a tar ball. You have taken a big step towards releasing your ShinyNewProduct. Actually, the most difficult part is finished now, so you can breathe and relax. Then again, you still need to tell your future users what your product does, where they can download it and how they can contact you to express their gratitude (or perhaps how to complain, but that's a corner case). Read on for more advice on that.
