Buildiling .net multiple Solutions in Jenkins using MSBuild plugin - jenkins

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.

Related

How to prevent msbuild config transforms in particular environments?

I have a azure webjob project that uses config transforms to create dev/test/release configuration. We are using TFS for CI/CD deployment to Azure. I want to have MSBuild apply the transforms for dev so we can debug locally. However, when we are building in TFS in the CI/CD pipeline I need to disable the config transforms during the build step.
TFS has an "apply XML transformations" checkbox in the release step, which is where we want the transforms applied since we have the environment variable set during release. Unfortunately, this is not working because the transforms are already applied during build so the release artifact only has the finished output file, not the separate transform files.
I have tried editing the .csproj file to disable the transforms. I assume the transforms are being performed by the following section of the project file:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterCompile" Condition="Exists('App.$(Configuration).config')">
<!--Generate transformed app config in the intermediate directory-->
<TransformXml Source="App.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="App.$(Configuration).config" />
<!--Force build process to use the transformed configuration file from now on.-->
<ItemGroup>
<AppConfigWithTargetPath Remove="App.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>
<!--Override After Publish to support ClickOnce AfterPublish. Target replaces the untransformed config file copied to the deployment directory with the transformed one.-->
<Target Name="AfterPublish">
<PropertyGroup>
<DeployedConfig>$(_DeploymentApplicationDir)$(TargetName)$(TargetExt).config$(_DeploymentFileMappingExtension)</DeployedConfig>
</PropertyGroup>
<!--Publish copies the untransformed App.config to deployment directory so overwrite it-->
<Copy Condition="Exists('$(DeployedConfig)')" SourceFiles="$(IntermediateOutputPath)$(TargetFileName).config" DestinationFiles="$(DeployedConfig)" />
</Target>
I tried adding conditions like "$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" to these sections, and it did not help (the transforms still got applied in all three environments). I even commented this section out completely, and I still got the transforms. This leaves me with three questions:
How can the config transforms be disabled?
How can I conditionally
disable them so they are still applied when debugging in VS?
Is this
the correct approach, or is there a better way to get the correct
transform applied when using CI/CD in TFS 2017?
To disable the config transform during the build, you just need to add argument /p:TransformWebConfigEnabled=False in MSBuild Arguments section of your Build task. You also need to add /p:AutoParameterizationWebConfigConnectionStrings=False if you want to update the connection string during the release.
Besides, you need to update your project file so that the Web.XXX.Config file will be included in the package if you are generating msdeploy package for deployment.
Change the "Build Action" of the config file from "None" to "Content".
Unload your project file and remove <DependentUpon> tag for the config file.
With these "MSBuild Arguments" it works for me:
/p:AutoParameterizationWebConfigConnectionStrings=false
/p:DeployOnBuild=true
/p:MarkWebConfigAssistFilesAsExclude=false
/p:PackageAsSingleFile=false
/p:PackageLocation="$(build.artifactstagingdirectory)\\"
/p:ProfileTransformWebConfigEnabled=false
/p:SkipInvalidConfigurations=true
/p:TransformWebConfigEnabled=false
/p:WebPublishMethod=FileSystem
The important ones:
/p:AutoParameterizationWebConfigConnectionStrings=false
/p:MarkWebConfigAssistFilesAsExclude=false
/p:ProfileTransformWebConfigEnabled=false
/p:TransformWebConfigEnabled=false
It started to work when I also added:
/p:ProfileTransformWebConfigEnabled=false
Thanks to #Eddie Chen - MSFT & #Wessel T.
Regards Hans

TFSBuild.proj import common targets after getting from source control

I am currently rewriting/cleaning up our TFS Builds, and I have noticed that we have a lot of duplication. I was wanting to create a "Common.targets" file which all our tfs builds (about 30) would then import.
I have tried a few things along these lines of:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft.Sdc.Common.Tasks"/>
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Import Project="$(BuildDefinition).proj"/>
<PropertyGroup>
<ProjectName>Felix.LincsPublishingHandlers</ProjectName>
</PropertyGroup>
<Import Project="$(BuildDirectory)/src/BuildScripts/Common/CommonTargets.targets"/>
</Project>
Where:
$(BuildDefinition).proj -> contains project/environment specific properties (eg db connection strings, IP addresses)
CommonTargets.targets -> used across all the various projects. Defined in the Build Definition > Source Settings
However when I try to run on the TFS Build agent (version 2010 if anyone needs to know), it tries to run the statements before it has copied down the source files. So I get an error saying that the CommonTargets.targets file doesn't exist.
I've had a look around the web, and the solutions I have come across so far have suggestions that I would prefer not to use:
Copy the Common.targets file under into the same folder that has the TFSBuild.proj file
I have 20+ builds in different folders
I would like them all to use a single common.targets file (not 20 copies of the same file)
Copy the Common.targets file to a location on the build server(s) that the TFS Build Agents can access
I want to have it in source control with the rest of the build scripts and code.
As we are doing a sort of migration project, the Common.targets will change a bit over time, so best to have in source control
Has come across any similar issue of trying to import a Common.targets file that is kept in TFS source control?
Thanks for any help
First, you should consider upgrading TFS as mainstream support for TFS 2010 ends in a few months.
http://nakedalm.com/its-that-time-again-get-ready-to-upgrade-to-tfs-2015/
Second, you should consider updating your build system to use a modern method. Use the TFS 2013 template and PowerShell.

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

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.

How to use MSBuild with TFS and SSIS

