Как я могу заставить TFS 2010 строить каждый проект в отдельный каталог?
В нашем проекте мы хотели бы, чтобы наша сборка TFS помещала каждый проект в свою папку под папкой drop, вместо того чтобы отбрасывать все файлы в одну плоскую структуру. Чтобы проиллюстрировать это, мы хотели бы увидеть что-то вроде этого:
DropFolder/
Foo/
foo.exe
Bar/
bar.dll
Baz
baz.dll
Это в основном тот же вопрос, который был задан здесь, но теперь, когда мы используем сборки на основе рабочих процессов, эти решения, похоже, не работают. Решение, использующее свойство CustomizableOutDir, выглядело так, как будто оно будет работать лучше всего для нас, но я не могу распознать это свойство. Я настроил наш рабочий процесс, чтобы передать его в MSBuild в качестве аргумента командной строки (/p: CustomizableOutDir = true), но похоже, что MSBuild просто игнорирует его и помещает вывод в OutDir, заданный рабочим процессом.
Я просмотрел журналы сборки, и я вижу, что свойства CustomizableOutDir и OutDir оба устанавливаются в командной строке args для MSBuild. Мне все еще нужно передать OutDir, чтобы я мог копировать свои файлы в TeamBuildOutDir в конце.
Любая идея, почему мой параметр CustomizableOutDir не распознается, или если есть лучший способ достичь этого?
Ответы
Ответ 1
Я придумал хороший способ сделать это. Оказывается, так как вы можете установить OutDir в любое рабочее место, если вы установите его в пустую строку, MSBuild вместо этого будет использовать OutputPath для конкретного проекта. Это позволяет нам быть более гибкими. Здесь мое полное решение (основанное на рабочем процессе сборки по умолчанию):
В Запустите задачу MSBuild установите OutDir в пустую строку. В этой же задаче установите для CommandLineArguments следующее: Это позволит вам ссылаться на OutDir по умолчанию для TFS по умолчанию:
String.Format("/p:CommonOutputPath=""{0}\\""", outputDirectory)
В каждом проекте, который вы хотите скопировать в папку перетаскивания, установите OutputPath следующим образом:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath Condition=" '$(CommonOutputPath)'=='' ">bin\Release\</OutputPath>
<OutputPath Condition=" '$(CommonOutputPath)'!='' ">$(CommonOutputPath)YourProjectName\bin\Release\</OutputPath>
</PropertyGroup>
Проверьте все, и у вас должна быть рабочая сборка, которая разворачивает каждый из ваших проектов в свою папку в папке с отбрасыванием.
Ответ 2
Я тоже решил эту проблему, и я думаю, что она чище, чем существующие решения в этой теме.
- Перед
Run MSBuild for Project
активностью я добавил активность Assign
: projectName = Regex.Replace(New FileInfo(localProject).Name, "\.sln$", "")
.
- Затем я добавил активность
Create Directory
: outputDirectory + "\" + projectName
- Наконец, в работе MSBuild я изменил
OutDir
на outputDirectory + "\" + projectName
.
Шаблон уже заполняет localProject
полным именем пути файла .sln
, созданного на Агенте, например, c:\build\path\to\MySolution.sln
. Операция назначения прерывает путь и расширение, помещая вывод в MySolution
. Вам нужно будет создать переменную projectName
и импортировать System.Text.RegularExpressions
и System.IO
.
Преимущество над решением OP состоит в том, что вам не нужно редактировать каждый .csproj
, эта информация выводится из имени файла решения.
Ответ 3
Мы должны были сделать это, чтобы обойти проблему, когда у нас есть Silverlight и библиотека .Net с тем же именем для сериализации CSLA. Библиотека будет перезаписана, и наши тесты потерпят неудачу.
Я использовал ответ Джонатана и сообщение Джима Лэмба, но я обнаружил, что вам также нужно установить OutDir для пустого.
Итак, вам нужно выполнить эти параметры для действий MSBuild (если вы используете следующий макрос, вам нужно также установить параметры активности для Clean, иначе вы получите предупреждения о том, что OutputPath не установлен):
- Установить CommandLineArguments для
String.Format("/p:SkipInvalidConfigurations=true;TeamBuildOutDir=""{0}"" {1}", BinariesDirectory, MSBuildArguments)
- Установить OutDir для пустого (был BinariesDirectory)
Я также создал макрос, который можно запустить в visual studio, который удаляет OutputPath из конфигураций, и добавляет PropertyGroup, который содержит OutputPath для всех конфигураций:
<PropertyGroup Label="OutputPathLabel">
<OutputPath Condition="'$(TeamBuildOutDir)'=='' ">bin\$(Configuration)\</OutputPath>
<OutputPath Condition="'$(TeamBuildOutDir)'!='' ">$(TeamBuildOutDir)\$(SolutionName)\$(MSBuildProjectName)\$(Configuration)\</OutputPath>
</PropertyGroup>
Здесь макрос:
Public Sub SetTeamBuildOutDir()
Dim projectObjects = DTE.Solution.Projects
For Each project In projectObjects
If project.ProjectItems IsNot Nothing Then
SetTeamBuildOutDirRecursive(project)
End If
Next
End Sub
Sub SetTeamBuildOutDirRecursive(ByVal proj As Project)
If proj.ConfigurationManager Is Nothing Then
For Each subProj As ProjectItem In proj.ProjectItems
If subProj.SubProject IsNot Nothing Then
SetTeamBuildOutDirRecursive(subProj.SubProject)
End If
Next
Else
SetTeamBuildOutDir(proj)
End If
End Sub
Sub SetTeamBuildOutDir(ByVal project As Project)
'Do not handle .vdproj
If project.FullName.ToLower().EndsWith(".vdproj") Then
Exit Sub
End If
Dim needToSave = False
Dim msproject = ProjectRootElement.Open(project.FullName)
Dim outputPathGroupExists = False
Dim outputPropertyGroup As ProjectPropertyGroupElement = Nothing
Dim lastConfigPropertyGroup As ProjectPropertyGroupElement = Nothing
For Each propertyGroup In msproject.PropertyGroups
If propertyGroup.Label = "OutputPathLabel" Then
outputPathGroupExists = True
outputPropertyGroup = propertyGroup
End If
If Not String.IsNullOrEmpty(propertyGroup.Condition) AndAlso _
propertyGroup.Condition.TrimStart().StartsWith("'$(Configuration)") Then
lastConfigPropertyGroup = propertyGroup
End If
'Remove the OutputPath from the configurations
Dim outputPathElement As ProjectPropertyElement = Nothing
For Each element As ProjectPropertyElement In propertyGroup.Children
If element.Name = "OutputPath" Then
outputPathElement = element
End If
Next
If outputPathElement IsNot Nothing Then
propertyGroup.RemoveChild(outputPathElement)
needToSave = True
End If
Next
'If we want to always remove the group and add it back (in case of modifications to the group)
'If outputPathGroupExists Then
' msproject.RemoveChild(outputPropertyGroup)
' outputPathGroupExists = False
'End If
If Not outputPathGroupExists Then
Dim propertyGroup = msproject.CreatePropertyGroupElement()
propertyGroup.Label = "OutputPathLabel"
'Need to insert the PropertyGroup before the CSharp targets are included
msproject.InsertAfterChild(propertyGroup, lastConfigPropertyGroup)
Dim isDbProject = project.FullName.ToLower().EndsWith(".dbproj")
Dim outputEmpty = propertyGroup.AddProperty("OutputPath", IIf(Not isDbProject, "bin\$(Configuration)\", "sql\$(Configuration)\"))
outputEmpty.Condition = "'$(TeamBuildOutDir)'=='' "
Dim outputTeamBuild = propertyGroup.AddProperty("OutputPath", "$(TeamBuildOutDir)\$(SolutionName)\$(MSBuildProjectName)\$(Configuration)\")
outputTeamBuild.Condition = "'$(TeamBuildOutDir)'!='' "
needToSave = True
End If
If needToSave Then
'checkout the project file with tfs
Shell("C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe checkout " & project.FullName, , True)
'Save the project file
msproject.Save()
End If
End Sub
Надеюсь, это поможет!!!
Ответ 4
Шаги здесь не требуют изменения файла проекта - http://lajak.wordpress.com/2011/05/07/customize-binaries-folder-in-tfs-team-build/
Ответ 5
Здесь очень простое решение, которое не требует изменения исходных файлов или файлов проекта. При настройке процесса сборки → Проекты для сборки вместо указания вашего .sln файла в проектах для сборки добавьте каждый проект (.csproj или .vbproj). Теперь в шаге "Запуск MSBuild для проекта" измените свойство OutDir на следующее:
outputDirectory + "/" + serverBuildProjectItem.Substring(serverBuildProjectItem.LastIndexOf("/"), serverBuildProjectItem.Length - serverBuildProjectItem.LastIndexOf("/")).Replace(".csproj", String.Empty)
Это приведет к тому, что каждый проект будет выводиться в подкаталог, названный в честь проекта.
Ответ 6
Ive установил пакет PublishedApplications из Nuget для каждого исполняемого файла в моем решении и создал подпапки в папке _PublishedApplications для каждого проекта во время сборки.
Ответ 7
Я не играл с получением TFS/MSBuild для размещения выходных файлов в отдельных папках, поэтому не могу дать прямой ответ. Однако, вот несколько предложений, которые я не заметил в вашей ссылке:
-
Вы можете добавить шаги после сборки к проектам, которые копируют необходимые файлы в структуру "развертывания". (Это, конечно, также будет работать на dev машинах, что может быть болью). Мы используем этот подход для наших библиотек, которые создаются, а затем копируются в папку общих библиотек (двоичных файлов) для других проектов, чтобы ссылаться на них.
-
Вы можете добавить цель MSBuild, чтобы скопировать нужные файлы там, где они вам нужны. Мы переопределили цели по умолчанию "копировать в папку", чтобы скопировать файлы в другую папку, обфускать их, подписать их цифровым способом, создать их в установщике, подписать под цифровой подписью установщик и затем скопировать его (и другие полезные материалы, такие как obfuscation map files) и список изменений с момента последней сборки в папке с отбрасыванием. В конечном итоге добавление вашей собственной цели после сборки дает вам максимальный контроль над тем, что получает где-то. (На минусовой стороне вам, возможно, придется вручную добавлять любые новые dll или exes в цель копирования после сборки, что может вызвать раздражение)
Ответ 8
Вот еще одно очень простое решение, которое не требует модификации исходных файлов или файлов проекта. При настройке процесса сборки → Проекты для сборки вместо указания вашего .sln файла в проектах для сборки добавьте каждый проект (.csproj или .vbproj). Теперь в шаге "Запуск MSBuild для проекта" измените свойство OutDir на следующее:
OutputDirectory + "\" + System.IO.Path.GetFileNameWithoutExtension(serverBuildProjectItem)
Ответ 9
Не уверен, что вы все равно можете получить команду build 2010 для использования последней версии msbuild, но там будет добавлено новое свойство /p: GenerateProjectSpecificOutputFolder = true, если указано, будет бить биты в $(OutDir)\$(ProjectName)\for каждый проект.