Set an incoming value to a new value - msbuild

How do I set an incoming value to a new value in msbuild?
Lets say I have this
msbuild /t:package /p:revision=2.2
in my msbuild file I want to change the revision to another value in another variable.
Let say I have:
$(Version)
I know want my Version value to set Revision value.
revision = Version
How?
Example
You get revision 1.0.0.0 in but want to set revision to what you have in your version?

You can do this by using PropertyGroups and Conditions. Save this MsBuild markup as "test.proj".
<Project DefaultTargets="VersionTest" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Version Condition="'$(Revision)' != ''">$(Revision)</Version>
<Version Condition="'$(Version)' == ''">0.0.0.0</Version>
</PropertyGroup>
<Target Name="VersionTest">
<Message Importance="high" Text="Revision is: $(Revision)" />
<Message Importance="high" Text="Version is: $(Version)" />
</Target>
</Project>
From a command prompt run msbuild.exe test.proj
VersionTest:
Revision is:
Version is: 0.0.0.0
Then run: msbuild test.proj /p:Revision=1.0.0.0
VersionTest:
Revision is: 1.0.0.0
Version is: 1.0.0.0

Related

Wix bootstrapper - Set version number in Bundle

I've got a Wix installer that uses a bootstrapper to launch my msi file. I've done this by calling a batch file as a post build event in my wix project. This then calls candle and light manually and passes various variables into the Bundle.wxs file. This all works and generates the exe which calls my msi file..
However, I now want to pass the msi BuildVersion into the bundle file. In the wxs file that creates the msi I am using the BuildVersion that I have setup in the BeforeBuild section, using the BuildVersion=%(AssemblyVersion.Version).
I cannot access this variable no matter what I try, in order to pass it to my build_bootstrapper.bat file. I can however pass in hardcoded values. I am currently setting up my own AssemblyVersionNumber enviornment variable as you can see below in the AfterBuild section:
<AssemblyVersionNumber Condition="'$(AssemblyVersionNumber)' == ''">$(BuildVersion)</AssemblyVersionNumber>
but it is empty by the time it gets to my script file (even though it's populated if hardcoded). I've tried everything.
Does anybody have any ideas of how I can get the %(AssemblyVersion.Version); to my command file from the post build step?
Thanks in advance
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="..\..\App\AppThing\bin\Release\AppThing.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version);</DefineConstants>
</PropertyGroup>
</Target>
<Target Name="AfterBuild">
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version);</DefineConstants>
<AssemblyVersionNumber Condition="'$(AssemblyVersionNumber)' == ''">$(BuildVersion)</AssemblyVersionNumber>
</PropertyGroup>
</Target>
<PropertyGroup>
<PreBuildEvent>$(ProjectDir)scripts\copy_services.bat $(SolutionDir) $(ProjectDir)</PreBuildEvent>
</PropertyGroup>
<Target Name="AfterClean">
<Message Text="Cleaning wix files, TargetDir is: $(TargetDir)" Importance="High" ContinueOnError="true" />
<CreateItem Include="$(TargetDir)\**\*.*">
<Output TaskParameter="Include" ItemName="BinFilesDir" />
</CreateItem>
<Delete Files="#(BinFilesDir)" />
</Target>
<PropertyGroup>
<PostBuildEvent>$(ProjectDir)scripts\build_bootstrapper.bat $(ProjectDir) $(ConfigurationName) $(AssemblyVersionNumber)</PostBuildEvent>
</PropertyGroup>
$(BuildVersion) isn't set to anything.
You're setting define constants to "BuildVersion=%(AssemblyVersion.Version)" but never actually defining a MSBuild property called "BuildVersion" so the value of $(BuildVersion) is "".
Use %(AssemblyVersion.Version).
<AssemblyVersionNumber Condition="'$(AssemblyVersionNumber)' == ''">%(AssemblyVersion.Version)</AssemblyVersionNumber>

MSBuild | Property Value Is Empty After Being Set

