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

В нашем проекте мы хотели бы, чтобы наша сборка TFS помещала каждый проект в отдельную папку в папке drop, вместо того, чтобы помещать все файлы в одну плоскую структуру. Чтобы проиллюстрировать это, мы хотели бы увидеть что-то вроде этого:

DropFolder/
  Foo/
    foo.exe
  Bar/
    bar.dll
  Baz
    baz.dll

По сути, это тот же вопрос, который был задан здесь, но теперь, когда мы используем сборки на основе рабочих процессов, кажется, что эти решения не работают. Решение, использующее свойство CustomizableOutDir, выглядело так, как будто оно будет работать лучше для нас, но я не могу распознать это свойство. Я настроил наш рабочий процесс для передачи его в MSBuild в качестве аргумента командной строки (/p:CustomizableOutDir=true), но кажется, что MSBuild просто игнорирует его и помещает выходные данные в OutDir, заданный рабочим процессом.

Я просмотрел журналы сборки и вижу, что свойства CustomizableOutDir и OutDir в аргументах командной строки устанавливаются как MSBuild. Мне все еще нужно передать OutDir, чтобы в конце я смог скопировать свои файлы в TeamBuildOutDir.

Любая идея, почему мой параметр CustomizableOutDir не распознается, или есть лучший способ добиться этого?

9 ответов

Решение

Я нашел хороший способ сделать это. Оказывается, так как вы можете установить OutDir в любое удобное для вас значение в рабочем процессе, если вы установите его в пустую строку, MSBuild вместо этого будет использовать выходной путь для конкретного проекта. Это позволяет нам быть более гибкими. Вот мое полное решение (основанное на рабочем процессе сборки по умолчанию):

В задаче "Выполнить 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>

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

Я тоже решил эту проблему и считаю, что она чище, чем существующие решения в этой теме.

  • Перед 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, эта информация выводится из имени файла решения.

Мы должны были сделать это, чтобы обойти проблему, когда у нас есть 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

Надеюсь это поможет!!!

Эти шаги не требуют изменения файла проекта - http://lajak.wordpress.com/2011/05/07/customize-binaries-folder-in-tfs-team-build/

Не уверен, что вы все еще можете заставить Team build 2010 использовать самую последнюю версию msbuild, но есть новое свойство /p:GenerateProjectSpecificOutputFolder=true, если указано, биты будут сброшены в $(OutDir)\$(ProjectName)\ для каждого проекта.

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

Вот очень простое решение, которое не требует модификации исходных файлов или файлов проекта. При настройке определения сборки "Процесс -> Проекты для сборки" вместо указания файла.sln в проектах для сборки добавьте каждый проект (.csproj или.vbproj). Теперь внутри шага "Запуск MSBuild for Project" вашего рабочего процесса измените свойство OutDir на следующее:

outputDirectory + "/" + serverBuildProjectItem.Substring(serverBuildProjectItem.LastIndexOf("/"), serverBuildProjectItem.Length - serverBuildProjectItem.LastIndexOf("/")).Replace(".csproj", String.Empty)

Это поместит выходные данные сборки каждого проекта в подкаталог с именем проекта.

Вот еще одно очень простое решение, которое не требует модификации исходных файлов или файлов проекта. При настройке определения сборки "Процесс -> Проекты для сборки" вместо указания файла.sln в проектах для сборки добавьте каждый проект (.csproj или.vbproj). Теперь внутри шага "Запуск MSBuild for Project" вашего рабочего процесса измените свойство OutDir на следующее:

OutputDirectory + "\" + System.IO.Path.GetFileNameWithoutExtension(serverBuildProjectItem)

Я не играл с TFS/MSBuild, чтобы поместить выходные файлы в отдельные папки, поэтому не могу дать прямой ответ. Однако вот несколько предложений, которые я не заметил в вашей ссылке:

  • Вы можете добавить шаги после сборки к проектам, которые копируют необходимые файлы в структуру "развертывания". (Это, конечно, также работает на машинах разработчиков, что может быть проблемой). Мы используем этот подход для наших библиотек, которые создаются и затем копируются в общую папку libs (binaries), в которую другие проекты могут ссылаться.

  • Вы можете добавить цель MSBuild, чтобы скопировать нужные файлы туда, куда вы хотите. Мы переопределили цели по умолчанию "копировать в папку", чтобы скопировать файлы в другую папку, скрыть их, подписать их цифровой подписью, встроить в установщик, подписать установщик цифровой подписью, а затем скопировать (и другие полезные вещи, такие как файлы карт обфускации) и список изменений с момента последней сборки в папку drop. В конечном итоге добавление вашей собственной цели после сборки дает вам максимальный контроль над тем, что и где находится. (С минусовой стороны, вам, возможно, придется вручную добавлять любые новые dll или exe-файлы к цели копирования после сборки, что может вызвать раздражение)

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