CruiseControl.net, send dynamic values to some files - web-config

I have been searching for a few days, I have also asked a question on the cc.net forum, but still don't have the answer.
My task is to fill Web.config with specific values during the building using cc.net. Here is the example:
I'm developing an ASP.NET website, I have a Web.config with some configuration, e.g. connection string:
<add name="ContextName" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=DatabaseName;User Id = UserName;Password=UserPassword;" providerName="System.Data.SqlClient" />
After the building I want to replace some values and make the config look like this:
<add name="ContextName" connectionString="Data Source=%SERVER%;Initial Catalog=%DATABASE%;User Id = %USER%;Password=%PASSWORD%;" providerName="System.Data.SqlClient" />
I tried this solution, but it didn't help me (or maybe I didn't understand how to use it properly).
Please help me to solve the task.
Thanks!

You can try to use this Config Transformation Tool which is XDT transformation command tool based on XDT (web.config) transform engine, which allows you to run XDT transformation on any XML files. You can use ccnet's task block to run it after your msbuild
<tasks>
<exec>
</exec>
</tasks>
More on ccnet executable task see here.
For more information on XDT transformation see this link in MSDN library

You can create a target on your build file to update the web.config and call that target after the build. I use something similar in my build files, here is an example:
<target name="update-config" >
<property name="export.config" value="" unless="${property::exists('export.config')}" />
<call target="${config-settings}" /> <!-- test or stage -->
<xmlpoke file="${export.config}" xpath="/configuration/appSettings/add[#key='ContextName']/#connectionString" value="${configValue.connectionString}" failonerror="true" />
</target>
<target name="test">
<property name="configValue.connectionString" value="test connection string here" />
</target>
<target name="stage">
<property name="configValue.connectionString" value="stage connection string here" />
</target>
After executing the target that compile your code and export you can run the target update-config, in this case I'm expecting a variable export.config with the path of the exported web.config then calling another target that sets the the value of the connectionstring variable (this can be target test or stage) and finally xmlpoke the web.config with the value.
Hope this helps!

Related

How to deploy different App.config values (with WiX)

I've been looking for a best practice recommendation on how to deploy an application with a WiX installer for different values in its App.config file. For example.
On my local development machine, I use App.config settings for our test environment:
<configuration>
<appSettings>
<WorkingDirectory>C:\Working</WorkingDirectory>
</appSettings>
<connectionStrings>
<add name="ApplicationEntities"
connectionString="[TestingConnectionString]"
providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
When I deploy to a test environment, those settings are acceptable. However, when we deploy to a production environment, I'd like them to be different. For example:
<configuration>
<appSettings>
<WorkingDirectory>\\prodserver\Working</WorkingDirectory>
</appSettings>
<connectionStrings>
<add name="ApplicationEntities"
connectionString="[ProductionConnectionString]"
providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
The answer to my question may very well be independent of WiX. But just in case, here is my WiX Product.wxs file's relavent fragment:
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="ProductComponent" Guid="{MY-GUID}">
<File Id="Application.exe"
Name="Application.exe"
Source="..\Application.exe"
Vital="yes"
KeyPath="yes"
DiskId="1" />
<File Id="Application.exe.config"
Name="Application.exe.config"
Source="..\Application.exe.config"
Vital="yes"
KeyPath="no"
DiskId="1" />
</Component>
</ComponentGroup>
</Fragment>
This setup ends with a manual edit of the App.config on the production server, which invites manual error. What would be a better way to handle this to accommodate an automated deployment?
I can think of two options, either deploy the app.config file and edit it using the XmlFile Element, or maintain multiple app.config files each representing your target environment, then deploy the appropriate file.
Here's an exmaple of both options, notice that I copy the file rather than just placing it on the file system. This serves two purposes, firstly you can see by the filename which one has been deployed, secondly if development.app.config and production.app.config are placed in the same location you will get an ICE30 validation error, by copying the file afterwards it avoids this error.
Notice also that I have a condition associated with the component, you'll need to decide how you identify which environment you are deploying to. Some ideas could be to use the machine name, the OU or simply pass it in on the command line as a property.
<Component Id="development.app.config" Guid="*">
<Condition>DEVELOPMENT</Condition>
<File Name="development.app.config" KeyPath="yes">
<CopyFile Id="development.app.config" DestinationName="app.config" />
</File>
<util:XmlFile
Id="WorkingDirectory"
Action="setValue"
File="app.config"
ElementPath="/configuration/appSettings"
Name="WorkingDirectory"
Value="C:\Working"
Permanent="no" />
</Component>
<Component Id="production.app.config" Guid="*">
<Condition>PRODUCTION</Condition>
<File Name="production.app.config" KeyPath="yes">
<CopyFile Id="production.app.config" DestinationName="app.config" />
</File>
<util:XmlFile
Id="WorkingDirectory"
Action="setValue"
File="app.config"
ElementPath="/configuration/appSettings"
Name="WorkingDirectory"
Value="\\prodserver\Working"
Permanent="no" />
</Component>

