Assembly Version in Teamcity Build Number Format - teamcity

in my assambly Version I want to set the first 3 digits and the fourth should be set thorugh Teamcity.
Example:
I set 2.0.1.0 in my Assambly.
Then my Teamcity should do:
2.0.1.90, 2.0.1.91...
At the moment I have:
2.0.1.%build.counter%
But what I want to have is, that 2.0.1 is set through my assambly version not through a hard number

Which Teamcity version are you using? Teamcity 9.1 has a new build feature File Content Replacer which allows you to replace contents of a file using regex. However earlier versions of teamcity do not have this in built, so for them you'll have a write it on your own, May be a powershell script or MSBuild target.
Sample code for MSBuild target SetRevisionNumber
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask AssemblyFile="MSBuild.Community.Tasks.dll" TaskName="MSBuild.Community.Tasks.FileUpdate" />
<Target Name="SetRevisionNumber" Condition="$(RevisionNumber) != ''">
<Message Text="Setting Revision Number to $(RevisionNumber) in $(AssemblyVersionFile)" Importance="High" />
<FileUpdate Files="$(AssemblyVersionFile)"
Regex="\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+)\.(\d+)"
ReplacementText="[assembly: AssemblyVersion("$1.$2.$3.$(RevisionNumber)" />
</Target>
</Project>

Related

Update Xml File (vsixmanifest)

I'm creating a Visual Studio 2013 Package (vsix) (shameless plug: pMixins ). As part of my quest to use TeamCity as a continuous integration server, I have configured Team City to build the .vsix Package (Visual Studio Package (vsix) - Team City without Visual Studio installed).
Now I want to configure Team City to set the Version in the VSIX Schema:
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest
Version="2.0.0"
xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011"
xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Version="1.0" Language="en-US" Publisher="Company" />
Following the advice in Using msbuild I want to update a config file with values from teamcity and How do I update an XML attribute from an MSBuild script? I have updated Microsoft.VsSDK.targets to use XmlPoke with the following Target:
<Target
Name="UpdateVSIXVersion"
BeforeTargets="PrepareForBuild"
Condition="$(VSIXVersion) != '' And $(VSIXVersion) != '*Undefined*'">
<Message Text= "Updating VSIX Version" />
<XmlPoke
XmlInputPath="source.extension.vsixmanifest"
Query="/PackageManifest/Metadata/Identity/#Version"
Value="$(VSIXVersion)">
</XmlPoke>
</Target>
I updated Team City with a system Parameter to set VSIXVersion:
But, when I check TeamCity, it made 0 replacements:
How do I get Team City to correctly update the .vsixmanifest xml?
After much searching I finally found the XmlPoke expects a namespace when the Xml file contains a namespace, even for the default namespace (Modifying .config File in an MSBuild Project).
However, I couldn't find any documentation for the XmlPoke.Namespaces parameter and the above referenced code didn't work. After much trial an error, I finally got it to work with this:
<Target
Name="UpdateVSIXVersion"
BeforeTargets="PrepareForBuild"
Condition="$(VSIXVersion) != '' And $(VSIXVersion) != '*Undefined*'">
<Message Text= "Updating VSIX Version" />
<XmlPoke
XmlInputPath="source.extension.vsixmanifest"
Query="/n:PackageManifest/n:Metadata/n:Identity/#Version"
Value="$(VSIXVersion)"
Namespaces="<Namespace Prefix='n' Uri='http://schemas.microsoft.com/developer/vsx-schema/2011' Name='DoNotKnowWhatThisIsFor-ButItIsRequired' />">
</XmlPoke>
Notes:
This requires MSBuild 12 to be configured on Team City
The Namespaces needs to be escaped.
The Name parameter is required, otherwise MSBuild will error out
The original XPath query had to be updated with the artificial namespace prefix.
MSBuild file is on Github if anyone needs it: https://github.com/ppittle/pMixins/blob/master/tools/vssdk_tools/v12.0/VSSDK/Microsoft.VsSDK.targets

Can I build multiple configurations of a project within one solution configuration?

