我刚刚加入了一个没有CI流程的团队(甚至不是一夜之间的构建)和一些粗略的开发实践。我想要改变这一点,所以我现在的任务是创建一个通宵构建。我跟随this series的文章:创建一个包含我们所有项目的主解决方案(一些web应用程序、web服务、一些Windows服务,以及可编译为命令行可执行文件的耦合工具);创建一个MSBuild脚本来自动构建、打包和部署我们的产品;并创建一个.cmd文件来一次点击完成所有这些工作。这是我现在试图完成的一项任务,作为这一切的一部分:
该团队目前的做法是将web.config和app.config文件放在源代码控制之外,并将其放入名为web.template.config和app.template.config的源代码控制文件中。其目的是开发人员将.template.config文件复制到.config,以便获得所有标准配置值,然后能够将.config文件中的值编辑为他在本地开发/测试所需的任何值。由于显而易见的原因,我想自动执行将.template.config文件重命名为.config的过程。做这件事最好的方法是什么?
有没有可能在构建脚本本身中做到这一点,而不必在脚本中规定需要重命名的每个单独的文件(这将需要在任何时候向解决方案添加新项目时对脚本进行维护)?或者,我可能需要编写一些批处理文件,然后直接从脚本运行?
此外,有没有更好的开发解决方案,我可以建议,使整个过程变得不必要?
发布于 2012-12-04 03:13:42
在阅读了大量关于项目组、目标和复制任务的内容之后,我想出了如何做我需要的事情。
<ItemGroup>
<FilesToCopy Include="..\**\app.template.config">
<NewFilename>app.config</NewFilename>
</FilesToCopy>
<FilesToCopy Include="..\**\web.template.config">
<NewFilename>web.config</NewFilename>
</FilesToCopy>
<FilesToCopy Include"..\Hibernate\hibernate.cfg.template.xml">
<NewFilename>hibernate.cfg.xml</NewFilename>
</FilesToCopy>
</ItemGroup>
<Target Name="CopyFiles"
Inputs="@(FilesToCopy)"
Outputs="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFilename)')">
<Message Text="Copying *.template.config files to *.config"/>
<Copy SourceFiles="@(FilesToCopy)"
DestinationFiles="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFilename)')"/>我创建了一个包含要复制的文件的项目组。**操作符告诉它递归遍历整个目录树,以查找具有指定名称的每个文件。然后,我向这些文件中的每个文件添加一段名为"NewFilename“的元数据。这是我将重命名每个文件的名称。
这段代码将添加名为app.template.config的目录结构中的每个文件,并指定我将把新文件命名为app.config:
<FilesToCopy Include="..\**\app.template.config">
<NewFilename>app.config</NewFilename>
</FilesToCopy>然后,我创建一个目标来复制所有文件。这个目标最初非常简单,只是为了总是复制和覆盖文件而调用复制任务。我将FilesToCopy项目组作为复制操作的源进行传递。我使用transforms来指定输出文件名,以及我的NewFilename元数据和众所周知的项元数据。
例如,下面的代码片断将文件c:\Project\Subdir\app.template.config转换为c:\Project\Subdir\app.config,并将前者复制到后者:
<Target Name="CopyFiles">
<Copy SourceFiles="@(FilesToCopy)"
DestinationFiles="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')"/>
</Target>但是后来我注意到,开发人员可能不喜欢在每次运行脚本时都覆盖他的自定义web.config文件。但是,如果存储库的web.template.config已被修改,并且其中包含代码所需的新值,则开发人员可能应该将其本地文件覆盖。我尝试了许多不同的方法--使用"Exist()“函数将复制属性"SkipUnchangedFiles”设置为true --都无济于事。
这个问题的解决方案是building incrementally。这可确保只有在app.template.config较新的情况下才会覆盖文件。我将文件名作为目标输入传递,并将新文件名指定为目标输出:
<Target Name="CopyFiles"
Input="@(FilesToCopy)"
Output="@(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')">
...
</Target>这具有目标检查,以查看当前输出相对于输入是否是最新的。如果不是,即特定的.template.config文件比其对应的.config文件具有更新的更改,那么它将复制web.template.config覆盖现有的web.config。否则,它将使开发人员的web.config文件保持原样。如果不需要复制任何指定的文件,则完全跳过目标。在干净的存储库克隆之后,将立即复制每个文件。
上面的解决方案被证明是一个令人满意的解决方案,因为我才刚刚开始使用MSBuild,我对它的强大功能感到惊讶。我唯一不喜欢的是我不得不在两个地方重复完全相同的变换。我讨厌复制任何类型的代码,但我想不出如何避免这种情况。如果有人有什么建议,我们将不胜感激。此外,虽然我认为必须这样做的开发实践完全很糟糕,但这确实有助于减轻这种糟糕的因素。
发布于 2012-10-19 01:01:49
简短回答:
是的,您可以(也应该)自动执行此操作。您应该能够使用MSBuild Move task重命名文件。
长篇答案:
希望从手动流程更改为自动流程,这是很棒的。通常很少有真正的理由不进行自动化。您的构建脚本将充当构建和部署实际工作方式的活动文档。在我看来,一个好的构建脚本比静态文档更有价值(尽管我并不是说你不应该有文档-它们毕竟不是相互排斥的)。让我们逐一解决您的问题。
最好的方法是什么?
我不完全理解您在这些文件中存储了什么配置,但我怀疑其中的许多配置可以在整个开发团队中共享。
我建议提出以下问题:
是否可以在构建脚本本身中执行此操作,而不必在脚本中规定需要重命名的每个文件?
是的,看看MSBuild Move task吧。您应该能够使用它来重命名文件。
每当向解决方案中添加新项目时,...which都需要对脚本进行维护?
这是不可避免的-您的构建脚本必须与您的解决方案一起发展。接受这一事实,并在您的估计中包括对构建脚本进行更改的时间。
此外,我可以建议一个更好的开发解决方案,使整个过程变得不必要?
我不知道所有的要求,所以很难推荐一些非常具体的东西。我可以说建议如下:
的瓶颈
请记住,从无构建脚本到完全自动化不是一个一朝一夕的过程。要有耐心,首先要专注于导致最大痛苦的自动化领域。
如果我误解了你的任何问题,请让我知道,我会更新答案。
https://stackoverflow.com/questions/12959349
复制相似问题