3
votes

I know this has been asked already, but we would really like to reject any attempt to commit files which would break a project in trunk. The decision to reject the committed files is based on the result of the building process of the project the files being committed belong to. I know that during the pre-commit phase the repository cannot be accessed concurrently, but this is not a problem for us since our builds are really fast and we can tolerate any delay involved.

Are there any tools to achieve what we want? Note that it will be necessary to recompile the whole project unit, not just the single files being committed.

If that cannot be done in any reasonable way, would it be possible to do the build the code during post-commit followed by an immediate rollback in case of failures on the building step? Can Hudson or other tools be configured to do what we want?

3
See also the discussion on SVN Usersalroc
You should push to a branch that's allowed to fail, and only merge from a branch if it's build-green (and usually test-green)Bartek Banachewicz

3 Answers

9
votes

Even if your build is fast. Let's say you can build the entire project in 90 seconds. Do you want people to wait 90 seconds every time they commit their code? What may happen is that people will simply do less commits, make bigger changes, and cause more errors.

First realize that committing a bad revision is not the end of the world. If you catch the problem early on, you can easily revert the change. The key here is early detection.

If you don't already have one, get a Continuous Integration system like Jenkins. Whenever someone commits a change in the code, Jenkins will do a build. If the builds are as fast as you claim, you will be notified in a couple of minutes when a change breaks the build. You can even have Jenkins revert the change if you so desire. Our philosophy is that the developer has 10 minutes to fix the problem, or revert their change. Then, we put them in stockades and pelt them with rotten tomatoes. (Actually, HR won't let us do that.)

Second, setup easy to follow standards that allow developers to make sure that their changes will work. We have a few basic ones:

  • We have a set of basic tools defined that all developers should have (Java, Ant, Subversion).
  • Outside of those three basic tools, all other tools and needed parts are placed inside the working directory and checked into Subversion.
  • No special environmental setup should be needed. Builds don't need to be configured, etc.
  • When a build is done, all built objects are done in the working directory.

This makes it easy for me to setup builds on our Jenkins server. And, more importantly, it makes it easy for developers to use the same build system Jenkins will use for the builds. If they can build it, Jenkins can build it.

Next, you have to change your development culture. Breaking a build is bad. Once that is done, Jenkins will publicly shame any developer who broke the build. One shop I saw had traffic lights setup. If a Jenkins build broke, those lights turned red. It's a big deal when that happens. The managers come out and want to know what's going on. Those lights never turned red when I was there.

Of course, being able to run a build is the very, very first step in software. It is a tiny baby step -- maybe even a crawl. No, not even that, it's the version of a six month old baby's first creep. If broken builds are a major concern at your place, you have very serious problems.

The next step beyond making sure everything compiles is making sure the code follows coding standard and the code isn't doing something that could be bad. In the Java world, it's running Checkstyle, Findbugs, and PMD against the code. Jenkins allows me to post nice charts showing me the results of these programs. We also gather all compile warnings and JavaDoc errors and graph those. We can even setup Jenkins to fail the build if there are too many warnings from any of these processes. Your code may compile, but the build fails because of bad technique.

Next is unit testing. In the Java world, it's JUnit and again Jenkins displays the results. We fail builds if any JUnit test fails. It doesn't do much good having a good build if your basic interface is bad.

Then, there's code coverage. How much of our code is being unit tested. We use JaCoCo for that. We don't fail builds for low code coverage, but we do put pressure on our developers to improve code coverage. Finally, we can do other testing. We deploy, and run automated functional and system tests.

Every change a developer does gets blasted all the way to Unit testing. It's one of the things I really like about Java and where I think Java development is way ahead of the curve. A typical Java build can be done in minutes. It's rare where we can't do a build, and run all unit tests with in 10 minutes. Any problems are caught early and fixed early on. And, all problems are on public display in Jenkins. We see who broke the build or caused a unit test to fail. We see who had compiler warnings they need to fix, or did some bad coding practice.

And because I give the developers the same set of tools that Jenkins uses for its builds, they can easily see what Jenkins will see. They can run the unit tests and the code tests too. There's no reason they commit code which causes more problems than it solves.

This is where you make great strides: Improving the development culture to care about what they're doing and shining a bright light on bad practices.

Putting obstacles in front of development -- like making developers wait 90 seconds after each commit to make sure their changes build -- builds resentment and usually backfires. You're no longer part of the team, but the build cop who treats everyone as a potential suspect. Instead, work with developers and convince them that what you want is to their benefit. Once they see that, they'll work with you and your whole development cycle runs much smoother.

0
votes

I know some CI tools are capable to do a "Pre-commit CI", so that changeset is first sent to the CI server to build, once it can be built successfully, it is committed to SVN then.

I have not tried on such feature personally but I believe the workflow may need to be changed slightly (Instead of committing directly, changes are sent to CI for pre-commit build)

QuickBuild: Proof-Build

Teamcity: Pre-tested commit

0
votes

In most cases you commit to a branch, it gets built, and if successful, the branch code is merged to a trunk. This fits better with most SCM systems that do not have explicit support for what you're asking for - considering the scm will send only changed files, and you need to checkout a full list for the build server to work (you don't really want to compile based on what files were left around from the previous build now do you).

SVN can happily do this in the pre-commit hook, I use a perl script in this hook to check for acceptable checkin comments and reject dodgy file types that might be added to the repo, so there's no reason why you cannot simply run a script that checksout the current branch, then copies the committing files over the top of them, builds, then checks the build log. To fail the pre-commit, just return 1 from the script (return 0 to pass it).

Its difficult to say exactly what you need as I don't know what or how you're performing your builds, but your script needs to be pretty much the same as any pre-commit hook script. SVN comes with a couple of samples and you can see several more on the internet.