Сервер сборки: лучшие практики управления сторонними компонентами?

Я поддерживаю довольно большое унаследованное приложение. Исходное дерево - настоящий беспорядок. Я пытаюсь настроить сервер сборки.

В исходном дереве у меня есть сторонний компонент с источниками (также в проекте include path). Эти компоненты также устанавливаются в среде IDE.

Мой вопрос: Как управлять этими компонентами?

Я решил управлять этим путем:

  • Установить IDE на сервере сборки
  • Установить все сторонние компоненты
  • Удалите источники компонентов из дерева источников проекта (и сохраните их в корне проекта в отдельной папке, каждый из которых застегнут)
  • Каждый раз, когда нам нужно настроить (или отлаживать) сторонний компонент, мы заново создадим пакет и переустановим его в среде IDE сервера сборки (и на каждой рабочей станции разработчиков).

В чем разница между наличием компонентов, установленных в среде IDE, и наличием источников в пути включения? Как компоновщик обрабатывает этот случай?

Ответ 1

Мы создали наши ежедневные сборки, используя простые командные файлы.

  • Каждый проект (.dpr) имеет связанный с ним файл Build.cmd.
  • Все файлы Build.cmd вызываются из нашего основного файла BuildServerRun.cmd.

Файл BuildServerRun.cmd заботится о

  • Удаление всего исходного дерева на сервере сборки.
  • Получение последней версии из нашего исходного хранилища.
  • Вызвать каждый Build.cmd и передать вывод в файл.
  • Отправьте результаты всем разработчикам.

Все пути к внешним компонентам настраиваются в файле 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"

Пример сборки .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

Ответ 2

Мой ответ более общий, чем ответ Ливена, который является специфичным для Delphi. Я написал это вскоре после вопроса, но пошел к сотруднику, прежде чем отправлять;)

Я отказываюсь устанавливать любую IDE в нашем основном агенте Windows. Мне кажется кошмаром. Механизм MSBuild отлично справляется со всеми сценариями сборки, а не .NET, вам просто нужен Windows SDK. Или вы можете использовать NAnt и даже CMake, что угодно. Просто не устанавливайте IDE. Это не весело на серверах сборки.

Теперь вы отметили это как Delphi. Я не знаю, как хорошо это работает, но, как писал Ливен, Delphi поставляется с компилятором командной строки. У меня просто нет опыта работы с сторонними компиляторами, но я думаю, что Delphi поддерживает MSBuild в последней версии.

Я также не уверен, что включение сторонних компонентов в управление версиями - это хорошая вещь из-за пространства, которое требуется - хотя вы можете также разместить их в другом месте и включить их как внешние, что делает его намного меньше, но также накладывает проблему на то, что обновление компонентов для одного приложения будет обновлять их для всех - так что вам лучше иметь хорошие интеграционные тесты. Но в любом случае это точка сервера сборки.

Кроме того, всегда хорошо проверять и иметь все компоненты, необходимые для создания приложения. Вам не нужно устанавливать компоненты в среду IDE, если они сделаны хорошо. В зависимости от того, какие компоненты они есть, во многих случаях вам даже не нужно устанавливать их на машинах разработчика. Многие компоненты .NET, например, доступны в дизайнере, когда вы добавляете ссылку на них. И лицензирование обычно не более чем "помещает файл лицензии в тот же каталог". Ну, как это должно быть, по крайней мере. Если это не так, как это работает в Delphi сегодня, вероятно, одна из причин, по которой Delphi выходит. За исключением проблем с Borland/Inprise/DevCo/Codegear/Embarcadero.

Ответ 3

Аналогичная ситуация здесь, к счастью, не началась с большого беспорядка. Это правда, что настоящая проблема заключается в конфигурации IDE, которая должна указывать на правильные версии сторонних компонентов, если вы посмотрите более старую версию. Единственное решение, о котором я слышал, это использование разных разделов реестра для различных конфигураций выпуска продукта.

Компоненты хранятся в отдельной структуре каталогов и, если возможно, используют номера версий в именах каталогов. Это упрощает проверку старых версий, и сценарии сборки указывают на правильную версию.

Мы используем Apache Ant в качестве основного инструмента построения уже много лет, и он действительно делает все, что нам нужно, включая unit test invocation и генерацию Innosetup script.

Компиляция пакетов необходима только для того, чтобы отправить исполняемый файл с помощью BPL, иначе он не нужен на сервере сборки.

Установка компонентов в среде IDE также не требуется на сервере сборки.

Ответ 4

Вы можете использовать инструмент Owly CI.

Это позволяет легко строить проекты, определяя файл манифеста. Он также позволяет обрабатывать зависимости - вы можете обернуть сторонние компоненты в owlyci-пакеты и пометить их как зависимости от основного проекта.

Существует пример, как использовать его с системой Jenkins CI.