在连续集成中处理多个分支

我一直在处理公司规模化 CI 的问题,同时试图找出当涉及到 CI 和多个分支机构时应该采取的方法。在 stackoverflow 也有一个类似的问题,多特征分支与连续集成。我已经开始一个新的,因为我想得到更多的讨论,并提供一些分析的问题。

到目前为止,我发现有两个主要的方法,我可以采取(或者也许其他一些? ? ?)。

因此,如果我想为开发人员提供他们自己的定制分支 CI,我需要 Jenkins 的特殊工具(API 或 shell 脚本或其他东西?)处理缩放。或者我可以告诉他们更经常地合并到 DEV,并在定制分支上没有 CI 地生活。你会选择哪一个,还有其他选择吗?

27152 次浏览

I would set up separate jobs for each branch. I've done this before and it isn't hard to manage and set up if you've set up Hudson/Jenkins correctly. A quick way to create multiple jobs is to copy from an existing job that has similar requirements and modify them as needed. I'm not sure if you want to allow each developer to setup their own jobs for their own branches, but it isn't much work for one person (i.e. a build manager) to manage. Once the custom branches have been merged into stable branches, corresponding jobs can be removed when they are no longer necessary.

If you're worried about the load on the CI server, you could set up separate instances of the CI or even separate slaves to help balance the load across multiple servers. Make sure that the server you are running Hudson/Jenkins on is adequate. I've used Apache Tomcat and just had to ensure that it had enough memory and processing power to process the build queue.

It's important to be clear on what you want to achieve using CI and then figure out a way to implement it without much manual effort or duplication. There's nothing wrong with using other external tools or scripts that are executed by your CI server that help simplify your overall build management process.

I would choose dev+stable branches. And if you still want custom branches and afraid of the load, then why not move these custom ones to the cloud and let developers manage it themselves, e.g. http://cloudbees.com/dev.cb This is the company where Kohsuke is now. There is an Eclipse Tooling also, so if you are on Eclipse, you will have it tightly integrated right into dev env.

When you talk about scaling CI you're really talking about scaling the use of your CI server to handle all your feature branches along with your mainline. Initially this looks like a good approach as the developers in a branch get all the advantages of the automated testing that the CI jobs include. However, you run into problems managing the CI server jobs (like you have discovered) and more importantly, you aren't really doing CI. Yes, you are using a CI server, but you aren't continuously integrating the code from all of your developers.

Performing real CI means that all of your developers are committing regularly to the mainline. Easy to say, but the hard part is doing it without breaking your application. I highly recommend you look at Continuous Delivery, especially the Keeping Your Application Releasable section in Chapter 13: Managing Components and Dependencies. The main points are:

  • Hide new functionality until it's finished (A.K.A Feature Toggles).
  • Make all changes incrementally as a series of small changes, each of which is releasable.
  • Use branch by abstraction to make large-scale changes to the codebase.
  • Use components to decouple parts of your application that change at different rates.

They are pretty self explanatory except branch by abstraction. This is just a fancy term for:

  1. Create an abstraction over the part of the system that you need to change.
  2. Refactor the rest of the system to use the abstraction layer.
  3. Create a new implementation, which is not part of the production code path until complete.
  4. Update your abstraction layer to delegate to your new implementation.
  5. Remove the old implementation.
  6. Remove the abstraction layer if it is no longer appropriate.

The following paragraph from the Branches, Streams, and Continuous Integration section in Chapter 14: Advanced Version Control summarises the impacts.

The incremental approach certainly requires more discipline and care - and indeed more creativity - than creating a branch and diving gung-ho into re-architecting and developing new functionality. But it significantly reduces the risk of your changes breaking the application, and will save your and your team a great deal of time merging, fixing breakages, and getting your application into a deployable state.

It takes quite a mind shift to give up feature branches and you will always get resistance. In my experience this resistance is based on developers not feeling safe committing code the the mainline and this is a reasonable concern. This in turn usually stems from a lack of knowledge, confidence or experience with the techniques listed above and possibly with the lack of confidence with your automated tests. The former can be solved with training and developer support. The latter is a far more difficult problem to deal with, however branching doesn't provide any extra real safety, it just defers the problem until the developers feel confident enough with their code.

Actually what is really problematic is build isolation with feature branches. In our company we have a set of separate maven projects all be part of a larger distribution. These projects are maintained by different teams but for each distribution all projects need to be released. A featurebranch may now overlap from one project to another and thats when build isolation gets painfully. There are several solutions we've tried:

  • create separate snapshot repositories in nexus for each feature branch
  • share local repositories on dedicated slaves
  • use the repository-server-plugin with upstream repositories
  • build all within one job with one private repository

As a matter of fact, the last solution is the most promising. All other solutions lack in one or another way. Together with the job-dsl plugin it is easy to setup a new feature branch. simply copy and paste the groovy script, adapt branches and let the seed job create the new jobs. Make sure that the seed job removes nonmanaged jobs. Then you can easily scale with feature branches over different maven projects.

But as tom said well above, it would be nicer to overcome the necessity of feature branches and teach devs to integrate cleanly, but that is a longer process and the outcome is not clear with many legacy system parts you won't touch any more.

my 2 cents