I would like to build the same project twice in the same solution configuration, varying some #define flags to toggle features. Both binaries will be deployed with different names.
The solutions that I know could work:
Add a solution configuration - But I will then need to build the solution twice, which I would prefer to avoid. Both project configurations will always be built.
Copy the project - But then I have the overhead of maintaining a new project when I only want to maintain a different configuration.
Batch build - I avoid using batch build as I use both devenv for local development and msbuild for continuous integration.
Any other ideas or suggestions?
Just figured out a way to do what you asked for. Create one msbuild file (I named mine multiple.proj) and add the script below.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Choose>
<When Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<ItemGroup>
<ProjectToBuild Include="$(MSBuildProjectName).csproj">
<Properties>Configuration=Release</Properties>
</ProjectToBuild>
</ItemGroup>
</When>
</Choose>
<Target Name="BeforeBuild">
<Message Text="Building configuration $(Configuration)..." />
</Target>
<Target Name="AfterBuild">
<MSBuild Projects="#(ProjectToBuild)"/>
</Target>
</Project>
</type>
</this>
Import the script on your projects (csproj or vbproj):
<Import Project="..\multiple.proj" />
This script tells msbuild to build again your project with another configuration as an AfterBuild event. I used Debug/Release to make the example, but you can easily change the script to support other configurations, or make the decision to build again based on other variables.
Be careful because you're running two builds at once, so build errors can be harder to understand.
Hope this helps.

How to calculate MSBuild property before import

Consider these two MSBuild files. First build-script.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- build-script.xml -->
<Project
ToolsVersion="4.0"
DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputName>OutputName</OutputName>
</PropertyGroup>
<Import Project="build-script-to-import.xml"/>
</Project>
and then build-script-to-import.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- build-script-to-import.xml -->
<Project
ToolsVersion="4.0"
DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputPath>Path\$(OutputName)</OutputPath>
</PropertyGroup>
<Target Name="Build">
<Message Text="$(OutputPath)" />
</Target>
</Project>
These two files represents a very simplified C# project file (build-script.xml) referencing a common targets file (build-script-to-import.xml). That means that it is not an option to change the build-script-to-import.xml file. The problem is that the OutputName is calculated, and I need to set it to this calculated value before I import the build-script-to-import.xml file. Do you know how I can accomplish this?
NOTE 1: The calculated value is in fact an assembly version which I am able to fetch from an assembly file with the GetAssemblyIdentity MSBuild task. The problem as I see it is that I may not call a target before the import happens. I would like to set the value for property OutputName with the help of the GetAssemblyIdentity MSBuild task.
NOTE 2: The build will be triggered by Visual Studio, so I may not use a batch file and send a property to MSBuild as a command line argument.
Move the declaration of $(OutputPath) inside your "Build" target. The only way to use "calculated" properties is to have them evaluated inside a target. Globally declared "static" properties will always be evaluated before any target runs, and presumably you need to run a target to calculate the value of $(OutputName). Just be sure your name calculating target runs before the "Build" target.
If Corresponding targets from imported project allows to modify DependsOnTargets
<Target Name="Build" DependsOnTargets="#(BuildDependsOn)" />
you can modify Item and add your target wich will prepare needed properties.
If it is not possible you can write wrapper to call underlying target/targets (Build/Rebuild/Clean) by yourself (without importing build-script-to-import.xml):
build-script.xml
<Target Name="Build" DependsOn="PrepareProperties">
<MSBuild Projects="build-script-to-import.xml"
Targets="Build"
Properties="OutputName=$(OutputName);$(OtherProperties)"/>
</Target>
Suggestion
Depends on your requirement to dynamically change OutputName there may be mach simpler solution. Just not to do it. It is rather simpler to write your own custom build step to copy from fixed output directory to your destination wich is calculated using your rules.
For example, I prefer practice when I have directory called latest with fixed path and a directory for each version of product. Every one can take latest version from that folder.

Using SlowCheetah's app.config transformations with Setup projects

