通过持续集成来保持不断增长的多样化代码库


10

我需要有关连续集成设置的概念和设计的帮助。

我们当前的CI设置使用buildbot。当我开始设计它时,我继承了一个定制的CI构建器(不是严格地说,因为我一年前参与了它的设计),该构建器经过定制可在一夜之间一次运行整个构建。一段时间后,我们认为这还不够,并开始探索不同的CI框架,最终选择了buildbot。我过渡到buildbot的目标之一(除了享受所有额外的乐趣)是要克服我们定制的夜间构建器的某些不足之处。

幽默一下,让我解释一下我继承的东西。我公司的代码库是将近150个独特的c ++ Windows应用程序,每个应用程序都依赖于十几个内部库中的一个或多个(以及许多第三方库)。其中一些库是相互依赖的,并且具有依赖的应用程序(尽管它们彼此无关)必须使用该库的相同内部版本来构建。这些应用程序和库中的一半被认为是“旧版”且不可移植,必须使用IBM编译器的几种不同配置(我已经为其编写了独特的子类Compile)构建,而另一半则使用Visual Studio构建。ShellCommands,因为不支持VSS)。

我们最初的每晚构建器只是简单地收集了所有内容的来源,并按一定顺序构建了东西。没有办法只构建一个应用程序,选择版本或对事物进行分组。它将启动虚拟机来构建许多应用程序。它不是很健壮,也不是可分发的。它不是非常可扩展的。我希望能够克服buildbot中的所有这些限制。

我最初执行此操作的方式是为我们要构建的每个应用程序创建条目(它们全部包含150个),然后创建可以将各种应用程序构建为组的触发调度程序,然后将这些组包含在整个夜间构建调度程序下。它们可以在专用的从属服务器上运行(不再需要虚拟机),如果我愿意,我可以简单地添加新的从属服务器。现在,如果我们要按计划进行完整构建,只需单击一下即可,但是如果需要,我们也可以只构建一个应用程序。

但是,这种方法有四个缺点。一种是源代码树的复杂依赖关系网。为了简化配置维护,所有构建器都是从大型词典生成的。检索依赖关系的方式并非十分稳健(即,在我的构建目标字典中删除某些内容)。第二个原因是每个构建都有15到21个构建步骤,这很难在Web界面中浏览和查看,并且由于有大约150列,因此需要永久加载(从30秒到几分钟)。第三,我们不再能够自动发现构建目标(尽管,尽管我的一位同事为此而烦恼,但我最初并不认为这对我们有什么帮助)。最后,

现在,转向新开发,我们开始使用g ++和subversion(请注意,不要移植旧的存储库-只是为了新的东西)。另外,我们也开始进行更多的单元测试(“更多”可能会给出错误的图片……更像是任何东西),以及集成测试(使用python)。我很难弄清楚如何将它们适合我的现有配置。

那么,我在哪里从哲学上错了?我怎样才能最好地继续前进(使用buildbot-这是我有许可证可以解决的唯一难题),以便实际上可以维护我的配置?如何解决设计中的某些弱点?对于大型(可能是过度)复杂代码库的CI策略,真正起作用的是什么?

编辑:

我以为我解释了我的问题,但显然我还不够清楚。我不是在寻求有关更改CI平台的建议。它不会发生,答案表明那将不会被接受。我知道的是其他人如何使用CI管理复杂的代码库。我有十几种平方的不同产品,而且我的依赖项随风而散,它们都是不同的。这就是我想知道的处理方法。


我也想知道答案。我们的环境并不像您的环境那么复杂,但是我们已经有了依赖关系的依赖关系(在安装项目的情况下,它的依赖关系深达四层)。我不知道每个项目是否应该是CI项目,或者我是否应该只使用Visual Studio .sln文件来照顾它,这样我就不必为每个项目重新创建依赖项树(以及未来的项目)。
moswald 2011年

