构建服务器:管理第三方组件的最佳实践?

时间:2009-06-19 09:10:24

标签: delphi build-automation project-organization

我正在维护一个非常大的遗留应用程序。源树真是一团糟。 我正在尝试设置构建服务器。

在源代码树上,我有第三方组件包含源代码(也在项目的include路径中)。这些组件也安装在IDE中。

我的问题是: 如何管理这些组件?

我想以这种方式管理:

  • 在构建服务器上安装IDE
  • 安装所有第三方组件
  • 从项目源代码树中删除组件源(并将它们保存在每个压缩的专用文件夹上的项目根目录中)
  • 每次我们需要定制(或调试)第三方组件时,我们重新构建软件包并将其重新安装在构建服务器的IDE中(以及每个开发人员工作站上)

在IDE中安装组件与包含路径中的源有什么区别?链接器如何处理这种情况?

4 个答案:

答案 0 :(得分:22)

我们使用简单的命令文件设置了每日构建。

  1. 每个项目(.dpr)都有一个关联的Build.cmd文件。
  2. 从我们的主BuildServerRun.cmd文件中调用所有Build.cmd文件。
  3. BuildServerRun.cmd文件负责

    1. 删除构建服务器上的整个源树。
    2. 从我们的源代码管理存储库获取最新版本。
    3. 调用每个Build.cmd并将输出通道传输到文件。
    4. 将结果邮寄给所有开发者。
    5. 外部组件的所有路径都在dcc32.cfg文件

      中配置
      ..    
      -u"c:\Program files\Developer Express Inc\ExpressInplaceEditors\Delphi 5\Lib"
      -u"c:\Program files\Developer Express Inc\ExpressQuantumGrid\Delphi 5\Lib"
      ..
      -r"c:\Program Files\Borland\Delphi5\Lib"
      -r"C:\Program Files\jvcl\jvcl\resources"
      ..
      -i"C:\Program Files\jvcl\jvcl\run"
      -i"C:\Program Files\jvcl\jcl\source"
      

      Build.cmd。

      的示例

      注意:我们有一个策略要编译到bin \ dcu,exe到bin,因此是-N,-E指令。

      @echo on
      dcc32speed -B -Q -W -H -Nbin\dcu -Ebin BpABA.dpr
      @echo off
      

      剪切的BuildServerRun.cmd

      的示例
      SET %Drive%=E:
      
      :BuildServer
      REM *************************************************
      REM     Clear files
      REM *************************************************
      ECHO. > "%Temp%\BuildLieven.txt"
      ECHO. > "%Temp%\TestRunLieven.txt"
      
      REM *************************************************
      REM     Set start time
      REM *************************************************
      echo | TIME | FIND "Huidige tijd" > "%Temp%\ResultLieven.txt"
      
      REM *************************************************
      REM     Get latest versions
      REM *************************************************
      IF %LatestVersion%==1 CALL %Drive%\buildserver\latestversion.cmd
      ECHO "Latest versions opgehaald" >> "%Temp%\ResultLieven.txt"
      
      REM *************************************************
      REM     Build projects
      REM *************************************************
      CD %Drive%\Projects\
      
      ECHO ***************************************************************** >> "%Temp%\BuildLieven.txt"
      ECHO BpABA >> "%Temp%\BuildLieven.txt"
      ECHO ***************************************************************** >> "%Temp%\BuildLieven.txt"
      CD %Drive%\Projects\BPABA\production
      ECHO Building BPABA\production
      CALL Build.cmd >> "%Temp%\BuildLieven.txt"
      CD %Drive%\Projects\BPABA\test
      ECHO Building BPABA\test
      CALL Build.cmd >> "%Temp%\BuildLieven.txt"
      CD %Drive%\Projects\BPABA\test\dunit
      ECHO Building BPABA\test\dunit
      CALL Build.cmd >> "%Temp%\BuildLieven.txt"
      ECHO BPABATests >> "%Temp%\TestRunLieven.txt"
      ECHO Running BPABATests
      CALL bin\BPABATests >> "%Temp%\TestRunLieven.txt"
      CD %Drive%\Projects
      ECHO. >> "%Temp%\BuildLieven.txt"
      ECHO. >> "%Temp%\BuildLieven.txt"
      ECHO. >> "%Temp%\BuildLieven.txt"
      
      REM *****************************************************************
      REM     Gather (Fatal)Errors/Hints/Warnings & Failures
      REM *****************************************************************
      ECHO ***************************************************************** >> "%Temp%\ResultLieven.txt"
      ECHO (Fatal)Errors/Hints/Warnings en Failures >> "%Temp%\ResultLieven.txt"
      ECHO ***************************************************************** >> "%Temp%\ResultLieven.txt"
      ECHO Fatal errors during build >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND /c "Fatal:" >> "%Temp%\ResultLieven.txt"
      
      
      ECHO Errors during build >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND /c "Error:" >> "%Temp%\ResultLieven.txt"
      
      ECHO Warnings during build >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND /c "Warning:" >> "%Temp%\ResultLieven.txt"
      
      ECHO Hints during build >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND /c "Hint:" >> "%Temp%\ResultLieven.txt"
      
      ECHO Failures during test >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\TestRunLieven.txt" | FIND /c "Failures:" >> "%Temp%\ResultLieven.txt"
      ECHO. >> "%Temp%\ResultLieven.txt"
      
      ECHO ***************************************************************** >> "%Temp%\ResultLieven.txt"
      ECHO Controle #Projecten = #Compiles >> "%Temp%\ResultLieven.txt"
      ECHO ***************************************************************** >> "%Temp%\ResultLieven.txt"
      ECHO #Projecten >> "%Temp%\ResultLieven.txt"
      TYPE "%Drive%\buildserver\buildserverrun.cmd" | FIND /i "cmd >> " | FIND /i "Lieven" | FIND /i /v /c "FIND /i /v /c" >> "%Temp%\ResultLieven.txt"
      ECHO #Compiles >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\buildLieven.txt" | FIND /i /c "dcc32" >> "%Temp%\ResultLieven.txt"
      ECHO #Tests expected to run >> "%Temp%\ResultLieven.txt"
      TYPE "%Drive%\buildserver\buildserverrun.cmd" | FIND /i "TestRunLieven" | FIND /i "CALL" | FIND /i /v /c "FIND /i /v /c" >> "%Temp%\ResultLieven.txt"
      ECHO #Tests actually run >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\TestRunLieven.txt" | FIND /i /c "DUnit / Testing" >> "%Temp%\ResultLieven.txt"
      ECHO. >> "%Temp%\ResultLieven.txt"
      ECHO. >> "%Temp%\ResultLieven.txt"
      
      ECHO ***************************************************************** >> "%Temp%\ResultLieven.txt"
      ECHO Detail (Fatal)Errors/Hints/Warnings en Failures >> "%Temp%\ResultLieven.txt"
      ECHO ***************************************************************** >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND "Fatal:" >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND "Error:" >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND "Warning:" >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\BuildLieven.txt" | FIND "Hint:" >> "%Temp%\ResultLieven.txt"
      TYPE "%Temp%\TestRunLieven.txt" | FIND "Failures:" >> "%Temp%\ResultLieven.txt"
      
      REM *************************************************
      REM     Set stop time
      REM *************************************************
      ECHO | TIME | FIND "Huidige tijd" >> "%Temp%\ResultLieven.txt"
      
      REM *************************************************
      REM     Send results
      REM *************************************************
      CALL %drive%\buildserver\Blat.cmd
      