Background
I am very new to MSBUild and I am attempting to write an MSBuild script with a post build event. Prior to the post build event, I want to obtain some version information (the version itself, then each segment of the version).
Problem
I can get the version successfully, but when trying to set properties based on the parts of the version, the properties are blank.
Code
<PropertyGroup>
<PostBuildEventDependsOn>
$(PostBuildEventDependsOn);
PostBuildMacros;
</PostBuildEventDependsOn>
<PostBuildEvent>
if $(ConfigurationName) == Release (
// This shows the correct version
echo THE ASSEMBLY VERSION IS: #(VersionNumber)
// This is blank
echo THE MAJOR VERSION IS: $(MajorVersion)
)
</PostBuildEvent>
</PropertyGroup>
<Target Name="PostBuildMacros">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="Targets" />
</GetAssemblyIdentity>
<ItemGroup>
<VersionNumber Include="#(Targets->'%(Version)')" />
</ItemGroup>
<PropertyGroup>
<MajorVersion>$([System.Version]::Parse(%(Targets.Version)).Major)</MajorVersion>
</PropertyGroup>
</Target>

MSBuild property set in target is not visible in parent target

here is my targets file
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="BuildApp" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<TestInitResult>false</TestInitResult>
</PropertyGroup>
<Target Name="BuildApp">
<CallTarget Targets="TestInit" ContinueOnError="true"/>
<Message Importance="high" Text="2 Value of flag: $(TestInitResult)"/>
<CallTarget Targets="target2" />
<CallTarget Targets="RunBuild" Condition="'$(TestInitResult)'=='true'"/>
</Target>
<Target Name="TestInit">
<PropertyGroup>
<TestInitResult>true</TestInitResult>
</PropertyGroup>
<Message Importance="high" Text="1 Value of flag: $(TestInitResult)"/>
</Target>
<Target Name="target2">
<Message Importance="high" Text="Inside run target2"/>
</Target>
<Target Name="RunBuild">
<Message Importance="high" Text="Inside run build"/>
</Target>
</Project>
Output of msbuild:
D:\CQF>msbuild build.targets
Microsoft (R) Build Engine version 12.0.30501.0
[Microsoft .NET Framework, version 4.0.30319.34209]
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 7/31/2015 4:38:49 AM.
Project "D:\CQF\build.targets" on node 1 (default targets).
TestInit:
1 Value of flag: true
BuildApp:
2 Value of flag: false
target2:
Inside run target2
Done Building Project "D:\CQF\build.targets" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.06
The value of TestInitResult set in target "TestInit" is not visible in target "BuildApp" when it returns.
Please let me know how to make TestInitResult visible in parent target.
Or is there better approach to achieve the required result.
What I want to achieve is, first TestInit target should run, then target2 should run, and target RunBuild should run only if TestInit was successful. If TestInit failed, only run target2, skip RunBuild.
Thank you.

Automatically increment and synchronize version for product and bootstrapper

