MSBUILD script should zip all assemblies in solution after build, but only gets some DLLs (under local and TFS build) - tfs

I want to set up my VS solution so at the end of the build, the installable files are zipped up for easy distribution. This should work under either a local build, or a TFS build. This is set up as follows:
There is one project (called MyApp.Packaging) which contains no code, just an MSBUILD .targets script
The project has references to all other projects, so builds last (confirmed by looking at the Project Build Order)
The build script contains the following to identify and zip (using MSBUILD Community Tasks' ZIP task) the EXE and DLLs into two different packages (there is other code to pull the version number from a version.txt file using MSBUILD Community Tasks - omitted for clarity)
<!-- Set package name and input/output folders -->
<PropertyGroup>
<PackageName>MyAppService</PackageName>
<BuildTargetFolder>$(TargetDir)</BuildTargetFolder>
<PackageOutputFolder>$(OutDir)</PackageOutputFolder>
</PropertyGroup>
<!-- Set location of files -->
<ItemGroup>
<MyAppBinaries Include="$(BuildTargetFolder)*.exe$(BuildTargetFolder)*.dll;" Exclude="$(BuildTargetFolder)MyApp.Packaging.dll" />
<MyAppOtherFiles Include="$(SolutionDir)MyApp.Packaging\InstallService.bat;$(SolutionDir)MyApp.Packaging\UnInstallService.bat;$(BuildTargetFolder)MyApp.HostService.exe.config" />
<MyAppContracts Include="$(BuildTargetFolder)MyApp.Common.DataContext.dll;$(BuildTargetFolder)MyApp.Common.Shared.dll" />
</ItemGroup>
<!-- After building (in Release mode only), build the installation package -->
<Target Name="AfterBuild">
<CallTarget Targets="BuildPackage" Condition="'$(Configuration)'=='Release'" />
</Target>
<!-- Build the package -->
<Target Name="BuildPackage">
<!-- Package for installing the MyApp Service -->
<Zip Files="#(MyAppBinaries);#(MyAppOtherFiles)" Flatten="True" WorkingDirectory="$(MSBuildProjectDirectory)" ZipFileName="$(PackageOutputFolder)\$(PackageName)_$(Major).$(Minor).$(Revision)_Install.zip" />
<!-- Package for MyApp Contracts -->
<Zip Files="#(MyAppContracts)" Flatten="True" WorkingDirectory="$(MSBuildProjectDirectory)" ZipFileName="$(PackageOutputFolder)\$(PackageName)_MyAppContracts_$(Major).$(Minor).$(Revision)_Install.zip" />
</Target>
The ZIP files are created in the TFS drop location when TFS does the build, or the Packaging project's bin folder for a local build.
The second ZIP (containing 2 DLLs) always gets created OK, under local and TFS build.
The problem is that when TFS does the build, the first ZIP contains no EXE and only 2 of the 23 DLLs (and all 3 of the files identified by MyAppOtherFiles). When the build is done locally (and the the Packaging project's bin folder is emptied first), the first ZIP contains no EXE or DLLs, and only the 2 .bat files identified by MyAppOtherFiles.
If I change BuildTargetFolder from $(TargetDir) to $(OutDir), I get the same result.
The TFS build definition uses an unmodified Default Template.
It is as if when TFS does the build, the Packaging project is the 3rd project to be built, rather than the last, therefore only zipping 2 DLLs. However, the solution checked into TFS is exactly the same as what I build locally, and in that case it seems the script cannot see ANY of the binaries. If the local build is done again (without emptying the Packaging project's bin folder), the ZIPs then contain all the required files, but this is obviously because after the 1st build the bin folder now contains the EXE & all the DLLs.
Its also confusing that under a TFS build the MyApp.HostService.exe.config (which is produced by the build) is zipped, but not the MyApp.HostService.exe. And why is the 2nd ZIP always created OK, when it contains DLLs that are skipped in the 1st ZIP ????? I have tried swapping the order the ZIPs are created, but it makes no difference!
What can I do to ensure that the zipping is always done after all the projects are built, under both local and a TFS build?
Thanks

Make sure you set the packaging project dependency on the solution depend on the other projects this way it will always build the others first, thus leaving you with the packaging last.

We do something similar but we have our tfs build definition setup to build the targets/proj file instead of the sln. In the targets/proj file we have a target that compiles our application and then uses wix to create a msi. In your case, you should create a target that uses the msbuild target to compile your exe project and then call the zip target to compress the output. You can leave the outdir parameter as is our you can set the property so the output goes to a directory of your choosing. Building this easy will work on both the tfs server and locally.

Related

Buildiling .net multiple Solutions in Jenkins using MSBuild plugin

I am trying to build .net multiple Solutions files in Jenkins using MSBuild plugin. I have installed and configured MSBuild. In the Build step - 'Build a Visual Studio project or Solution using MSBuild', under 'MSBuild Build FIle' how do we reference the build file(ex, test.txt) which have 5 solution file paths in it. When i give the path directly C:\test.txt, the build is failing with error
C:\test.txt(1,1): error MSB4025: The project file could not be loaded. Data at the root level is invalid. Line 1, position 1.
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:02.22
Build step 'Build a Visual Studio project or solution using MSBuild' marked build as failure
Finished: FAILURE
Below are the solution file paths mentioned in my test.txt file
C:\workspace\DotNet\Constants.sln
C:\workspace\DotNet\Security.sln
C:\workspace\DotNet\Library.sln
C:\workspace\DotNet\Mapping.sln
C:\workspace\DotNet\MapForce.sln
Could I build by mentioning five solution file paths in .txt file and referring the .txt file path by just using one 'Build a Visual Studio project or solution using MSBuild section'?
I have tried with command prompt manually it builds fine. Also, tried with 'Execute Windows batch command' option by batch commands it works fine and builds successfully, facing problem with 'Build a Visual Studio project or solution using MSBuild' when spefiying .txt file which has many solution file paths in it.
Appreciate your help on this.
MSBuild builds MSBuild files, written in xml, not text files (hence the error MSB4025). Luckily creating a file which can be used to build x other files is fairly simple, here is an example:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<ItemGroup>
<Sln Include="C:\workspace\DotNet\Constants.sln"/>
<Sln Include="C:\workspace\DotNet\Security.sln"/>
<Sln Include="C:\workspace\DotNet\Library.sln"/>
<Sln Include="C:\workspace\DotNet\Mapping.sln"/>
<Sln Include="C:\workspace\DotNet\MapForce.sln"/>
</ItemGroup>
<Target Name="Build">
<MsBuild Projects="#(Sln)" Targets="Build" Properties="Configuration=Release;Platform=Win32" BuildInParallel="True" />
</Target>
</Project>
This is just written in a straightforward way, shorter but possibly more complicated code might apply. E.g. to just build all solutions in the C:\workspace\DotNet directory you'd just write <Sln Include="C:\workspace\DotNet\*.sln"/> instead of manually spelling out each of them. Or if all of them reside in that directory you could include them by filename only, e.g. <Sln Include="Constants.sln"/> and then add the directory when expanding the list like Projects="#(Sln->'c:\workspace\dotnet\%(Identity)')".
As you can see this builds the Win32|Release version, change that by altering the properties. Also not the BuildInParallel switch: only use this if the solutions don't depend on each other.

sfproj - outpath Build error

Iam trying to build the sfproj using msbuild on my build machine , This is what Iam doing.
<target ="package">
<foreach item="File" property="sfproj">
<in>
<items refid="servicefabric.files.sfproj" />
</in>
<do>
<exec program="${msbuild14.exe}">
<arg value="${sfproj}" />
<arg value="/p:Configuration=${config}" />
<arg value="/p:Platform=x64" />
<arg value="/target:Package" />
</exec>
</do>
</foreach>
</target>
The error Iam getting on the build machine is
(_CheckForInvalidConfigurationAndPlatform target) ->
10:25:10 [exec] C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(724,5): error : The OutputPath property is not set for project 'App.sfproj'. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='Debug' Platform='x64'. You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project.
It appears that the Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.1.0 Nuget package contains an MSBuild target that skips building of the sfproj itself (that or makes certain options present in order for it to succeed).
In my case I had accidentally checked in some Nuget package folders into source control that were incomplete. Visual Studio saw the presence of the folder so it didn't try to redownload it. You need to make sure that the build folder is present and it contains an MSBuild target file. Your best bet is just to delete the packages folder entirely to ensure you're starting off with a fresh start.
https://ijustwrite.software/2016/07/20/ouputpath-property-not-set/
I ran into a problem with the same symptoms. It happened to me after upgrading the Azure SDK, but it seems to me that it could easily happen in a few ways. The trouble is that there are two paths in the sfproj file that lead into the directory where nuget packages are stored, oddly enough on the first and last line of the file. This causes problems because you may have overridden where nuget packages are stored (this is not at all uncommon). Since these are relative paths, it's easy for nuget to get the packages to where you have specified, but for the lines in the project to point to "..\packages" instead, which makes Visual Studio want to restore the packages, but to never think they have been restored as it's looking for them in the wrong place.
To fix it all you need to do is modify the paths in the sfproj file to point to wherever you have your nuget packages set to download (this setting is in the nuget.config file, which can be in any directory above your project directory).
These are the two broken lines in my sfproj file:
<Import Project="..\packages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.props" Condition="Exists('..\packages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.props')" />
<Import Project="..\packages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.targets" Condition="Exists('..\packages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.targets')" />
Since I have the value ThirdPartyLibraries\NuGetPackages in my nuget.config file (which is two directories above my project file), these lines had to be modified to be the following in order to work again :
<Import Project="..\..\ThirdPartyLibraries\NuGetPackages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.props" Condition="Exists('..\..\ThirdPartyLibraries\NuGetPackages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.props')" />
<Import Project="..\..\ThirdPartyLibraries\NuGetPackages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.targets" Condition="Exists('..\..\ThirdPartyLibraries\NuGetPackages\Microsoft.VisualStudio.Azure.Fabric.MSBuild.1.3.0\build\Microsoft.VisualStudio.Azure.Fabric.Application.targets')" />
And that fixes it right up. I was lucky: I had two sfproj files, one with this issue, and one without, so all I had to do was diff to see the trouble.

How to include config transform files in web application filesystem publish output

I've been pulling my hair out on this for a while now. I'm trying to implement a continuous integration and deployment pipeline using TeamCity and Octopus Deploy. I am 99% there, except for one problem. I am using the standard msbuild runner of teamcity, configured to use the version 12 of msbuild.
I need to include the web.config transforms in the published output so they can be packaged into a nuget package for octopus deploy. I do not want the transforms to be applied by msbuild.
I am not using Octopack to create packages. I'm using the built-in teamcity nuget packager. So I'm publishing the website to a filesystem folder and then creating the package from the files in this folder. However, no matter what I do I cannot get msbuild to include the web.config transform files in the publish (I am using Octopus Deploy to perform the transforms, so I don't want msbuild to perform them).
I have verified that all the transform files (Web.Release.config, etc..) are marked as "Content". I have NOT marked them to copy always, because doing this copies them to the bin folder, not the root folder where they belong.
I have removed the /p:Configuration= property from the msbuild command line as I've read that is required for transforms to be applied. my parameters to msbuild look like this:
/p:DeployOnBuild=true /p:PublishProfile=Deployment
There is nothing in the publish profile that seems to relate to transforms. The publish profile contains the filesystem location to publish to.
Any suggestions here?
Note: I've given up and found a different solution, but I'm leaving this open in case anyone has any input.
You could create a custom .nuspec file and reference the files that you want to include from there.
My suggestion would be to have the .nuspec file in the same directory as the web.config / web.release.config files, and make the paths relative from there.
So if you publish to a directory called /output you could use rules like this
<files>
<file src="*.config" target="\" />
<file src="publish\*.*" target="\" />
</files>
So nuget pack nuspecPath would become the way to pack the project
NuSpec Reference
Hope this helps

How to build solr.tgz file from source using "ant package"

I want to build a .tgz distribution file from solr.
The build.xml file tells me to use "ant package".
However, running ant package gets everything from svn and builds ./package/solr-6.0.0-SNAPSHOT.zip whereas my code base is from lucene_4_10_x branch.
How do I build ./package/solr-4.10.3.zip from the source code?
I need to build from the source code because I have some local changes that I want to compile and deploy.
According to LUCENE-4288, Solr will only package properly if it's checked out from SVN by default. However, if you change package-src-tgz to package-local-src-tgz, it will properly package. Find the following lines in solr/build.xml:
<!-- make a distribution -->
<target name="package" depends="package-src-tgz,..."/>
And change package-src-tgz to package-local-src-tgz.
<!-- make a distribution -->
<target name="package" depends="package-local-src-tgz,..."/>
Then just rerun ant package inside solr/, and the packaged archives (solr-<version>-SNAPSHOT.tgz and solr-<version>-SNAPSHOT.zip) will be available under solr/package/.

Overriding the PostBuildEvent in TFSBuild.proj

I'm using currently VS 2010 and TFS 2008. In one of our solutions we have a .csproj file with the following:
<Target Name="BeforeBuild">
<TransformXml Source="..\..\..\ProjectX\ProjectXWebSite\ProjectXWebSite\Web.config" Transform="..\..\..\ProjectX\ProjectXWebSite\ProjectXWebSite\Web.$(Configuration).config" Destination="..\..\..\ProjectX\ProjectXWebSite\ProjectXWebSite\Web.$(Configuration).config.transformed" />
</Target>
<PropertyGroup>
<PostBuildEvent>xcopy "C:\Source\Projects\ProjectX\ProjectXWebSite\ProjectXWebSite\Web.$(Configuration).config.transformed" "C:\Source\Projects\ProjectX\ProjectXWebSite\ProjectXWebSite\Web.config" /R /Y</PostBuildEvent>
</PropertyGroup>
This works fine when building locally, but TFS is failing when it reaches <PostBuildEvent>, because this path is not available on the build machine. How can I get TFS to either skip the entire "BeforeBuild" or just set the <PostBuildEvent> to an empty string, so that the build will work successfully when built locally in VS2010 and via TFS 2008? I've tried within TFSBuild.proj to set <Target Name="BeforeBuild" />, but this doesn't work.
I'd recommend against using absolute pathnames in your projects - relative paths will make them relocatable and headaches like this will disappear.
i.e. In the post-build xcopy, just change C:\Source\Projects\ProjectX to ..\..\..\ProjectX
(You can't rely on always being able to put your code on C: - I've had to move my code from C: to D: or E: due to lack of disk space or installation of a new drive on several occasions, and using relative paths has made this process very easy. It's also very handy at times to be able to have multiple copies (different versions or branches) of your source code on your PC at once and still be able to build them all)

Resources