无法在本地计算机上构建将使CI服务器任务对于您的业​​务至关重要。您可能需要重新考虑。
托尔比约恩Ravn的安徒生

Answers:


3

尽管我没有遇到您所描述的那样糟糕的情况,但是我一直在维护具有数十个组件的CI配置,在这些组件之间存在一些“简单”依赖项。我希望我的方法可以给您一些继续进行的提示。这个问题肯定不仅与CI服务器的选择有关,而且与整个构建过程和项目结构有关。

我将问题分为两部分:Building和CI。

建造

对于“构建”,我指的是将现有源代码更改为最终工件的过程。我们公司主要在开发中使用Java,而我们使用的构建工具是Maven。由于您的项目性质,您可能无法使用它,但是Maven中有一些有价值的概念值得注意:

1)在Maven世界中,每个工件(库,真实程序等)都需要清楚地隔离和解耦。工件之间的依赖关系应该清楚。我应该强调,混乱的依赖关系,尤其是构建工件之间的循环依赖关系将使构建过程变得一团糟。

例如,在此之前,我看到了一些Java项目,尽管在整个构建过程之后,已经构建了多个JAR(您可以将其视为Java中的lib / dll),但实际上它们是相互依赖的。就像,A.jar在B.jar中使用东西,反之亦然。这种“模块化”是完全没有意义的。A.jar和B.jar始终需要一起部署和使用。言外之意是,以后如果您要将它们分成不同的项目(例如,在其他项目中重用),您将无法这样做,因为您无法确定首先构建哪个项目(A或B)。

是的,需要在您的软件设计中加以考虑,但我始终相信,与其花时间在一个凌乱的项目中制作复杂的构建工具/模型,不如花时间重新组织设计以使用简单的建筑模型。

2)依赖关系应该是声明性的。我之前看到过很多构建过程,其中包括项目本地所需的所有库。如果某些库实际上是您需要构建的其他工件,这将使构建过程非常麻烦。

3)用于工件的“集中式”存储,以获取依赖关系,或在工件编译后对其进行部署。整个办公室不需要“集中”(如果这样的话,那会很好),只需一个本地目录就可以了。

关于2和3的更多详细说明。仅举一个例子,我遇到了一个涉及3个独立项目的项目。每个项目都基于源代码,以及源代码目录中lib /目录下的libs构建。项目A将构建多个库,这些库又由项目B和C使用。存在很多缺点:构建过程复杂且难以自动化;源控件变得with肿,在不同项目中重复使用了不必要的重复JAR

在Maven的世界中,所要做的是,项目B和C在项目源中实际上并不包含A.jar(以及其他依赖项,例如其他第三方库)。它是声明性的。例如,在项目B的构建配置中,只需声明它需要:A.lib v1.0,xyz.lib v2.1等,然后构建脚本将从/A/1.0/A查找lib。 jar和/xyz/2.1/xyz.lib

对于非Maven的世界,此工件目录只需要是具有一致目录结构的一个或两个目录即可。您可以将所有第3方库放到共享位置,并让开发人员同步或复制到其本地计算机。在多年以前的C ++项目中,我正在做的工作是将lib和标头设置为$ {artifact_dir} / lib_name / ver,并将artifact_id声明为环境变量。

构建项目A时,它将在该artifact_dir中具有其结果的副本,因此,当我们构建项目B时,B可以自动获得A的结果,而无需手动复制。

4)非可变释放。一旦发布A.lib 1.0,就是这样,您不会指望A.lib 1.0的内容在1个月后发生变化,只是因为存在一些错误修复。在这种情况下,应为A.lib 1.1。不断变化的代码库的工件应考虑特殊的“版本”,在Maven中我们称其为快照。

