Каков наилучший способ заставить TFS выводить каждый проект в отдельный каталог?

Я помещаю большую кодовую базу в Team Foundation Server. Мне бы хотелось, чтобы процесс сборки создавал готовые к развертыванию сборки наших проектов.

Обычный способ, которым мы это делаем, - это чтобы выходные данные каждого проекта находились в отдельной папке. Так, например, мы получаем что-то вроде

C:\project1\
            assembly1.dll
            assembly2.dll
            project1.exe
            project1.exe.config
C:\project2\
            assembly2.dll
            assembly3.dll
            project2.exe
            project2.exe.config
C:\project3\
            assembly1.dll
            assembly3.dll
            project3.exe
            project3.exe.config

Какой способ нам нравится.

Тем не менее, TFS, похоже, хочет поместить все в один каталог.

C:\output\
          assembly1.dll
          assembly2.dll
          assembly3.dll
          project1.exe
          project1.exe.config
          project2.exe
          project2.exe.config
          project3.exe
          project3.exe.config

что, хотя и экономит некоторое количество дискового пространства (сборки присутствуют только по одному разу), не соответствует нашим требованиям.

Как лучше всего указать, куда TFS/MSBuild должен помещать выходные файлы? Нужно ли редактировать файлы sln/csproj по отдельности, чтобы добиться этого, или я могу сделать это в файле TFSBuild.proj? (т.е. в файле, специфичном для MSBuild)

11 ответов

Решение

Я только что опубликовал другой метод здесь:

http://mikehadlow.blogspot.com/2009/06/tfs-build-publishedwebsites-for-exe-and.html но если вы не можете перейти по ссылке, вот она в полном объеме:

Как правило, рекомендуется собирать весь код под контролем вашей команды в одном Uber-решении, как описано в этом документе "Шаблоны и практики", Руководство по разработке команды с TFS. Если вы затем сконфигурируете сервер сборки TFS для сборки этого решения, то по умолчанию будет размещаться вывод сборки в одну папку "Release".

Любые проекты веб-приложений в вашем решении также будут выводиться в папку с именем _PublishedWebsites\. Это очень хорошо, потому что это означает, что вы можете просто Robocopy развернуть веб-приложение.

К сожалению, нет аналогичного поведения по умолчанию для других типов проектов, таких как WinForms, консоль или библиотека. Было бы очень хорошо, если бы мы могли иметь подпапку _PublishedApplications\ с выводом любого выбранного проекта (ов). К счастью, это не так сложно сделать.

Работа _PublishedWebsites довольно проста. Если вы посмотрите на файл проекта вашего веб-приложения, вы увидите импорт внизу:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />

На моем компьютере свойство MSBuildExtensionsPath оценивается как C:\Program Files\MSBuild. Если мы откроем файл Microsoft.WebApplication.targets, мы увидим, что это довольно простой файл MSBuild, который распознает, когда сборка не является сборкой на рабочем столе, т.е. TFS build и копирует вывод в:

$(OutDir)_PublishedWebsites\$(MSBuildProjectName)

Я просто скопировал файл Micrsoft.WebApplication.targets, поместил его под контроль исходного кода с относительным путем к файлам моего проекта и изменил _PublishedWebsites на _PublishedApplications и переименовал файл CI.exe.targets. Для каждого проекта, который я хочу вывести в _PublishedApplications, я просто добавил этот импорт внизу файла проекта:

<Import Project="<your relative path>\CI.exe.targets" />

Вы можете отредактировать CI.exe.targets (или как вы хотите это называть), чтобы сделать ставку. В моем случае единственное изменение - добавить пару строк для копирования файла App.config:

<Copy SourceFiles="$(OutDir)$(TargetFileName).config" DestinationFolder="$(WebProjectOutputDir)\bin" SkipUnchangedFiles="true" />

В Microsoft.WebApplication.targets есть много вещей, которые имеют отношение только к веб-приложениям и могут быть удалены для других типов проектов, но я оставлю это в качестве упражнения для читателя.

TFS 2012+

Мне нравится это решение...

Отредактируйте определение вашей сборки. В разделе "Процесс" установите MSBuild arguments в

/p:GenerateProjectSpecificOutputFolder=true

Как это:

По умолчанию каждый файл проекта (*.csproj, *.vbproj и т. Д.) Указывает выходной каталог по умолчанию (обычно это bin\Debug, bin\Release и т. Д.). Team Build на самом деле переопределяет это, так что вы не знаете, какие свойства задает разработчик в файле проекта, но и то, что Team Build может делать предположения о том, где расположены выходные данные.

Самый простой способ переопределить это поведение - установить для CustomizableOutDir значение true в группе элементов SolutionToBuild, как показано здесь:

<ItemGroup>
  <SolutionToBuild Include="$(BuildProjectFolderPath)\path\MySolution.sln" />
    <Properties>CustomizableOutDir=true</Properties>
  </SolutionToBuild>
</ItemGroup>

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

Этот метод определенно предпочтительнее, чем переопределение целей Core*, которые могут вызвать проблемы с обновлением.

Для каждого узла SolutionToBuild установите для свойства OutDir значение $(OutDir)\SubFolder.
Например:

  <ItemGroup>
   <SolutionToBuild Include="Project1.sln" >
    <Properties>OutDir=$(OutDir)\Project1\</Properties>      
   </SolutionToBuild>
   <SolutionToBuild Include="Project2.sln" >
    <Properties>OutDir=$(OutDir)\Project2\</Properties>      
   </SolutionToBuild>
   <SolutionToBuild Include="Project3.sln" >
    <Properties>OutDir=$(OutDir)\Project3\</Properties>      
   </SolutionToBuild>
  <ItemGroup>

(Это работает в TF2008, но не в TF2005.)