答案 1 :(得分:3)

我的答案比Lieven的答案更为通用,后者是特定于Delphi的。我在问题发生后不久写了这篇文章,但在提交之前就找了一位同事;)

我拒绝在我们的主Windows构建代理上安装任何IDE。对我来说听起来像是一场噩梦。 MSBuild引擎可以很好地处理所有构建方案,除了.NET之外,您只需要安装Windows SDK。或者你可以使用NAnt甚至CMake,无论如何。只是不要安装IDE。它在构建服务器上并不好玩。

现在你已将其标记为Delphi。我不知道它在那里有多好,但正如Lieven写的那样,Delphi附带了一个命令行编译器。我对第三方组件的工作原理没有任何经验,但我认为Delphi在最新版本中支持MSBuild。

我也不确定将thiry-party组件包含到版本控制中是否是一件好事,因为它占用了空间 - 尽管你也可以将它们放在其他地方并将它们包含在外部,这使得它更小,但是同时也存在一个问题,即升级一个应用程序的组件会为所有应用程序升级它们 - 所以你最好进行良好的集成测试。但无论如何,这就是构建服务器的重点。

除此之外,签出并拥有构建应用程序所需的所有组件总是一件好事。如果组件良好,则无需将组件安装到IDE中。根据它们的组件,在许多情况下,您甚至不需要在开发人员计算机上安装它们。例如,当您添加对它们的引用时,设计器中可以使用许多.NET组件。许可通常不过​​是“将许可证文件放入同一目录”。好吧,至少应该如此。如果今天它不是Delphi的工作方式,这可能是Delphi即将推出的原因之一。除了Borland / Inprise / DevCo / Codegear / Embarcadero之外的麻烦。

答案 2 :(得分:1)

这里类似的情况,幸运的是它并没有从一个大混乱开始。确实,真正的问题在于IDE配置,如果您查看旧版本,则需要指向第三方组件的正确版本。我听说过的唯一解决方案是针对不同的产品发布配置使用不同的注册表分支。

组件保存在单独的目录结构中,并尽可能在目录名称中使用版本号。这样可以更容易地检查旧版本并使构建脚本指向正确的版本。

我们多年来一直使用Apache Ant作为主要构建工具,它确实可以满足我们所需的一切,包括单元测试调用和Innosetup脚本生成。

只有在使用BPL发送可执行文件时才需要编译软件包,否则在构建服务器上不需要。

在构建服务器上也不需要在IDE中安装组件。

答案 3 :(得分:0)

您可以使用Owly CI工具。

通过定义清单文件,它可以轻松地构建项目。 它还允许句柄依赖 - 您可以在owlyci包中包装第三方组件,并将它们标记为主项目的依赖项。

有一个example,如何在Jenkins CI系统中使用它。