非可变释放更多是一个道德问题。但是解决的方法很明确:当您有多个项目,并且使用相同的lib时,您就知道您使用的是哪个版本的lib,并且您将确保在不同项目中使用的相同版本的lib的确相同。 。我认为我们很多人都遇到了以下问题:为什么项目X和Y都使用lib A,但是生成结果却不同?(事实证明,在深入研究lib的内容或文件大小之后,X和Y使用的lib A实际上是不同的)。


所有这些确保您的项目可以独立进行构建,而没有很多手动技巧,例如先构建项目A,将A.lib复制到项目B,然后再构建项目B ...

例如,在进行了这样的练习之后,当您构建项目A时,它将尝试从集中式工件存储中获取依赖项。如果未找到某些依赖项(这是您公司的其他项目,例如项目B),则您需要做的是获取项目B的源代码,进行构建(成功后将其部署到集中存储中),以及然后再次构建项目A。


CI

有了简单的构建系统,明确的依赖关系,CI就会容易得多。我希望您的CI服务器满足以下要求:

1)监视源代码管理,仅在源代码发生更改时签出+构建

2)能够建立项目之间的依赖关系

有了对项目的明确依赖性,您只需要根据实际项目在CI中设置项目,然后根据项目的依赖性来设置CI项目依赖性。您的CI服务器应设置为在构建任何项目之前先构建依赖项目(当然,仅当项目源确实有更改时才进行构建)。

如果一切顺利,您应该拥有一个庞大,复杂但仍可管理的配置项(更重要的是,一个可管理的项目结构)


我喜欢这个答案的去向,但您能否在“建筑”部分中详细介绍?也就是说,举一些例子,更全面,详细地解释一些概念。
内特

嗯...喜欢哪一部分?我尝试编辑帖子以提供每个部分的更多细节。如果您能告诉我您认为需要详细说明的那部分会更好。顺便说一句,如果您也使用Java,请访问maven.apache.org。Maven可能不是最容易采用的方法,但是它迫使您使事情变得整洁有序。
阿德里安·舒姆

1

在类似情况下对我有效的是:

  • 通过将构建的某些部分分流到专用的构建应用中来进行应用级抽象(在我们的示例中,这些是从主构建中调用的PHP脚本)。这样可以将数十个构建步骤减少为一个构建步骤。
  • 通过制作从主构建脚本启动的子构建脚本来进行构建级抽象。不知道它是否与buildbot相关(没有该产品的经验)。

我建议您将构建本身视为软件开发项目。这意味着您需要对构建代码库进行模块化,并为其编写一些自动化测试(例如,构建一个已知的修订版本并检查其是否产生正确的结果)。


0

我会将Jenkins视为CI服务器,您可以在此处查看以下功能:

https://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins

为什么?它易于安装,具有出色的界面,易于配置和扩展,并且几乎所有功能都有很多现成的插件:

https://wiki.jenkins-ci.org/display/JENKINS/Plugins

试试看 :)


2
我觉得您已经阅读了我的问题的标题,但没有阅读正文……我不是在寻找产品建议。我选择了一个产品。我正在寻找如何组织复杂的CI设置。
内特

内特(Nate),我看了您所有的帖子,我认为您选择了错误的产品,这就是我建议詹金斯(Jenkins)的原因。我在工作中使用Jenkins进行C ++产品的各种测试(甚至是用多种语言编写的测试),并在多台计算机上进行集群测试,并且运行良好。管理和配置非常容易。真的,尝试一下:)
Patrizio Rullo 2011年


0

在此之前,我们现在使用ThoughtWorks的Go,我们使用CruiseControl.Net。考虑到我们有两支球队彼此相距世界一半,并且我们之间存在很大的时区差异,因此这很有用。

我们正在管理多个项目,并且大多数任务涉及全球各地的两个开发人员之间的重叠,因此我们必须牢记所有文件都不应破坏其他人的构建。

使用Go并成为Agile Process的顽固派,管理也变得更加容易,它在安装后给我们减轻了很多麻烦。测试也已与Go集成在一起。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.