Я немного опоздал на вечеринку, отвечающую на этот вопрос, но есть очень простой способ реализовать ответ Майка Хэдлоу. Кто-то написал пакет nuget, который делает именно то, о чем говорит Майк. Вы можете найти его здесь: http://www.nuget.org/packages/PublishedApplications

Обновление для TFS 2010 (и предстоящий TFS 2012). Джейсон Стенгрум написал хороший пост в блоге, в котором рассказывается, как это сделать.

http://blog.codeassassin.com/2012/02/03/override-the-tfs-team-build-outdir-property/

(ссылка выше не работает... ссылка на кэшированную версию)

https://webcache.googleusercontent.com/search?q=cache:4rKu4oB3TwcJ:blog.stangroome.com/2012/02/03/override-the-tfs-team-build-outdir-property/+&cd=1&hl=en&ct=clnk&gl=ca

Переопределить свойство TFS Team Build OutDir

Обновление: с.NET 4.5 есть более простой способ.

Очень распространенная жалоба пользователей системы сборки Team Foundation Server на то, что она меняет структуру папок выходных данных проекта. По умолчанию Visual Studio помещает все файлы в соответствующую папку /bin/ или /bin// каждого проекта, но Team Build просто использует плоскую структуру папок, помещая все файлы в корневую папку или в подпапку //. папка со всеми результатами проекта, смешанными вместе.

Кроме того, поскольку Team Build достигает этого, устанавливая свойство OutDir с помощью командной строки MSBuild.exe в сочетании с приоритетом свойства MSBuild, это значение нельзя легко изменить из самого MSBuild, и популярное решение состоит в том, чтобы отредактировать файл Build Process Template *.xaml в используйте другое имя свойства. Но я предпочитаю не трогать рабочий процесс, если это абсолютно не необходимо

Вместо этого я использую функции решения до цели и встроенную задачу MSBuild v4, чтобы переопределить реализацию задачи MSBuild по умолчанию, используемую для построения отдельных проектов в решении. В моей альтернативной реализации я препятствую прохождению свойства OutDir и передаю свойство PreferredOutDir, которое отдельные проекты могут использовать при желании.

Первая часть, заменив свойство OutDir на свойство PreferredOutDir на уровне решения, достигается простым добавлением нового файла в каталог, в котором находится файл решения. Этот новый файл должен быть назван в соответствии с шаблоном "before..sln.targets" Например, для файла решения с именем "Foo.sln" новый файл будет "before.Foo.sln.targets". Содержимое этого нового файла должно выглядеть следующим образом. Убедитесь, что этот новый файл снова зарегистрирован в системе контроля версий.

Вторая часть, позволяющая каждому проекту управлять структурой выходной папки, это просто вопрос добавления строки в файл проекта *.csproj или *.vbproj (в зависимости от языка). Найдите первый элемент в файле проекта, для которого не указан атрибут Condition, и найдите соответствующий закрывающий тег для этого элемента. Сразу над закрывающим тегом добавьте строку примерно так:

<OutDir Condition=" '$(PreferredOutDir)' != '' ">$(PreferredOutDir)$(MSBuildProjectName)\</OutDir>

В этом примере проект будет выводиться в папку размещения Team Build в подпапке с именем, совпадающим с файлом проекта (без расширения.csproj). Вы можете выбрать другой шаблон. Кроме того, веб-проекты обычно создают свою собственную выходную папку в подпапке _PublishedWebSites в папке размещения Team Build, чтобы поддерживать это поведение, просто установите свойство OutDir равным свойству PreferredOutDir.

Вы можете проверить, сработали ли ваши изменения на вашем локальном компьютере, прежде чем регистрироваться, просто запустив MSBuild из командной строки и указав свойство OutDir, как это делает Team Build, например:

msbuild Foo.sln /p:OutDir=c:\TestDropFolder\

Для тех, кому интересно, как это работает с TFS 2010, в этом посте есть несколько ответов, один из которых мне очень помог.

Вы можете иметь один buildscript на проект, который будет делать то, что вы хотите. Просто создайте новый файл TFSBuild, добавьте проекты, которые вы хотите построить, в группу элементов (в том порядке, в котором вы хотите их построить), укажите, где вы хотите, чтобы вывод был. Это делается путем переопределения свойства - в вашем файле TFSBuild.

Но я также согласен с предыдущим постером - почему бы вам просто не запустить один скрипт сборки и не добавить zip-задачу в конце? Поддержание buildscript для каждого проекта увеличивает накладные расходы на обслуживание...

Слинг это в группу свойств:

<CustomizableOutDir>true</CustomizableOutDir>

Он переопределит глобальное свойство CustomizableOutDir, которое по умолчанию установлено в False. Установка этого в свойствах SolutionToBuild не будет работать.

Вы достигаете этого, переопределяя стандартную целевую реализацию CoreDropBuild.

В вашем файле TFSBuild.proj (по умолчанию хранится в TeamBuildTypes /) добавьте следующую цель:

    <!-- Override default implementation -->
    <Target 
       Name="CoreDropBuild"
       Condition=" '$(SkipDropBuild)'!='true' and '$(IsDesktopBuild)'!='true' "
       DependsOnTargets="$(CoreDropBuildDependsOn)">
...
    </Target>

Внутри этой цели вы можете манипулировать выводом так, как хотите. По умолчанию просто копировать все из $(BinariesRoot)\$(BuildType) в $(DropLocation)\$(BuildNumber).

Я обычно использую проект Microsoft.Sdc.Tasks для возможности копирования файлов.

Простое решение:

Замените все узлы на . Это, конечно, будет работать только для публикуемых проектов (например, веб-проектов и приложений), но не для библиотечных проектов.

Так просто:)

Другие вопросы по тегам