How can I let CruiseControl.NET/nant run all Unittest projects postfixed with .Test?

In our continuous integration setup, I would like to set up CruisControl.NET to automatically run all our unittests. However, I don't want to have to specify every unittest dll seperately in the configuration.
All the unittest projects are all postfixed with .Test (and all non-unittest projects are not). How can I configure CruiseControl.NET to run all the unittests from these projects (I am using v1.5.7256.1 of CruiseControl.NET)?
My current config attempt:
<nunit>
<path>$(nunit.path)</path>
<assemblies>
<assembly>$(working.dir)\**\*.Test.dll</assembly>
</assemblies>
</nunit>
I'm finding it very difficult to find documentation on this specific nunit element. Most pages I can find talk about using exec, nunit2 or another nunit element or the nunit-console commandline options.
I don't have much experience with managing the build environment and am working on an existing configuration where every assembly was specified separately in the following manner.
<nunit>
<path>$(nunit.path)</path>
<assemblies>
<assembly>$(artifact.dir)\test1.dll</assembly>
<assembly>$(artifact.dir)\test2.dll</assembly>
</assemblies>
</nunit>
Hence my failed attempt using wild cards.
EDIT:
Here is some extra xml of my configuration file to show the context a little bit:
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<project name="MyProject">
<!-- whole bunch of other elements -->
<tasks>
<nunit>
<!-- see above -->
</nunit>
</tasks>
</project>
</cruiscontrol>
After Mightmuke's suggestion, I tried replacing the <nunit> element with his suggestion, but got the following exception: Unable to instantiate CruiseControl projects from configuration document. Configuration document is likely missing Xml nodes required for properly populating CruiseControl configuration. Unable to load array item 'property' - Cannot convert from type System.String to ThoughtWorks.CruiseControl.Core.ITask for object with value: ""
Then I tried to move the <property> and <foreach> element outside the element. Then I get the exception: Unused node detected: <property name="nunit.filelist" value="" />
I'm now trying to find out more about the <foreach> element and where I can put that, but somehow I find it hard to find any documentation about it.
EDIT2:
I found the documentation of the nunit task I'm using: http://ccnet.sourceforge.net/CCNET/NUnit%20Task.html
I specifies the element to be of type String[]. I'm not sure what that means... but it seems from the example that it just means that it must contain a list of child elements of the same name in Singular form.
PS: I realize this question is getting a bit out of hand... When the whole thing is solved, I'll try to edit it in such a format so that it might be useful to someone else later.
This is an example configuration if you were to use the nunit console.
<property name="nunit.filelist" value="" />
<foreach item="File" property="testfile" verbose="true">
<in>
<items basedir=".">
<include name="${working.dir}\**\*.Test.dll" />
</items>
</in>
<do>
<property name="nunit.filelist" value="${nunitfile.list + ' ' + testfile}" />
</do>
</foreach>
<exec program="nunit-console-x86.exe" failonerror="true" verbose="true">
<arg value="${nunit.filelist}" />
<arg value="/xml=nunit-results.xml" />
<arg value="/nologo" />
<arg value="/nodots" />
</exec>
This hasn't been tested, and there are likely better ways to skin it, but it will hopefully provide a starting point for you.

NAnt ignoring property in included build file

I'm trying to make my project build file include a local build file, to allow for some customization for each developer, without having to keep exclulding the build file from version control commits etc.
But NAnt keeps ignoring the properties in my included build file, and not overwriting the properties set in the global build file.
For demo purposes this short build file behaves the same:
<project name="FooProject" default="showme" basedir="." >
<description>Foo</description>
<!-- Overwrite this property in local.build -->
<property name="database.connectionstring" overwrite="true" readonly="false" value="foo" />
<include buildfile="local.build" failonerror="true" verbose="true" />
<target name="showme" description="Show connectionstring variable">
<echo message="Connectionstring: ${database.connectionstring}" />
</target>
</project>
-and my local.build file looks like this:
<property name="database.connectionstring" value="bar" />
The expected output when running NAnt with this build file is "Connectionstring: bar", but the resulit is "Connectionstring: foo", no matter which combination of readonly and overwrite I try.
It does fail if I rename the file to something else, so NAnt is aware of the included file.
NAnt is v0.91 alpha.
Am I overlooking something or is NAnt not supposed to work like I expect?
It seems you should still wrap the contents of the included build file inside a project-element. Like so:
<project>
<property name="database.connectionstring" value="bar" />
</project>
When I did that the connectionstring was "bar".
Granted: I use Nant 0.91 final.

