В нашем проекте мы хотели бы иметь нашу сборку TFS, помещает каждый проект в его собственную папку под папкой отбрасывания, вместо того, чтобы бросить все файлы в одну плоскую структуру. Для иллюстрирования мы хотели бы видеть что-то вроде этого:
DropFolder/
Foo/
foo.exe
Bar/
bar.dll
Baz
baz.dll
Это - в основном тот же вопрос, как был спрошен здесь, но теперь, когда мы используем основанные на рабочем процессе сборки, те решения, кажется, не работают. Решение с помощью свойства CustomizableOutDir было похоже на него, будет работать лучше всего на нас, но я не могу заставить то свойство быть распознанным. Я настроил наш рабочий процесс для передачи его в MSBuild как параметр командной строки (/p:CustomizableOutDir=true), но кажется, что MSBuild просто игнорирует его и помещает вывод в OutDir, данный рабочим процессом.
Я посмотрел на журналы сборки, и я вижу, что свойства CustomizableOutDir и OutDir оба становятся установленными в командной строке args к MSBuild. Мне все еще нужен OutDir, который будет передан в том, так, чтобы я мог скопировать свои файлы в TeamBuildOutDir в конце.
Какая-либо идея, почему мой параметр CustomizableOutDir не становится распознанным, или если существует лучший способ достигнуть этого?
Я придумал хороший способ сделать это. Оказывается, поскольку вы можете установить для OutDir все, что захотите в рабочем процессе, если вы установите для него пустую строку, MSBuild вместо этого будет использовать OutputPath для конкретного проекта. Это позволяет нам быть более гибкими. Вот мое полное решение (основанное на рабочем процессе сборки по умолчанию):
В задаче «Выполнить MSBuild» установите для OutDir пустую строку. В той же задаче установите для CommandLineArguments примерно следующее. Это позволит вам иметь ссылку на OutDir TFS по умолчанию из вашего проекта:
String.Format("/p:CommonOutputPath=""{0}\\""", outputDirectory)
В каждом проекте, который вы хотите скопировать в папку drop, установите OutputPath следующим образом:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath Condition=" '$(CommonOutputPath)'=='' ">bin\Release\</OutputPath>
<OutputPath Condition=" '$(CommonOutputPath)'!='' ">$(CommonOutputPath)YourProjectName\bin\Release\</OutputPath>
</PropertyGroup>
Отметьте все, и у вас должен быть рабочий build, которая развертывает каждый из ваших проектов в отдельной папке в папке drop.
Я не пробовал заставить TFS / MSBuild помещать выходные файлы в отдельные папки, поэтому не могу дать прямого ответа. Однако вот несколько предложений, которые я не заметил в вашей ссылке:
Вы можете добавить шаги после сборки в проекты, которые копируют необходимые файлы в структуру «развертывания». (Это, конечно, также будет работать на машинах разработчиков, что может быть проблемой). Мы используем этот подход для наших библиотек, которые создаются, а затем копируются в общую папку libs (двоичных файлов), чтобы другие проекты могли ссылаться на них.
Вы можете добавить цель MSBuild, чтобы копировать необходимые файлы туда, куда вы хотите. Мы переопределили цели по умолчанию «копировать в папку для перетаскивания», чтобы скопировать файлы в другую папку, затемнить их, поставить цифровую подпись, встроить в программу установки, поставить цифровую подпись для установщика, а затем скопировать его (и другие полезные вещи, такие как файлы карты обфускации) и список изменений с момента последней сборки в папке drop. В конечном итоге добавление вашей собственной цели после сборки дает вам максимальный контроль над тем, что именно и куда помещается. (С другой стороны, вам может потребоваться вручную добавить любые новые библиотеки DLL или exes к цели копирования после сборки, что может вызвать раздражение)
Нам пришлось сделать это, чтобы обойти проблему, когда у нас есть библиотека Silverlight и библиотека .Net с одинаковым именем для сериализации CSLA. Библиотека перезаписывалась, и наши тесты проваливались.
Я использовал ответ Джонатана и пост Джима Лэмба, но обнаружил, что вам также нужно установить OutDir пустым.
Итак, вам нужно сделать эти параметры для деятельности MSBuild (если вы используете следующий макрос, вам нужно установить параметры деятельности для Clean тоже, иначе вы получите предупреждения, что OutputPath не установлен):
String.Format("/p:SkipInvalidConfigurations=true;TeamBuildOutDir=""{0}"" {1}", BinariesDirectory, MSBuildArguments)
Я также создал макрос, который можно запустить в 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
Надеюсь, это поможет!!!