开发者

How to always execute a target in MSBuild

I have an MSBuild file that manipulates the AssemblyInfo file before the application is compiled. At the end of the build, it restores the AssemblyInfo file. It does this by backing up the file, manipulatin开发者_运维知识库g it, and then after build time, restoring the file.

This works fairly well except when an error occurs during the build. It then does not restore the original file. Is there a way I can tell MSBuild to execute a target at the end of a build no matter if it succeeded or failed?


Based on your last comment to the original question I would take another approach, and forget the approach you are currently taking. You should know that your version info doesn't have to be in the AssemblyInfo.cs file. It can be in any code file, just as long as you only have attributes AssemblyVersion and AssemblyFileVersion defined once each. With that being said what I would do is follow these steps:

  1. Remove AssemblyVersion & AssemblyFileVersion from AssemblyInfo.cs
  2. Create a new file, name it whatever you want want in my case I put it at Properties\VersionInfo.cs. Do not add this file to the project.
  3. Edit the project file to include that file into the list of file to be compiled only when you want it

Let's expand a bit on #3. When you build a .NET project, the project itself is an MSBuild file. Inside that file you will find an item declared Compile. This is the list of files that will be sent to the compiler to be compiled. You can dynamically include/exclude files from that list. In you case you want to include the VersionInfo.cs file only if you are building on the build server (or whatever other condition you define). For this example I defined that condition to be if the project was building in Release mode. So for Release mode VersionInfo.cs would be sent to the compiler, and for other builds not. Here are the contents of VersionInfo.cs

VersionInfo.cs

[assembly: System.Reflection.AssemblyVersion("1.2.3.4")]
[assembly: System.Reflection.AssemblyFileVersion("1.2.3.4")]

In order to hook this into the build process you have to edit the project file. In that file you will find an element (maybe more than 1 depending on project type). You should add a target similar to the following there.

<Target Name="BeforeCompile">
  <ItemGroup Condition=" '$(Configuration)'=='Release' ">
    <Compile Include="Properties\VersionInfo.cs" />
  </ItemGroup>
</Target>

Here what I've done here is to define a target, BeforeCompile, which is a well-known target that you can override. See this MSDN article about other similar targets. Basically this is a target which will always be called before the compiler is invoked. In this target I add the VersionInfo.cs to the Compile item only if the Configuration property is set to release. You could define that property to be whatever you wanted. For instance if you have TFS as your build server then it could be,

<Target Name="BeforeCompile">
  <ItemGroup Condition=" '$(TeamFoundationServerUrl)'!='' ">
    <Compile Include="Properties\VersionInfo.cs" />
  </ItemGroup>
</Target>

Because we know that TeamFoundationServerUrl is only defined when building through TFS.

If you are building form the command line then something like this

<Target Name="BeforeCompile">
  <ItemGroup Condition=" '$(IncludeVersionInfo)'=='true' ">
    <Compile Include="Properties\VersionInfo.cs" />
  </ItemGroup>
</Target>

And when you build the project just do msbuild.exe YourProject.proj /p:IncludeVersion=true. Note: this will not work when building a solution.


What about changing the problem:

  • Add a "template" AssemblyInfo.cs.template to version control that represents your "ideal" AssemblyInfo.cs with regex hooks in there
  • Before build, copy the template to the real and apply your regexes
  • Add some kind of subversion ignore for AssemblyInfo.cs (I'm no svn expert, but I'm pretty sure there is a way you can tell it to ignore certain files)
  • In the event that your devs need to add some kind of customization that would normally appear in an AssemblyInfo.cs (eg InternalsVisibleTo), then get them to add it to a different .cs file that IS checked in.

As a further refinement, combine Sayed's solution with mine and remove version info stuff from the actual AssemblyInfo.cs and have a VersionInfo.cs.template that is checked in, that creates a VersionInfo.cs in BeforeBuild.


I never used it, but from the documentation it seems that the OnError Element is useful to what you're trying to achieve.

Causes one or more targets to execute, if the ContinueOnError attribute is false for a failed task.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