How to stop MSBuild _WPPCopyWebApplication target cleaning App_Data folder

I'm using the _WPPCopyWebApplication MSBuild target in a CruiseControl.net build-and-deploy script, but it appears that this target cleans files not part of the project before the deployment - specifically, App_Data files (which for this app, include uploaded images, etc).
From Microsoft.Web.Publishing.targets;
<OnBefore_WPPCopyWebApplication>
$(OnBefore_WPPCopyWebApplication);
CleanWebProjectOutputDir;
PipelineTransformPhase;
</OnBefore_WPPCopyWebApplication>
How can I stop it doing the CleanWebProjectOutputDir, given this target;
<Target Name="Deploy" DependsOnTargets="Tests">
<MSBuild Projects="$(TargetPath)Website.csproj" Properties="Configuration=Debug;WebProjectOutputDir=\\servername\share;Outdir=$(ProjectDir)bin\;" Targets="ResolveReferences;_WPPCopyWebApplication" />
</Target>
This is from a VS2010 solution, albeit built under CC.Net; I'm aware of MSDeploy, but haven't got my head around that fully yet, so would prefer to stick with MSBuild/_WPPCopyWebApplication for now.
EDIT:
I've further narrowed this to this part of the target;
<!-- In the case of the incremental Packaging/Publish, we need to find out the extra file and delee them-->
<ItemGroup>
<_AllExtraFilesUnderProjectOuputFolder Include="$(WebProjectOutputDir)\**" />
<_AllExtraFilesUnderProjectOuputFolder Remove="#(FilesForPackagingFromProject->'$(WebProjectOutputDir)\%(DestinationRelativePath)')" />
</ItemGroup>
<!--Remove all extra files in the temp folder that's not in the #(FilesForPackagingFromProject-->
<Delete Files="#(_AllExtraFilesUnderProjectOuputFolder)" />
So I guess the question becomes, how can I supress this specific Delete task, or at least add App_Data** to the _AllExtraFilesUnderProjectOuputFolder exclusions?
Add CleanWebProjectOutputDir=False to your properties:
<Target Name="Deploy" DependsOnTargets="Tests">
<MSBuild Projects="$(TargetPath)Website.csproj" Properties="Configuration=Debug;CleanWebProjectOutputDir=False;WebProjectOutputDir=\\servername\share;Outdir=$(ProjectDir)bin\;" Targets="ResolveReferences;_WPPCopyWebApplication" />
</Target>

MSBuild. Check if windows service is installed

I'm new to msbuild and currently I'm trying to create msbuild script that will deploy my C# windows service to remote test server.
I'm thinking about using sc.exe utility for this purpose. Reading about it I didn't find a way to check whether windows service is installed on a remote server. If the service is installed then I need to stop it and update necessary files, otherwise I need to register the service.
P.S. For release builds I plan to use WiX to create MSI package.
You need MSBuild Comminity Tasks.
In latest build exists an example in MSBuild.Community.Tasks.v1.2.0.306\Source\Services.proj.
It will solve first part of your question:
<PropertyGroup>
<MSBuildCommunityTasksPath>$(MSBuildProjectDirectory)\MSBuild.Community.Tasks\bin\Debug</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project="$(MSBuildProjectDirectory)\MSBuild.Community.Tasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="Test">
<CallTarget Targets="DoesServiceExist" />
<CallTarget Targets="GetServiceStatus" />
<CallTarget Targets="ServiceControllerStuff" />
</Target>
<Target Name="DoesServiceExist">
<ServiceQuery ServiceName="MSSQLServer123" MachineName="127.0.0.1" >
<Output TaskParameter="Exists" PropertyName="Exists" />
<Output TaskParameter="Status" PropertyName="ServiceStatus" />
</ServiceQuery>
<Message Text="MSSQLServer Service Exists: $(Exists) - Status: $(ServiceStatus)"/>
</Target>
<Target Name="GetServiceStatus">
<ServiceQuery ServiceName="MSSQLServer" MachineName="127.0.0.1">
<Output TaskParameter="Status" PropertyName="ResultStatus" />
</ServiceQuery>
<Message Text="MSSQLServer Service Status: $(ResultStatus)"/>
</Target>
<Target Name="ServiceControllerStuff">
<ServiceController ServiceName="aspnet_state" MachineName="127.0.0.1" Action="Start" />
<ServiceController ServiceName="aspnet_state" MachineName="127.0.0.1" Action="Stop" />
</Target>
Those MSBuild task is just a wrapper around .Net class ServiceController. Take a look for documentation to understand how it works and how you can configure it in details.
Second part includes installing service. For that purpose sc.exe suits very well.
A complete solution is posted here. May help future visitors.
Update: Link updated as the other blogging service went down.