WebConfig Replacement CruiseControl.Net - web-config

I have to deploy my solutions in many environnement (dev,staging,..)
2 Options: replace the whole file of just sections. Solution on either of them would be appreciated
I made 4 differents files: appSettings.Staging.config, appSettings.Dev.config, connectStrings.Dev.config, connectStrings.Staging.config.
I want to replace those section in the web.config during deployment.
My msBuild Section looks like this
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>C:\Travail\erp.visual.webapp.erpportal</workingDirectory>
<projectFile>erp.visual.webapp.erpportal.sln</projectFile>
<buildArgs>/p:ProjectFile=$SolutionFile$ /t:TransformWebConfig /p:Configuration=Staging</buildArgs>
<targets>Build</targets>
<timeout>900</timeout>
<logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
How can i retrieve the "/p:Configuration=Staging" argument ? i try the folowing
<ItemGroup Condition=" '$(Configuration)' == 'Staging' ">
<WebConfigReplacementFiles Include="appSettings.Staging.config">
<Section>appSettings</Section>
</WebConfigReplacementFiles>
<WebConfigReplacementFiles Include="connectionStrings.Staging.config">
<Section>connectionStrings</Section>
</WebConfigReplacementFiles>
</ItemGroup>
But where do I place this section into the ccnet.config ?

Found a way to do this. i have a web.config per environnement. web.staging.config, web.test.config. web.uat.config and so on
In my ccnet.config file
<nant>
<executable>C:\nant\bin\nant.exe</executable>
<baseDirectory>C:\Travail\erp.visual.webapp.erpportal</baseDirectory>
<nologo>false</nologo>
<buildFile>C:\Program Files\CruiseControl.NET\server\build.xml</buildFile>
<targetList>
<target>buildAll</target>
</targetList>
<buildTimeoutSeconds>60000</buildTimeoutSeconds>
</nant>
In my build.xml file i use the copy file tag from Nant in a target tag
<copy file="${root.dir}\erp.visual.webapp.erpportal\web.staging.config"
tofile="${deploy.web.dir}\Web.config"
overwrite="true"
inputencoding="latin1"
outputencoding="utf-8">
</copy>

Related

Is there an MSBuild macro for build date/time?

Suppose I have a build script with a Target section like the following:
<Target Name="AssemblyVersionMAIN" Inputs="#(AssemblyVersionFiles)" Outputs="UpdatedAssemblyVersionFiles">
<Attrib Files="%(AssemblyVersionFiles.FullPath)" Normal="true"/>
<AssemblyInfo
CodeLanguage="CS"
OutputFile="%(AssemblyVersionFiles.FullPath)"
AssemblyProduct="$(ProductName)"
AssemblyTitle="$(ProductName)"
AssemblyCompany="$(CompanyName)"
AssemblyCopyright="© $(CompanyName) 2014" <!-- THIS LINE -->
AssemblyVersion="$(Major).$(Minor).$(Build).$(Revision)"
AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)"
AssemblyInformationalVersion="$(Major).$(Minor).$(Build).$(Revision)">
<Output TaskParameter="OutputFile" ItemName="UpdatedAssemblyVersionFiles"/>
</AssemblyInfo>
</Target>
At the moment, the year is static and has to be changed manually. Is there a simple way of replacing "2014" with something like $(Year)? I've checked the MSBuild reference but nothing jumps out at me.
Since you are using MsBuild 4 you could also use a property function for this, like e.g.:
<PropertyGroup>
<CurrentDate>$([System.DateTime]::Now.ToString(yyyy.MM.dd))</CurrentDate>
</PropertyGroup>
Just format the recieved date as you need it. There are also plenty of other functions available, see also http://msdn.microsoft.com/en-us/library/dd633440(v=vs.100).aspx.
Since I'm using MSBuild Community Tasks and MSBuild 4, I can substitute the following:
AssemblyCopyright="© $(CompanyName) $([System.DateTime]::Now.ToString(`yyyy`))"
which seems to work.

How to write AssemblyVersion to file using MSBuild?

