views:

157

answers:

1

We have a suite of related products written in VB6, with some C# and VB.NET projects, and all the source is kept in a single Subversion repository.

We haven't been using branches in Subversion (although we do tag releases now), and simply do all development in trunk, creating new releases when the trunk is stable enough. This causes no end of grief when we release a new version, issues are found with it, and we have already begun working on new features or major changes to the trunk. In the past, we would address this in one of two ways, depending on the severity of the issues and how stable we thought the trunk was:

  1. Hurry to stabilize the trunk, fix the issues, and then release a maintenance update based on the HEAD revision, but this had the side effect of releases that fixed the bugs but introduced new issues because of half-finished features or bugfixes that were in trunk.

  2. Make customers wait until the next official release, which is usually a few months.

We want to change our policies to better deal with this situation. I was considering creating a "maintenance branch" in Subversion whenever I tag an official release. Then, new development would continue in trunk, and I can periodically merge specific fixes from trunk into the maintenance branch, and create a maintenance release when enough fixes are accumulated, while we continue to work on the next major update in parallel. I know we could also have a more stable trunk and create a branch for new updates instead, but keeping current development in trunk seems simpler to me.

The major problem is that while we can easily branch the source code from a release tag and recompile it to get the binaries for that release, I'm not sure how to handle the setup and installer projects. We use QSetup to create all of our setup programs, and right now when we need to modify a setup project, we just edit the project file in-place (all the setup projects and any dependencies that we don't compile ourselves are stored on a separate server, and we make sure to always compile the setup projects on that machine only). However, since we may add or remove files to the setup as our code changes, there is no guarantee that today's setup projects will work with yesterday's source code.

I was going to put all the QSetup projects in Subversion to deal with this, but I see some problems with this approach.

I want the creation of setup programs to be as automated as possible, and at the very least, I want a separate build machine where I can build the release that I want (grabbing the code from Subversion first), grab the setup project for that release from Subversion, recompile the setup, and then copy the setup to another place on the network for QA testing and eventual release to customers.

However, when someone needs to change a setup project (to add a new dependency that trunk now requires or to make other changes), there is a problem. If they treat it like a source file and check it out on their own machine to edit it, they won't be able to add files to the project unless they first copy the files they need to add to the build machine (so they are available to other developers), then copy all the other dependencies from the build machine to their machine, making sure to match the folder structure exactly. The issue here is that QSetup uses absolute paths for any files added to a setup project. However, this means installing a bunch of setup dependencies onto development machines, which seems messy (and which could destabilize the development environment if someone accidentally runs the setup project on their machine).

Also, how do we manage third-party dependencies? For example, if the current maintenance branch used MSXML 3.0 and the trunk now requires MSXML 4.0, we can't go back and create a maintenance release if we have already replaced the MSXML library on the build machine with the latest version (assuming both versions have the same filename). The only solution I can think is to either put all the third-party dependencies in Subversion along with the source code, or to make sure we put different library versions in separate folders (i.e. C:\Setup\Dependencies\MSXML\v3.0 and C:\Setup\Dependencies\MSXML\v4.0). Is one way "better" or more common than the other?

Are there any best practices for dealing with this situation? Basically, if we release v2.0 of our software, we want to be able to release v2.0.1, v2.0.2, and v.2.0.3 while we work on v2.1, but the whole setup/installation project and setup dependency issue is making this more complicated than the typical "just create a branch in Subversion and recompile as needed" answer.

+2  A: 

To my understanding, the key is to get rid of absolute paths and "well-known" network locations. Don't have them. Ever.

Where I work, we keep all the setup files, projects, dependencies - ALL of it - in the very same code repository where the main code is. This way, when we create a branch, all the setup stuff gets branched along with it, and gets preserved in the exact same form as it was at the moment of branching.

The only problem that I see here is that, as you mentioned, QSetup uses absolute paths. While I find this completely ridiculous, I understand that you probably will not consider switching to something more professional (we use NSIS, by the way).

However, it seems to me that a relatively simple solution may be applied. I assume here that QSetup keeps its projects in some kind of text, human-understandable format (otherwise, it is just ridiculous beyond comprehension). As such, you can create a copy of your QSetup project file(s) and replace all your paths with relative ones, with some kind of a marker at the beginning, like so: %ROOT%\Dependencies\SomeDep.dll

Then you can have your build script run a simple utility just before calling QSetup, which will create the "real" project file by replacing %ROOT% with the appropriate path, where the repository happens to be checked out.

After implementing this, you may create a build on any machine - be it a designated build machine, or a development one, or something else.

Fyodor Soikin
I wish we were using something else, but QSetup does have its pros: it has nice GUI interface for creating custom actions, so no scripting is needed, and it's pretty easy to use in genereal. A fair amount of work went it into the different setup projects as well, which also makes switching more difficult. I won't rule out the possibly of switching though.
Mike Spross
As a matter of fact, QSetup does use a text format (it's a pretty weird format, but the paths are plain-text at least). I also thought of using a marker and just replacing it with the correct path before running QSetup. The only problem is that using a marker makes it difficult to edit the project in the QSetup editor, because new files that are added would still be added with the full path. We can edit the paths in the GUI editor to include the marker after a file is added, it's just annoying to have to remember the extra step.
Mike Spross
On the other hand, the marker is a good check. If someone tries to compile the project in QSetup, they will get errors because of the bogus path. That will remind them to use the build script instead. Also, a marker would be a good way to insert the correct version numbers into the setup. Now I just have to find all the dependencies on the build machine and copy them into Subversion.
Mike Spross
Which would be a very useful exercise anyway. My experience shows that when you have specific locations and "well-known" paths, they always get cluttered, and then you can't do a cleanup, because who knows where this stuff is used. :-) Good luck with that.
Fyodor Soikin
if you make your Marker tool to do the replace/remove etc you could just run it over your file before you edit with QSetup, and then after you complete your edits you run it again to remove them and re-insert the markers.
Paul Farry
I think I will do something similar to this. It turns out QSetup does understand relative paths, it just doesn't generate relatives paths when you add new file to a setup project. You have to manually edit the file path after adding it. Using parent directory syntax seems to work OK (".\SomeFolder\SomeFile"). For the version numbers, I replaced all hard-coded version numbers with `{VERSION}` in the QSetup file (we put the version number in the setup EXE name and a few other places) and wrote a simple VBScript that preprocesses the file before it is built by the build server.
Mike Spross
That way in Subversion the setup project files are consistent and always have `{VERSION}` markers in them, and the build server only edits its working copy (which it doesn't commit back to Subversion). This way there aren't a bunch of extra commits in Subversion everytime the setup file version number is replaced by the script.
Mike Spross