Conditionally setting the AssemblyVersion at build time

I have a need to build a project and only increment the version number if and only if the project has changed, is there ANY way to do this other than build the project twice Can this possibly be done with a custom MSBuild task

So far I have seen that you can update the AssemblyInfo.cs from the MSBuild process but doing so before the build makes it so that it will produce a new assembly, which I don't want to do unless something else changes which causes the build to produce a new assembly, then and only then do I want to apply a new version number.

Any help would be greatly appreciated!

Thanks,
Jim


Answer this question

Conditionally setting the AssemblyVersion at build time

  • AK WG99

    "output be all the assemblyinfo files"

    Does this mean the output of the project If it is an exe or dll

    I came across your post and wondered if it would possibly do what I need to do...

    How To: Reference the project file as a target input

    I was messing around today with my latest custom task (more on that later, as soon as I can find somewhere to post it), and needed to find a way to tell the target that it depended on the actual project file. I wanted to force the target, and by extension my task, to get run whenever the project file changed.

    A quick trip down the hall to Rajeev revealed an elegant solution: the MSBuildProjectFile property. This gets set to the name of the current leaf project file. I'm now using it like this:

    <Target Name="BeforeBuild" Inputs="$(MSBuildProjectFile)" Outputs="@(AssemblyInfo)">
       <AssemblyInfo [stay tuned for more details on what this task is!]/>
    </Target>

    Now whenever the project file changes the target gets run. For reference, MSDN has a list of all the special properties that MSBuild knows about.

    [ Author: Neil Enns ]

    What consfuses me is the Outputs=”@(AssemblyInfo)” part, what does this do I thought this was the output of the project But it looks like it is the same name as your Task Or are these logically different things

    < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

    Also, in this example, does MSBuildProjectFile literally mean if the .csproj file itself changed Or does it consider anything it builds

     

    Any more info will greatly help, also, is there anyway you can point me to a working example of the use of this I am very interested in the AssemblyInfo Task you are writing and if you can, I would like to see the source of that as well…

     

     

    My urgency is based on the fact that I am researching ways to reduce our build output for incremental changes all the while controlling the specific version assigned to each assembly built.  So any advanced peek at your work would be great Big Smile

     

    Thanks,

     

    -Jim C

    *** Note *** I am or will be wanting to apply this to VS 2005 csproj files. Each with multiple source files and references. Plus, this would need to be applied to literally hundreds of projects...so I am looking for the most generic possible solution and I am just now learning this stuff!

    ***EDIT***

    I've been looking at the .targets and it seems that the Inputs I want should be the same Inputs as the core compile targets


  • Amit G

    Hello,

    This is what I see in the build log file -

    Target BeforeBuild:

    Skipping target "BeforeBuild" because it has no outputs.

    TfsBuild proj file -

    <Target Name="BeforeBuild" Inputs="$(MSBuildAllProjects);@(Compile);@(ManifestResourceWithNoCulture);$(ApplicationIcon);$(AssemblyOriginatorKeyFile);@(ManifestNonResxWithNoCultureOnDisk);@(ReferencePath);@(CompiledLicenseFile);@(EmbeddedDocumentation);@(CustomAdditionalCompileInputs)" Outputs="@(AssemblyInfo)">

    <Message Text="Before build is firing!"/>

    <!-- Trying to update the AssemblyInfo files -->

    </Target>

    Any help appreciated.

    Thanks.


  • Anthony Fine

    Hi Jim,

        I believe you could use the target built-in dependency checking to do this.  By setting the correct inputs and outputs on a target, MSBuild automatically skips over the target when its outputs files are all newer than its input files.  So, if you had a target like this:

    <BeforeBuild Inputs="@(FilesThatCauseTheOutputToChange)" Outputs="@(OutputFiles)">
       <!-- Update the assemblyInfo.cs here -->
    </BeforeBuild>

    That wouldn't run the build target unless the files that cause the output to change have been updated since the output files have been updated. 

    If you are trying to insert this into an existing MSBuild project that is being built by Visual Studio, there are a list of names you can assign to a custom target you write that will make it be called at the appropriate time in your build.  In particular, I recommend taking a look at this thread:  http://forums.microsoft.com/msdn/ShowPost.aspx PostID=89060

    Cheers,

       Taylor

  • Alan Wills

    Taylor's approach is the right idea. In fact, for my assemblyinfo task (which will get posted as soon as we have our gotdotnet site up!) this is the recommended way of doing it. Set your inputs to be all the possible files that could cause a rebuild (typically your source files and resource files), and have the output be all the assemblyinfo files that got changed.

    Neil



  • jlove

    I came up with this and it sseems to work...


    <Target Name="BeforeBuild" Inputs="$(MSBuildAllProjects);@(BuiltProjectOutputGroupDependency);@(Compile);@(ManifestResourceWithNoCulture);$(ApplicationIcon);$(AssemblyOriginatorKeyFile);@(ManifestNonResxWithNoCultureOnDisk);@(ReferencePath);@(CompiledLicenseFile);@(EmbeddedDocumentation);@(CustomAdditionalCompileInputs)" Outputs="@(IntermediateAssembly);" Condition="'$(BuildingInsideVisualStudio)'=='true'" DependsOnTargets="AllProjectOutputGroupsDependencies;$(CoreCompileDependsOn)">
        <!--
       
        Inputs="@(BuiltProjectOutputGroupDependency)"
        Outputs="@(IntermediateAssembly);
        $(NonExistentFile)"
        >
        -->
        <WriteLinesToFile File="c:\lines.txt" Lines="@(BuiltProjectOutputGroupDependency);@(Compile)" />
      </Target>

  • Robert Gruen

    Ah, yes, my blog entry is missing a critical piece of information. In my targets file I've defined the following new item group:

    <ItemGroup>
       <AssemblyInfo>**\AssemblyInfo.*</AssemblyInfo>
    </ItemGroup>

    This picks up all assemblyinfo files, regardless of language, in all subdirectories of the project. This is important because VB and C# store the assemblyinfo file in different places, and the extensions are different.

    I then use this as the Output parameter on the task. It means that when my task gets run the incremental build aspects of msbuild will know that the output files, if changed, will trigger further actions later in the build process.

    I agree, the core compile targets are likely the inputs you want to use. That way if something is going to cause a compile to happen you can update the version number. That would make your target look like this:

    <Target Name="BeforeBuild" Inputs="$(MSBuildAllProjects);@(Compile);@(ManifestResourceWithNoCulture);$(ApplicationIcon);$(AssemblyOriginatorKeyFile);@(ManifestNonResxWithNoCultureOnDisk);@(ReferencePath);@(CompiledLicenseFile);@(EmbeddedDocumentation);@(CustomAdditionalCompileInputs)" Outputs="@(AssemblyInfo)">
       <!-- Update the AssemblyVersions here somehow -->
    </Target>

    Does this help

    Neil

  • ian1234

    Neil,

    Any update on your AssemblyInfo task I've been trying to get mine to work which it would if I could simply load the AssmeblyInfo.cs file and change the values but this seems to be more difficult that implementing a custom build task. I've looked at using the CSharpCodeProvider but there seems to be no way to load the existing AssemblyInfo file and change the AssemblyVersion and write the cs file back out directly unless I simply use text search and replace. I was wanting to use the CodeDOM, am I over killling the solution Should I simply use a text search and replace

    Any direction would be appreciated.

    Thanks,
    Jim

  • Cairn

    Awesome! Thank you! I'm only 3 days into learning about MSBuild, I figured there had to be some way of doing this, thanks! I will give it a try!
  • snamaki

    You're quite welcome.  I only have a day or two on you, but I'm getting there.  It can be pretty cool stuff.

    Good luck!

  • Conditionally setting the AssemblyVersion at build time