FinalEdit: Despite relative directories not working in the first post, it worked if I simply removed the $(MsBuildThisFileDirectory) from the Exec line.
Edit2: I added the new targets to the DefaultTargets. Which now runs them by default. However, timing was now off with the postbuild command. I added <Exec Command="call $(MsBuildThisFileDirectory)documentation\tools\GenerateDocumentation.bat" IgnoreExitCode="false" /> to the target, but it gives an error that C:\Users\my is not a valid batch file because of the space which is actually C:\Users\my program\documentation\tools\GenerateDocumentation.bat. Putting quotes around the path gives me error MSB4025 that Name cannot begin with $.
Edit: I have tried stijn's code and it works when I explicitly run it from the command line using /t:RetrieveIdentities, but for some reason it doesn't seem to run otherwise.
I have been using Doxygen to generate documentation for my source code, however, I would like to be able to do it automatically. I wrote a simple .bat script to run Doxygen with my desired config file and compile the output into a .chm help file, but I have been unable to change the revision number automatically in Doxygen.
I was attempting to simply update the config file by adding a new line to the config file with the new revision number using MSBuild, but I have been unable to get anything to print or even create a new file when none is present.
The code I have so far I have gotten from other similar questions, but I cannot seem to get it to work.
<ItemGroup>
<MyTextFile Include="\documentation\DoxygenConfigFile.doxyconfig"/>
<MyItems Include="PROJECT_NUMBER = %(MyAssemblyIdentitiesAssemblyInfo.Version)"/>
</ItemGroup>
<Target Name="RetrieveIdentities">
<GetAssemblyIdentity AssemblyFiles="bin\foo.exe">
<Output TaskParameter="Assemblies" ItemName="MyAssemblyIdentities"/>
</GetAssemblyIdentity>
<WriteLinesToFile File="#(MyTextFile)" Lines="#(MyItems)" Overwrite="false" Encoding="UTF8" />
</Target>
Encoding is wrong, it should be UTF-8
When working with items/properties, the % and # and $ must come right before the (, no spacing in between: %(MyAssemblyIdentitiesAssemblyInfo.Version)
MyAssemblyIdentitiesAssemblyInfo does not exist, you probably meant MyAssemblyIdentities
Look up how msbuild evaluates properties and items. Basically what it will do in your script is evaluate MyItems, but at that time MyAssemblyIdentities does not yet exist so is empty, and only afterwards the GetAssemblyIdentity gets executed. Fix this by enforcing correct evaluation order: put your items inside the target and make it depend on another target that creates MyAssemblyIdentities before evaluating your items.
To summarize:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="GetAssemblyIdentities">
<GetAssemblyIdentity AssemblyFiles="bin\foo.exe">
<Output TaskParameter="Assemblies" ItemName="MyAssemblyIdentities"/>
</GetAssemblyIdentity>
</Target>
<Target Name="RetrieveIdentities" DependsOnTargets="GetAssemblyIdentities">
<ItemGroup>
<MyTextFile Include="\documentation\DoxygenConfigFile.doxyconfig"/>
<MyItems Include="PROJECT_NUMBER = %(MyAssemblyIdentities.Version)"/>
</ItemGroup>
<WriteLinesToFile File="#(MyTextFile)" Lines="#(MyItems)"
Overwrite="false" Encoding="UTF-8" />
</Target>
</Project>
Note this will only work if you invoke msbuild in the directory where the script is, else the paths (documentation/foo) will be wrong. That could be fixed by using eg $(MsBuildThisFileDirectory)\bin\foo.exe)

NetBeans: Run Target to execute an external bat file

