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

发布于 2024-07-25 13:17:11 字数 385 浏览 9 评论 0原文

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

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

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

我想这样管理:

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

将组件安装在 IDE 中与将源代码安装在包括路径? 链接器如何处理这种情况?

I'm maintaining a quite large legacy application. The source tree is a real mess.
I'm trying to set up a build server.

On the source tree, I've third party component with sources (also in the project's include path). These components are also installed within the IDE.

My question is :
How to manage those components ?

I thought to manage this way:

  • Install the IDE on the build server
  • Install all the third party component
  • Remove the component sources from the project sources tree (and keep them on the project root on a dedicated folder each zipped)
  • Each time we need to customize (or debug) a third party component we re-build the package and re-install it in the IDE of the build server (and on each developers workstation)

What's the difference between having the components installed in the IDE and having the sources in the include path ? How the linker handle that case ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤寂小茶 2024-08-01 13:17:11

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

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

BuildServerRun.cmd 文件负责

  1. 删除构建服务器上的整个源代码树。
  2. 从我们的源代码控制存储库获取最新版本。
  3. 调用每个 Build.cmd 并将输出通过管道传输到文件。
  4. 将结果邮寄给所有开发人员。

中配置

..    
-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"

外部组件的所有路径均在 dcc32.cfg 文件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

We have set up our daily builds using simple command files.

  1. Each project (.dpr) has an associated Build.cmd file.
  2. All Build.cmd files are called from our main BuildServerRun.cmd file.

The BuildServerRun.cmd file takes care of

  1. Deleting the entire source tree on the buildserver.
  2. Getting a latest version from our source control repository.
  3. Call each Build.cmd and pipe the output to a file.
  4. Mail the results to all developers.

All paths to external components are configured in the dcc32.cfg file

..    
-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"

Example of a Build.cmd.

Note: we have a policy to compile to bin\dcu, exe to bin, hence the -N, -E directives.

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

Example of snipped 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
给不了的爱 2024-08-01 13:17:11

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

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

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

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

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

My answer is more general than Lieven's answer, which is Delphi-specific. I wrote this one shortly after the question, but went to a co-worker before submitting ;)

I refuse to install any IDE on our main Windows build agent. Sounds like a nightmare to me. The MSBuild engine handles all build scenarios well, and other than .NET, you just need the Windows SDK installed. Or you could use NAnt and even CMake, whatever. Just don't install IDEs. It's not fun on build servers.

Now you have tagged this as Delphi. I don't know how good it works there, but as Lieven wrote, Delphi comes with a command line compiler. I just don't have any experience how it works with third-party compnents, but I think Delphi supports MSBuild in the latest version.

I'm also unsure whether including thiry-party components into version control is a good thing, because of the space it takes - though you can also put them somewhere else and include them as external, which makes it much smaller, but also imposes the problem that upgrading the components for one app will upgrade them for all - so you better have good integration tests. But that is the point of a build server anyway.

Apart from that, it is always a good thing to check-out and have all components required to build the application available. You don't need to install components into an IDE if they were made well. Depending on what components they are, in many cases you don't even need to install them on developer machines. Many .NET components, for example, are available in the designer when you add a reference to them. And licensing is typically no more than "put the license file into the same directory". Well, that's how it should be, at least. If that's not how it works in Delphi today, that's likely one of the reasons Delphi is on its way out. Other than the Borland/Inprise/DevCo/Codegear/Embarcadero hassle.

星光不落少年眉 2024-08-01 13:17:11

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

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

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

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

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

Similar situation here, fortunately it did not start with a big mess. It is true that the real problem lies in the IDE configuration, which needs to point to the correct versions of the third party components if you check out an older version. The only solution I have heard of is the use of different registry branches for the different product release configurations.

The components are kept in a separate directory structure, and use version numbers in the directory names when possible. This makes it easier to check out old versions and have the build scripts point to the correct version.

We use Apache Ant as the main build tool for years now and it really does everything we need, including unit test invocation and Innosetup script generation.

Compilation of packages is only necessary you ship the executable with BPLs, otherwise it is not necessary on a build server.

Installing the components in the IDE is also not necessary on the build server.

夏了南城 2024-08-01 13:17:11

您可以使用Owly CI工具。

它允许通过定义清单文件以简单的方式构建项目。
它还允许处理依赖项 - 您可以将第 3 方组件包装在 owlyci 包中并将它们标记为主项目的依赖项。

有一个 示例,介绍如何将其与 Jenkins CI 系统一起使用。

You can use Owly CI tool.

It allow build projects in easy way by defining manifest file.
It also allows handle dependencies - you can wrap 3rd party components in owlyci packages and mark them as dependencies to the main project.

There is an example, how to use it with Jenkins CI system.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文