I'm a complete novice in using TFS Build definition and MSBuild scripts.
I want to automate my SSIS build and deployments and create a build definition which will build and deploy my SSIS project whenever I queue it up.
I found this project: http://sqlsrvintegrationsrv.codeplex.com/releases/view/82369
which allows you to create a DLL which you can place in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies
Then you can call the SSIS.MSBuild.proj (See end for this) with certain parameters like this in a visual studio command line:
MSBuild SSIS.MSBuild.proj /t:SSISBuild,SSISDeploy /p:SSISProj="MySSISProject",Configuration="DEV",,SSISServer="AB-CDE-FGH-I1\DEV",ProjectName="MySSISProject"
or I can put it in a BAT file like this:
%systemroot%\Microsoft.Net\Framework\v4.0.30319\MSBuild.exe SSIS.MSBuild.proj /t:SSISBuild,SSISDeploy /p:SSISProj="MySSISProject",Configuration="DEV",,SSISServer="AB-CDE-FGH-I1\DEV",ProjectName="MySSISProject"
It works fine when you run the BAT file, it builds and deploys the SSIS project.
Questions:
How can I use this so it is automated, so I can manually kick off a build and deployment from within VS/TFS? Using a build definition.
How can I ensure the correct configurations are selected, and the correct destination server? For example we have SSIS configurations for DEV, SIT, SYS, UAT, PRD. Each with its own server name. Do I need a separate build definition for each environment or is there a way to use one build definition?
Anything useful in using powershell somehow?
Here is SSIS.MSBuild.proj:
<?xml version="1.0" encoding="Windows-1252"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="SSISBuild;SSISDeploy">
<!--Requires a property called $(SSISProj) to be defined when this script is called-->
<UsingTask TaskName="DeploymentFileCompilerTask" AssemblyFile="C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.SqlServer.IntegrationServices.Build.dll" />
<Target Name="SSISBuild" Condition="'$(SSISProj)' != ''">
<PropertyGroup>
<SSISProjPath>$(SSISProj)\$(SSISProj).dtproj</SSISProjPath>
</PropertyGroup>
<Message Text="**************Building SSIS project: $(SSISProjPath) for configuration: $(CONFIGURATION)**************" />
<DeploymentFileCompilerTask
InputProject="$(SSISProjPath)"
Configuration="$(CONFIGURATION)"
ProtectionLevel="DontSaveSensitive">
</DeploymentFileCompilerTask>
</Target>
<UsingTask TaskName="DeployProjectToCatalogTask" AssemblyFile="C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.SqlServer.IntegrationServices.Build.dll" />
<Target Name="SSISDeploy" Condition="'$(SSISProj)' != ''">
<Message Text="**************Publishing SSIS project: $(SSISProj) to: $(SSISServer) to folder: $(PROJECTNAME)**************" />
<PropertyGroup>
<ISPac>$(SSISProj)\bin\$(CONFIGURATION)\$(SSISProj).ispac</ISPac>
</PropertyGroup>
<DeployProjectToCatalogTask
DeploymentFile="$(ISPac)"
Instance="$(SSISServer)"
Folder="$(PROJECTNAME)"
CreateFolder="true"/>
</Target>
</Project>
EDIT I tried adding some MSBuild Arguments to the TFS Build Definition. I tried various combinations of arguments, some with quotes, some without. I couldn't get it to work.
"C:\Users\me\Desktop\Buildssis\SSIS.MSBuild.proj" /t:SSISBuild,SSISDeploy /p:SSISProj="MySSISProject",Configuration="SIT",SSISServer="AB-CDE-FGH-I1\DEV",ProjectName="MySSISProject"
But I always get this error:
MSBUILD : error MSB1008: Only one project can be specified.
Switch: C:\Users\me\Desktop\Buildssis\SSIS.MSBuild.proj
For switch syntax, type "MSBuild /help"
I think you are prety close about the solution. you can call your package in console application and set the variables there. And for different DEV, SIT, SYS, UAT, PRD. you can have configuration file for the the console application. and then you can set the package variables in the console app. I hope it solve the preoblem. As much i could understand.
Please let me know if this is not related to your problem then explain your question a bit more.
To answer your question, the best way would be to use an UpgradeBuildTemplate for your team build.
Modify the build script to calls the tasks that you have created in the "AfterCompile" target of the build. See below
http://msdn.microsoft.com/en-us/library/aa337604(v=vs.100).aspx
You can pass build parameters in your team build definition. If you edit your build definition and edit Process, you will see option to pass MSBuild Arguments.

Do I have to use a solution file with a Team Build definition?

Our application uses a combination of ASP.NET and Flex platforms.
I am able to successfully use the build service to build and deploy the .NET web site. That works fine. However, we also have our ActionScript files in TFS and I've created a batch file to successfully compile the ActionScript from the command-line.
I want to create two separate build definitions for the ASP.NET and Flex compilation. Flex obviously doesn't have an SLN file--can I create a build definition file from scratch to support the Flex compile batch file without a solution file? The tasks are fairly simple to create (see below), but I've never built a customized Team Build script without using the Create wizard--and the Create wizard expects you to supply a solution file, which I don't have.
My build script would be very straight-forward:
Get the latest version of the ActionScript files
Run the ActionScript compile batch file
Copy the ActionScript files to the deploy folder
Absolutely. TFSBuild.proj is an MSBuild file that calls your solution build in TFS. You can modify that to build whatever you want using MSBuild, which is the language which .vbproj and .csproj files are written in. There's a wealth of tasks that MSBuild allows you to use...
No you don't need a solution file in getting a build done using TFSBuild. A very simple project file could look like this (courtesy Aaron Hallberg):
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<Target Name="EndToEndIteration">
<Exec Command="SomeScript.cmd" />
</Target>
</Project>
Please investigate this page from Aarons blog. The default targets in a tfsbuild.proj file is actually defined in a "common" targets file and imported into the projfile by this instruction:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v8.0\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
If the import is removed you only need the EndToEndIteration target to get tfsbuild running....
All the best
/Niels

Resources