I have a JavaHelp project and I have a bat file that basically runs a jhindexer (to create help index).
I would like to make it so that every time I make a build (Run>Target>Other target>Final build - it would run the jhindexer bat on pre-compile. Unfortunately I can't seem to get it working.
Here is my build.xml bit:
<target name="-pre-compile">
<echo message="Creating index"/>
<property name="createIndex" value="${basedir}\" />
<echo>${createIndex}</echo>
<!--<exec command="cmd /C createIndex.bat" />--> //Says its deprecated
<exec dir="${createIndex}" executable="createIndex.bat">
<arg file="cmd createIndex.bat" />
</exec>
</target>
This code gives me:
Creating index
Y:\NetBeansProjects\JavaHelp\
Y:\NetBeansProjects\JavaHelp\build.xml:79: Execute failed:
java.io.IOException: Cannot run program "\createIndex.bat" (in directory "Y:\NetBeansProjects\JavaHelp"): CreateProcess error=2, The system cannot find the file specified
If I change it to:
<exec command="cmd /C createIndex.bat" />
Creating index
Y:\NetBeansProjects\JavaHelp\
The command attribute is deprecated.
Please use the executable attribute and nested arg elements.
I can't seem to figure out a way to run the bat file...
Edit 1:
here is the contents of the bat file:
cd src\helpsetproject
..\..\javahelp\bin\jhindexer topics
It basically goes from basedir too the folder where Images, Topics folders are. Then I run jhindexer (which is in basedir\javahelp\bin) and give it topics (name of folder in the director i am in) as a parameter I guess. It works standalone, but not from Run Target in NetBeans.
Try this:
<target name="-pre-compile">
<echo message="Creating index"/>
<property name="createIndex" value="${basedir}\" />
<echo>${createIndex}</echo>
<exec dir="${createIndex}" executable="cmd">
<arg line="/c createIndex.bat" />
</exec>
</target>

Iterating file structure in Phing and compressing with YUICompressor

I have a directory structure like so:
-css
---subdir1
------common.css
---subdir2
------common.css
------custom.css
---subdir3
------common.css
------styles.css
I'm trying to loop each directory in Phing, and subsequently minify each file into a single hashed filename within each directory using the YUI compressor. The result would look something like this:
-css
---subdir1
------1973a613f7c87b03dbe589e6935a09bd.min.css
---subdir2
------1973a613f7c87b03dbe589e6935a09bd.min.css
---subdir3
------1973a613f7c87b03dbe589e6935a09bd.min.css
I therefore need to know each directory that I'm within so I can output my minified scripts to it.
These are my two targets:
<target name="minify">
<echo msg="Minifying CSS and JS files with YUI at ${yuicompressor}" />
<foreach param="filename" absparam="absfilename" target="runyui">
<fileset dir="${publicdir}/css">
<include name="*.css" />
<include name="**/*.css" />
</fileset>
</foreach>
</target>
<target name="runyui">
<filehash file="${abspathtopwd}" hashtype="MD5" propertyname="filehash" />
<echo msg="java -jar ${yuicompressor} -v --line-break 5000 --type css ${absfilename} >> ${abspathtopwd}/${filehash}.min.css" />
<exec command="java -jar ${yuicompressor} -v --line-break 5000 --type css ${absfilename} >> ${abspathtopwd}/${filehash}.min.css" />
</target>
Where:
yuicompressor is the path to the yui compressor jar
publicdir is just an absolute path to my applications public directory
abspathtopwd is the property I wish to use for the "current iteration's directory"
How can I get the current working directory (or pwd if you prefer) in the current foreach iteration with Phing? All I can see I have access to is the relative and absolute paths to the files themselves.
Note: I'm aware that this current solution would create a new file for each input file, but that's what I'm aiming to fix with abspathtopwd.
Thanks!
For anyone interested in this problem, check out this post, which led me to:
<foreach param="dir" absparam="absdir" target="minify.directory">
<fileset dir="${publicdir}/css">
<type type="dir" />
<depth max="0" min="0" />
</fileset>
</foreach>
This allows me to specify a directory constraint when iterating, thus passing through the relative and absolute directory name as opposed to the filename.

MSBuild ReadLinesFromFile all text on one line

When I do a ReadLinesFromFile on a file in MSBUILD and go to output that file again, I get all the text on one line. All the Carriage returns and LineFeeds are stripped out.
<Project DefaultTargets = "Deploy"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<ItemGroup>
<MyTextFile Include="$(ReleaseNotesDir)$(NewBuildNumber).txt"/>
</ItemGroup>
<Target Name="ReadReleaseNotes">
<ReadLinesFromFile
File="#(MyTextFile)" >
<Output
TaskParameter="Lines"
ItemName="ReleaseNoteItems"/>
</ReadLinesFromFile>
</Target>
<Target Name="MailUsers" DependsOnTargets="ReadReleaseNotes" >
<Mail SmtpServer="$(MailServer)"
To="$(MyEMail)"
From="$(MyEMail)"
Subject="Test Mail Task"
Body="#(ReleaseNoteItems)" />
</Target>
<Target Name="Deploy">
<CallTarget Targets="MailUsers" />
</Target>
</Project>
I get the text from the file which normally looks like this
- New Deployment Tool for BLAH
- Random other stuff()""
Coming out like this
- New Deployment Tool for BLAH;- Random other stuff()""
I know that the code for ReadLinesFromFile will pull the data in one line at a time and strip out the carriage returns.
Is there a way to put them back in?
So my e-mail looks all nicely formatted?
Thanks
The problem here is you are using the ReadLinesFromFile task in a manner it wasn't intended.
ReadLinesFromFile Task
Reads a list of items from a text file.
So it's not just reading all the text from a file, it's reading individual items from a file and returning an item group of ITaskItems. Whenever you output a list of items using the #() syntax you will get a separated list, the default of which is a semicolon. This example illustrates this behavior:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<ItemGroup>
<Color Include="Red" />
<Color Include="Blue" />
<Color Include="Green" />
</ItemGroup>
<Target Name="Build">
<Message Text="ItemGroup Color: #(Color)" />
</Target>
</Project>
And the output looks like this:
ItemGroup Color: Red;Blue;Green
So while the best solution to your problem is to write an MSBuild task that reads a file into a property as a string an not a list of items, that's really not what you asked for. You asked if there was a way to put them back, and there is using MSBuild Transforms.
Transforms are used to create one list from another and also have the ability to transform using a custom separator. So the answer is to transform your list read in using ReadItemsFromFile into another list with newlines. Here is an example that does just that:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<ItemGroup>
<File Include="$(MSBuildProjectDirectory)\Test.txt" />
</ItemGroup>
<Target Name="Build">
<ReadLinesFromFile File="#(File)">
<Output TaskParameter="Lines" ItemName="FileContents" />
</ReadLinesFromFile>
<Message Text="FileContents: #(FileContents)" />
<Message Text="FileContents Transformed: #(FileContents->'%(Identity)', '%0a%0d')" />
</Target>
</Project>
Test.text looks like:
Red
Green
Blue
And the output looks like this:
[C:\temp]:: msbuild test.proj
Microsoft (R) Build Engine Version 3.5.21022.8
[Microsoft .NET Framework, Version 2.0.50727.1433]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 11/8/2008 8:16:59 AM.
Project "C:\temp\test.proj" on node 0 (default targets).
FileContents: Red;Green;Blue
FileContents Transformed: Red
Green
Blue
Done Building Project "C:\temp\test.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.03
What's going on here is two things.
#(FileContents->'%(Identity)', '%0a%0d')
We are transforming the list from one type to another using the same values (Identity) but a custom separator '%0a%0d'
We are using MSBuild Escaping to escape the line feed (%0a) and carriage return (%0d)
If you are using MSBuild 4.0, you can do the following instead, to get the contents of a file:
$([System.IO.File]::ReadAllText($FilePath))
Instead of #(FileContents->'%(Identity)', '%0a%0d') I believe you can do #(FileContents, '%0a%0d')
You can use WriteLinesToFile combined with
$([System.IO.File]::ReadAllText($(SourceFilePath))):
< WriteLinesToFile File="$(DestinationFilePath)" Lines="$([System.IO.File]::ReadAllText($(SourceFilePath)))"
Overwrite="true"
/>
This will copy your file exactly at it is.