I'm trying to implement automatic versioning so that when I build my Bootstrapper, both the MyApp and Bootstrapper versions are automatically incremented and synchronized. Otherwise you end up with duplicate bootstrap entries in the add/remove programs for each installation attempt with matching versions.
When I build the bootstrapper, an AfterBuild target uses GetAssemblyIdentity to get the automatically generated version of MyApp successfully, and the bootstrapper output file is properly named with the incremented version number e.g. MyApp.1.0.5123.1352.exe
But, when I install this Bootstrapper, the version that shows in add/remove programs is always 1.0.0.0.
I've tried using bindings in the Bootstrapper Bundle Version field but I can't get it to read the MyApp version.
Using !(bind.packageVersion.MyApp) results in never incrementing 1.0.0.0.
Using !(bind.assemblyName.MyApp) results in build errors (Unresolved bind-time variable).
Using !(bind.FileVersion.filAAF013CA9B89B07C81031AE69884BF11) results in build errors (Unresolved bind-time variable). <-- Makes sense as the FileID exists in the Setup project, and this is the Bootstrapper project.
What can I do to get my Bootstrapper Bundle to have the same version
as the MyApp it is packaging?
=====MyApp\AssemblyInfo.cs=====
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.*")]
=====Setup.wixproj=====
<Target Name="BeforeBuild">
<PropertyGroup>
<LinkerBaseInputPaths>..\MyApp\bin\$(Configuration)\</LinkerBaseInputPaths>
</PropertyGroup>
<HeatDirectory OutputFile="MyApp_Files.wxs" Directory="..\MyApp\bin\$(Configuration)\" DirectoryRefId="INSTALLLOCATION" ComponentGroupName="MyApp_Project" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" AutoGenerateGuids="false" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" Condition="'%(ProjectReference.PackageThisProject)'=='True'" />
</Target>
=====Bootstrapper.wixproj=====
<Target Name="AfterBuild">
<GetAssemblyIdentity AssemblyFiles="..\MyApp\bin\$(Configuration)\MyApp.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<Copy SourceFiles=".\bin\$(Configuration)\$(OutputName).exe" DestinationFiles=".\bin\$(Configuration)\MyApp.%(AssemblyVersion.Version).exe" />
<Delete Files=".\bin\$(Configuration)\$(OutputName).exe" />
</Target>
=====Bootstrapper\Bundle.wxs=====
<Bundle Name="$(var.ProductName) Bootstrapper v!(bind.packageVersion.MyApp)"
Version="!(bind.packageVersion.MyApp)"
This is what I would do:
In my assembly I use auto versioning: AssemblyVersion("1.0.*")
In the setup project reference the version using binding to the assembly: !(bind.fileVersion.MyAssembly.dll) (MyAssembly.dll is the File/#Id of the assembly)
In the bundle using binding to the setup version:
!(bind.packageVersion.Setup) (Setup is the project name as is referenced in the bundle project.)
Got it!!! I didn't realize you can declare Variables aka DefineConstants in a BeforeBuild Target.
Below is an example BeforeBuild Target that generates a variable BuildVersion
Bundle.wxs:
<Bundle Name="$(var.ProductName) Bootstrapper v$(var.BuildVersion)"
Version="$(var.BuildVersion)"
Bootstrapper.wixproj:
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="..\MyApp\bin\$(Configuration)\MyApp.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version)</DefineConstants>
</PropertyGroup>
</Target>
<!-- This is extra, not needed: Renames output file with version number -->
<Target Name="AfterBuild">
<GetAssemblyIdentity AssemblyFiles="..\MyApp\bin\$(Configuration)\MyApp.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<Copy SourceFiles=".\bin\$(Configuration)\$(OutputName).exe" DestinationFiles=".\bin\$(Configuration)\MyApp.%(AssemblyVersion.Version).exe" />
<Delete Files=".\bin\$(Configuration)\$(OutputName).exe" />
</Target>

TeamCity MSBuild refer to build counter

I have a property group which includes a property for the build_number which is being passed in from TeamCity as solely the Build Counter. The build number format being set in TeamCity as simply {0} for the counter.
<PropertyGroup>
<Major>10</Major>
<Minor>1</Minor>
<Build>$(BUILD_NUMBER)</Build>
<Release>0</Release>
...
</PropertyGroup>
The Major, Minor and Release properties are then updated from values in a file in source control.
So that TeamCity logs the build as the full 4 part build reference (not just the counter), I set it thus:
<TeamCitySetBuildNumber BuildNumber="$(Major).$(Minor).$(Build).$(Release)" />
However, now when I reference my $(Build) property, it's now set to the 4 part build reference, and any property I have made which makes reference to $(BUILD_NUMBER) prior to setting using TeamCitySetBuildNumber also gets overwritten with the 4 part reference.
NB I've also changed it with a system message:
<Message Text="##teamcity[buildNumber '$(Major).$(Minor).$(Build).$(Release)']" />
but the overall effect is the same.
How Can I refer to the build counter (only) AFTER I have set the BuildNumber above?
If you're using a project file, you could try calling the TeamCitySetBuildNumber command in the AfterBuild section of the *.vbproj or *.csproj file:
<Target Name="AfterBuild">
<TeamCitySetBuildNumber BuildNumber="$(Major).$(Minor).$(Build).$(Release)" />
</Target>
If you're using a solution file, I'd create a *.proj file that calls your solution file and then after that call the TeamCitySetBuildNumber command (not sure if you can call the TeamCitySetBuildNumber command within the target like this though...):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="SetBuildNumber">
<PropertyGroup>
<Major>10</Major>
<Minor>1</Minor>
<Build>$(BUILD_NUMBER)</Build>
<Release>0</Release>
</PropertyGroup>
<Target Name="Build">
<Message Text="Build task called... " Importance="high"/>
<MSBuild Projects="$(teamcity_build_checkoutDir)\your_solution.sln" Properties="Configuration=Release"/>
</Target>
<Target Name="SetBuildNumber" DependsOnTargets="Build">
<Message Text="Setting build number back to TeamCity... " Importance="high"/>
<TeamCitySetBuildNumber BuildNumber="$(Major).$(Minor).$(Build).$(Release)" />
</Target>
</Project>