在我们的项目中,我们希望我们的TFS构建将每个项目放在drop文件夹下的自己的文件夹中,而不是将所有文件都放到一个平面结构中。为了说明,我们希望看到类似的内容:
DropFolder/
Foo/
foo.exe
Bar/
bar.dll
Baz
baz.dll
这与问here的问题基本相同,但现在我们正在使用基于工作流的构建,这些解决方案似乎不起作用。使用CustomizableOutDir属性的解决方案看起来对我们来说效果最好,但我无法识别该属性。我自定义了我们的工作流程,将其作为命令行参数传递给MSBuild(/ p:CustomizableOutDir = true),但似乎MSBuild只是忽略它并将输出放入工作流程给出的OutDir中。
我查看了构建日志,我可以看到CustomizableOutDir和OutDir属性都在命令行args中设置为MSBuild。我仍然需要传递OutDir,以便我可以在最后将我的文件复制到TeamBuildOutDir。
知道为什么我的CustomizableOutDir参数没有得到识别,或者是否有更好的方法来实现这个目标?
答案 0 :(得分:14)
我想出了一个很好的方法。事实证明,由于您可以将OutDir设置为工作流中的任何内容,因此如果将其设置为空字符串,MSBuild将使用特定于项目的OutputPath。这让我们变得更加灵活。这是我的整个解决方案(基于默认构建工作流程):
在“运行MSBuild”任务中,将OutDir设置为空字符串。在同一任务中,将CommandLineArguments设置为如下所示。这将允许您从项目中引用TFS默认OutDir:
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>
检查所有内容,您应该有一个工作版本,将每个项目部署到drop文件夹下的自己的文件夹中。
答案 1 :(得分:8)
我也解决了这个问题,我认为它比这个线程上的现有解决方案更清晰。
Run MSBuild for Project
活动之前,我添加了Assign
个活动:projectName = Regex.Replace(New FileInfo(localProject).Name, "\.sln$", "")
。 Create Directory
个活动:outputDirectory + "\" + projectName
OutDir
更改为outputDirectory + "\" + projectName
。 模板已使用代理上构建的localProject
文件的完整路径名填充.sln
,例如c:\build\path\to\MySolution.sln
。 assign活动将路径和扩展名切断,将输出放在MySolution
中。您需要创建projectName
变量,然后导入System.Text.RegularExpressions
和System.IO
。
优于OP的解决方案的优势在于您无需编辑每个.csproj
,该信息是从解决方案文件的名称推断出来的。
答案 2 :(得分:4)
我们必须这样做才能绕过我们拥有Silverlight和.Net库以及CSLA序列化同名的问题。该库将被覆盖,我们的测试将失败。
我使用了Jonathan的答案和Jim Lamb's post,但我发现你还需要将OutDir设置为空。
因此,您需要为MSBuild活动执行这些参数(如果使用以下宏,则还需要为Clean设置活动参数,否则会收到没有设置OutputPath的警告):
String.Format("/p:SkipInvalidConfigurations=true;TeamBuildOutDir=""{0}"" {1}", BinariesDirectory, MSBuildArguments)
我还创建了一个可以在visual studio中运行的宏,它从配置中删除了OutputPath,并为所有配置添加了一个包含OutputPath的PropertyGroup,如下所示:
<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
希望这有帮助!!!
答案 3 :(得分:2)
答案 4 :(得分:1)
这是一个非常简单的解决方案,无需修改源文件或项目文件。设置构建定义的过程时 - &gt;要构建的项目,而不是在要构建的项目中指定.sln文件,添加每个项目(.csproj或.vbproj)。现在,在工作流程的“运行MSBuild for Project”步骤中,将OutDir属性更改为以下内容:
outputDirectory + "/" + serverBuildProjectItem.Substring(serverBuildProjectItem.LastIndexOf("/"), serverBuildProjectItem.Length - serverBuildProjectItem.LastIndexOf("/")).Replace(".csproj", String.Empty)
这会将每个项目的构建输出放入以项目命名的子目录中。
答案 5 :(得分:1)
我已经为Nuget为My Solution中的每个可执行文件安装了package PublishedApplications,并且在构建期间为每个项目在_PublishedApplications文件夹下创建了子文件夹。
答案 6 :(得分:1)
不确定你是否仍然可以让团队构建2010使用最新版本的msbuild,但是有一个新属性/ p:GenerateProjectSpecificOutputFolder = true,当指定时会将这些位丢弃到$(OutDir)\ $(ProjectName)\中每个项目。
答案 7 :(得分:0)
我没有玩TFS / MSBuild将输出文件放在单独的文件夹中,因此无法给出直接答案。但是,这里有一些我没有在您的链接中发现的建议:
您可以将后期构建步骤添加到将所需文件复制到“部署”结构的项目中。 (这当然也可以在dev机器上运行,这可能会很痛苦)。我们将这种方法用于我们的库,然后构建它们,然后将其复制到共享库(二进制文件)文件夹中以供其他项目引用。
您可以添加MSBuild目标以将所需文件复制到所需位置。我们已经覆盖默认的“复制到放置文件夹”目标,将文件复制到另一个文件夹,对它们进行模糊处理,对它们进行数字签名,将它们构建到安装程序中,对安装程序进行数字签名,然后复制它(以及其他有用的东西,如混淆映射文件)以及自上次构建到drop文件夹以来的更改列表。最终添加自己的后期构建目标可以让您最大限度地控制放在哪里。 (在负面,您可能必须手动将任何新的dll或exes添加到构建后的复制目标,这可能会令人恼火)
答案 8 :(得分:0)
这是另一个非常简单的解决方案,无需修改源文件或项目文件。设置构建定义的过程时 - &gt;要构建的项目,而不是在要构建的项目中指定.sln文件,添加每个项目(.csproj或.vbproj)。现在,在工作流程的“运行MSBuild for Project”步骤中,将OutDir属性更改为以下内容:
OutputDirectory + "\" + System.IO.Path.GetFileNameWithoutExtension(serverBuildProjectItem)