I'm using the SlowCheetah XML Transforms extension to handle web.config-like transformations with app.config. That part works great.
I added a setup project and configured it to include the project output of the first project. I noticed that when I ran the installer, it installed the non-transformed app.config. Looking at the Primary output Outputs (say that 10 times fast), I noticed that its finding the binary in Project\bin\Debug\Project.exe, but Project.exe.config comes from Project\app.config instead of Project\bin\Debug\Project.exe.config.
I could exclude app.config from the Primary output, and hard-code the path to a specific configuration's app.config (Project\bin\Debug\Project.exe.config), but then I'd get the same app.config regardless of which configuration I used to build it.
Is there a workaround for getting the appropriate transformed app.config in a Setup project?
Hi we are planning on releasing a new version which has ClickOnce support in the next few days. If you need a build of the add in before than which has the fix please contact me and I can get that out to you.
This may not be exactly the answer you're looking for but I have previously wrestled with how to get the correct app.config file into a setup project. I have a TFSBuild.proj msbuild file that uses transforms. The SlowCheetah transforms I think use the same msbuild task but I may be incorrect. SlowCheetah certainly provides a more useful user experience when working with transform files. My build file takes a slightly different approach. At the end of the automated build I wanted to generate installers for each of the target deployment environments. I use a number of msbuild extensions, including the TransformXml build task - not all required for the following but FWIW these are the imports:
<!-- import extensions -->
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
I have the following environments defined:
<ItemGroup>
<!-- target deployment environments -->
<Configs Include="Prod" />
<Configs Include="Staging" />
<Configs Include="Test" />
</ItemGroup>
Then the standard AfterCompileSolution target contains a call to the target that generates the installer for each environment:
<Target Name="AfterCompileSolution">
<!-- Create installers for target deployment environments -->
<CallTarget Targets="MyProject" />
</Target>
<Target Name="MyProject" Outputs="%(Configs.Identity)">
<ItemGroup>
<MyProjectTempConfig Include="$(SolutionRoot)\MyProjectService\Temp.config" />
<MyProjectConfigFrom Include="$(SolutionRoot)\MyProjectService\App.%(Configs.Identity).config" />
<MyProjectConfigTo Include="$(SolutionRoot)\MyProjectService\App.config">
<Attributes>ReadOnly</Attributes>
</MyProjectConfigTo>
</ItemGroup>
<Message Text="MyProject - Target environment: %(Configs.Identity)" />
<!-- transform app.config using appropriate -->
<Copy SourceFiles="#(MyProjectConfigTo)"
DestinationFiles="#(MyProjectTempConfig)"
OverwriteReadOnlyFiles="true"
ContinueOnError="true"
Condition="!Exists(#(MyProjectTempConfig))"/>
<File TaskAction="RemoveAttributes" Files="#(MyProjectConfigTo)"/>
<TransformXml Source="#(MyProjectTempConfig)"
Transform="#(MyProjectConfigFrom)"
Destination="#(MyProjectConfigTo)" />
<!-- run setup -->
<Exec Command=""$(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\devenv" "$(SolutionRoot)\MyProject.sln" /build Release /project MyProjectService.Setup"/>
<!-- rename output for target deployment environment -->
<Copy SourceFiles="$(SolutionRoot)\MyProjectService.Setup\Release\MyProjectService.msi"
DestinationFiles="$(OutDir)\%(Configs.Identity)_MyProjectService.msi"
OverwriteReadOnlyFiles="true"
ContinueOnError="true"/>
</Target>

XmlUpdate task not updating my XML file

I have the following task in an MSBuild script:
<XmlUpdate
Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"
XmlFileName="$(PackageDir)\temp\OddEnds.Testing\OddEnds.Testing.nuspec"
XPath="/package/metadata/version"
Value="%(OddEndsTestingAsmInfo.Version)" />
which is supposed to update an empty version node in a NuGet specification file with the assembly version. My .nuspec file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http:www.w3.org/2001/XMLSchema-instance">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>OddEnds</id>
<authors>Tomas Lycken</authors>
<!-- Here's the node I want to update -->
<version></version>
<owners>Tomas Lycken</owners>
<description>Odd ends and bits that I might need in any project.</description>
</metadata>
</package>
I believe the XPath pointer /package/metadata/version points to the right node (since if I change it to something else, it complains about not finding the node) yet the output says 0 node(s) selected for update.
What am I missing?
You may need to include the namespace in your xpath string.
Check out this blog post: http://www.lesnikowski.com/blog/index.php/update-nuspec-version-from-msbuild/
You can also try //*:version. This will select all version elements regardless of namespace.
I had exactly the same problem with NuGet, XmlUpdate, MSBuild and XPath.
In the end I switched to the NuGetPack task of the MSBuild Community Tasks project.
(Note that the NuGet tasks are (at least for right now) only available in the Nightly Build)
Adding the version number to your NuGet package via MSBuild using this task would then look somehow like the following snippet:
<Target Name="NuGet">
<GetAssemblyIdentity AssemblyFiles="$(BuildCompileDirectory)\$(AssemblyName).dll">
<Output TaskParameter="Assemblies" ItemName="AssemblyIdentities"/>
</GetAssemblyIdentity>
<NuGetPack
ToolPath="$(ToolsDirectory)"
WorkingDirectory="$(BuildCompileDirectory)"
File="$(SrcDirectory)\$(SolutionName).nuspec"
Version="%(AssemblyIdentities.Version)"/>
</Target>
Hope that helps!
Your task would need to look like this:
<XmlUpdate
Prefix="xmlsucks"
Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"
XmlFileName="$(PackageDir)\temp\OddEnds.Testing\OddEnds.Testing.nuspec"
XPath="/xmlsucks:package/xmlsucks:metadata/xmlsucks:version"
Value="%(OddEndsTestingAsmInfo.Version)" />
Feel free to change the prefix to whatever derogatory term you would like to use :-)

Resources