让TFS将每个项目输出到自己的目录的最好方法是什么?

我将一个大型的代码库放到Team Foundation Server中。 我希望构build过程能够创build我们项目的“准备部署”构build。

我们这样做的正常方法是让每个项目的输出都在自己的文件夹中。 所以,举个例子,

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 

尽pipe它节省了一定数量的磁盘空间(每个程序集只有一次)并不是我们想要的。

什么是最好的方式来指定TFS / MSBuild应该把输出文件的位置? 我是否需要分别编辑sln / csproj文件来实现这个目标,或者我可以在TFSBuild.proj文件中完成这项工作吗? (即,在一个MSBuild特定的文件中)

我刚刚在这里写了另一个方法:

http://mikehadlow.blogspot.com/2009/06/tfs-build-publishedwebsites-for-exe-and.html,但如果你不能打扰跟随链接,这里是完整的:;

按照本“模式与实践”PDF,团队发展与TFS指南中所述,通过一个统一的超级解决scheme收集您团队控制下的所有代码是一种很好的做法。 如果您configurationTFS构build服务器来构build此解决scheme,则默认行为是将构build输出放置到单个文件夹“Release”中。

您的解决scheme中的任何Web应用程序项目也将输出到名为_PublishedWebsites \的文件夹。 这非常好,因为这意味着您可以简单地通过robocopy部署Web应用程序。

不幸的是,其他项目types(如WinForms,控制台或库)没有类似的默认行为。 这将是非常好的,如果我们可以有一个_PublishedApplications \子文件夹与任何选定的项目的输出。 幸运的是,这并不难。

_PublishedWebsites的工作方式非常简单。 如果你看看你的Web应用程序的项目文件,你会发现在底部附近有一个导入:

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

在我的机器上,MSBuildExtensionsPath属性的计算结果为C:\ Program Files \ MSBuild,如果我们打开Microsoft.WebApplication.targets文件,我们可以看到这是一个非常简单的MSBuild文件,可以识别何时构build不是桌面版本,也就是说TFS构build,并将输出复制到:

 $(OutDir)_PublishedWebsites\$(MSBuildProjectName) 

我简单地复制了Micrsoft.WebApplication.targets文件,将其放在源代码控制下,使用我的项目文件中的相对path,并将_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中有很多东西只与Web应用程序相关,可以从其他项目types中剥离出来,但是我将把它作为读者的练习。

TFS 2012+

我喜欢这个解决scheme…

编辑您的构build定义。 在“进程”部分下,将MSBuild arguments设置为

/p:GenerateProjectSpecificOutputFolder=true

喜欢这个:

在这里输入图像说明

默认情况下,每个项目文件(* .csproj,* .vbproj等)指定一个默认的输出目录(通常是bin \ Debug,bin \ Release等)。 团队build设实际上覆盖了这一点,以便您不在开发人员在项目文件中设置什么属性,而是让团队build设可以假设产出的位置。

覆盖此行为的最简单方法是在SolutionToBuild项目组中将CustomizableOutDir设置为true,如下所示:

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

如果您构build解决scheme,这将使drop文件夹结构大致匹配您将在本地获得的内容。

这种方法肯定会优先于覆盖可能导致升级问题的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。)

我回答这个问题的时候有点晚,但是有一个很简单的方法来实现Mike Hadlows的回答。 有人写了一个nuget包,确切地说,迈克在谈论什么。 你可以在这里find它: http : //www.nuget.org/packages/PublishedApplications

TFS 2010(和即将到来的TFS 2012)的更新。 Jason Stangroome写了一篇很好的博客文章,概述了如何做到这一点。

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

(上面的链接是死的…链接到caching的版本)

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 =约

覆盖TFS团队生成OutDir属性

更新: 与.NET 4.5有一个更简单的方法 。

Team Foundation Server构build系统用户非常普遍的抱怨是,它改变了项目输出的文件夹结构。 默认情况下,Visual Studio将所有文件放在每个项目各自的/ bin /或/ bin文件夹中,但Team Build只是使用一个平面文件夹结构,将所有文件放在放置文件夹的根目录下,或者再次放入一个//子文件夹文件夹,所有项目输出混合在一起。

此外,因为Team Build通过MSBuild.exe命令行设置OutDir属性并结合MSBuild的属性优先级来实现此目的,所以不能从MSBuild本身轻易地更改该值,而stream行的解决scheme是将生成过程模板* .xaml文件编辑为使用不同的属性名称 。 但是,除非绝对必要,否则我不想触摸工作stream程。

相反,我同时使用“目标解决scheme”和MSBuild v4的“embedded式任务”function来覆盖用于在解决scheme中构build单个项目的MSBuild任务的默认实现。 在我的替代实现中,我阻止OutDir属性被传递,而我通过一个名为PreferredOutDir的属性,而不是个别的项目可以使用,如果需要的话。

第一部分,将解决scheme级别的OutOir属性replace为PreferredOutDir属性,只需将新文件添加到解决scheme文件所在的目录即可实现。这个新文件应该按照“before..sln.targets”例如,对于名为“Foo.sln”的解决scheme文件,则新文件将是“到达.Foo.sln.targets”。 这个新文件的内容应该像这样 。 确保这个新文件被签入到源代码pipe理。

第二部分,让每个项目控制其输出文件夹结构,只需要将一行添加到项目的* .csproj或* .vbproj文件(取决于语言)。 find没有指定Condition属性的项目文件中的第一个元素,并find该元素的相应结束标记。 紧随结束标记之上,添加一行如下所示的内容:

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

在这个例子中,项目将输出到与项目文件(没有.csproj扩展名)相同的子文件夹下的Team Build下拉文件夹。 你可以select不同的模式。 此外,Web项目通常会在Team Build下拉文件夹的_PublishedWebSites子文件夹下创build自己的输出文件夹,以维持此行为,只需将OutDir属性设置为等于PreferredOutDir属性。

您可以在签入之前validation您的更改是否在本地计算机上运行,​​只需从命令行运行MSBuild,并像Team Build一样指定OutDir属性,例如:

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

对于那些对TFS 2010如何工作感到好奇的人来说, 这个post有几个答案,其中相关的一个对我很好。

你可以为每个项目build立一个buildscript,这将做你想要的。 只需创build一个新的TFSBuild文件,将您想要构build的项目添加到项目组(按您希望构build的顺序),设置您希望输出的位置。 这是通过覆盖TFSBuild文件中的 – 属性来完成的。

但是我也同意上一张海报 – 为什么不用一个构build脚本运行,并在最后添加一个压缩任务? 维护每个项目的构build脚本不会增加维护开销…

把它放在一个属性组中:

 <CustomizableOutDir>true</CustomizableOutDir> 

它将覆盖默认情况下设置为False的全局“CustomizableOutDir”属性。 在SolutionToBuild的属性中设置此项将不起作用。

通过覆盖默认的CoreDropBuild目标实现来实现这一点。

在您的TFSBuild.proj文件(默认存储在TeamBuildTypes / <Build Type>下)添加以下目标:

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

在此目标中,您可以根据需要操作输出。 默认是从$(BinariesRoot)\ $(BuildType)复制到$(DropLocation)\ $(BuildNumber)。

我通常使用Microsoft.Sdc.Tasks项目文件复制function。

简单scheme:

用<SolutionToPublish>replace所有<SolutionToBuild>节点。 这当然只适用于可发布项目(如Web项目和应用程序),而不适用于图书馆项目。

就如此容易 :)