How to copy a build to test server? - continuous-integration

Hope someone can assist me with this. Have TeamCity up and running and doing builds on various projects. I'd like to be able to copy/deploy a successful TeamCity ran build to a test server automatically.
I was thinking of using PowerShell to do this but, am open to other ideas. Can some provide me with info on how I can accomplish this.
Thanks.

I use WGet. Here are the instructions for forming the team city URL. You can do a WGet in powershell, but if you only wanted powershell for this functionality, you can just use a plain wget utility for windows.
EDIT: Here is an example from our QA deployment (names changed to protect the guilty):
"C:\Program Files (x86)\NcFTP\wget.exe" "http://teamcityserver.domain.com:8111/guestAuth/repository/download/bt6/.lastFinished/Artificat.ear"
The location of the wget isn't relevant, that is just where it happens to be. The guestAuth part of the parameter specifies the authentication type (in our case we enabled guest authorization to not have to bother with passwords - it is an internal server only anyway and protected by firewalls). The options are in the documentation I linked to.
The other interesting feature of the parameters is the bt6. That is the unique key of the build, and is different for every project. You can discover what it is by navigating the team city website to the configuration of that build - it will be there. There are also instructions for referencing the configuration by name, but we found that was too verbose to bother with.

I've been implementing this for our applications today. Using msbuild. I have found this very useful as we can add in custom steps such as modifying config files, archiving live builds and notifying people of changes.
Here is a build script you may find useful. It precompiles the application and then copies it into the deploy directory.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Deploy">
<PropertyGroup>
<WebsitePublishDirectory>Artifacts\Website</WebsitePublishDirectory>
<WebsiteDeployDirectory>\\SERVERNAME\Path\to\web\root</WebsiteDeployDirectory>
<WebsiteProject>[Project name here]</WebsiteProject>
</PropertyGroup>
<Target Name="Deploy">
<RemoveDir Directories="$(WebsitePublishDirectory)" />
<AspNetCompiler
VirtualPath="test"
PhysicalPath="$(WebsiteProject)"
TargetPath="$(WebsitePublishDirectory)"
Force="true"
Debug="false" />
<ItemGroup>
<PublishedFiles Include="$(WebsitePublishDirectory)\**" />
</ItemGroup>
<Copy SourceFiles="#(PublishedFiles)" DestinationFolder="$(WebsiteDeployDirectory)\%(RecursiveDir)" />
</Target>
</Project>

You could also install a TeamCity agent on the test server. That's actually how TeamCity was intented to be used.

I created a Post Build Script in Visual Studio like this:
c:\TeamCityBuild\pt_build.bat
exit 0
Then on the TC-server I have a .bat that looks like this:
net use r: \192.168.16.85\WebSite password /USER:domain.com\administrator
xcopy "C:\TeamCityBuild\path\WebSite*" "r:\" /R /Y /E
r: \192.168.16.85\WebSite /DELETE
if errorlevel 1 goto buildFAILED
:buildOK
echo Wehej!!!
exit 0
:buildFAILED
echo Oh NOOO!!!
exit 1
'R:' is a mapped drive to the test server.
The error handling is only needed to avoid script errors when someone builds the project on a environment without the correct folder structure.
So far everyting is working great!

Related

How to configure where NuGet.exe Command Tool line looks for packages

We have successfully set up a couple of local package repositories using the NuGet.Server package and hosted them on a local IIS webserver. We are able to connect from the Package Manager and install no problem. So these are working fine.
In order for us not to have to check in our packages folder we have included the following command line in each project file that includes NuGet references. This works, if the NuGet.exe is in the path on the CI build agent.
However, I would like to move the source configuration form the command line in every project file and put it in just one place, preferably where other pesky developers can't change it ;)
<Target Name="BeforeBuild">
<Exec Command="nuget install $(ProjectDir)packages.config -s
http://domain:80/DataServices/Packages.svc/;
http://domain:81/DataServices/Packages.svc/
-o $(SolutionDir)packages" />
</Target>
Is there a better way?
Yes there is ;-)
Take a look at NuGetPowerTools. After running Install-Package NuGetPowerTools, it adds a .nuget folder to your $(SolutionDir) containing nuget.exe, nuget msbuild targets and settings (which you will need to check in).
After that, you simply run Enable-PackageRestore and it sets up msbuild targets into your visual studio project files which will make sure that packages will be fetched in a prebuild step, even on your build server, without checking in any packages. (don't forget to check in the .nuget folder though!).
This way, you simply manage the nuget package sources in a nuget msbuild settings file (in the .nuget folder) central to your solution, instead of in each project.
Cheers,
Xavier
I finally got NuGetPowerTools to install after the advice from digitaltrust on http://blog.davidebbo.com
Although NuGetPowerTools solved my problem, it was overkill for what I wanted. It requires that you check in to version control a .nuget folder that it creates in your solution root. The folder contains NuGet.exe, and a couple of target files. I don't like this as I think version control is for source code, not tools.
I came up with the following solution.
Save NuGet.exe to a folder on your local drive, both on dev and continuous integration machines. I chose C:\tools\nuget\
Add that filepath to the Path Environment Variable in all environments
On continuous integration machines, find %APPDATA%\NuGet\NuGet.Config and enter the following
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="LocalRepositoryName" value="http://Domain/DataServices/Packages.svc/" />
</packageSources>
You can add more than one entry to packageSources and NuGet will search them in the order that they appear
The after build code from my question can now be amended to the following.
<Target Name="BeforeBuild">
<Exec Command="nuget install $(ProjectDir)packages.config
-o $(SolutionDir)packages" />
</Target>
The end result of this is that whenever the approved repository location is changed, the config has to be changed in only one place rather than in every csproj file. Also, it is the continuous integration server administrators who determine that location, not the developers in their command line calls.

VS2010 Web Publish command line version of File System deploy

Folks,
In a nutshell, I want to replicate this dialog:
It's a Visual Studio 2010 ASP.Net MVC project. If I execute this command, I get all the files I want, including the transformed web.configs in the "C:\ToDeploy" directory.
I want to replicate this on the command line so I can use it for a QA environment build.
I've seen various articles on how to do this on the command line for Remote Deploys, but I just want to do it for File System deploys.
I know I could replicate this functionality using nAnt tasks or rake scripts, but I want to do it using this mechanism so I'm not repeating myself.
I've investigated this some more, and I've found these links, but none of them solve it cleanly:
VS 2008 version, but no Web.Config transforms
Creates package, but doesn't deploy it..do I need to use MSDeploy on this package?
Deploys package after creating it above...does the UI really do this 2 step tango?
Thanks in advance!
Ok, finally figured this out.
The command line you need is:
msbuild path/to/your/webdirectory/YourWeb.csproj /p:Configuration=Debug;DeployOnBuild=True;PackageAsSingleFile=False
You can change where the project outputs to by adding a property of outdir=c:\wherever\ in the /p: section.
This will create the output at:
path/to/your/webdirectory/obj/Debug/Package/PackageTmp/
You can then copy those files from the above directory using whatever method you'd like.
I've got this all working as a ruby rake task using Albacore. I am trying to get it all done so I can actually put it as a contribution to the project. But if anyone wants the code before that, let me know.
Another wrinkle I found was that it was putting in Tokenized Parameters into the Web.config. If you don't need that feature, make sure you add:
/p:AutoParameterizationWebConfigConnectionStrings=false
I thought I'd post a another solution that I found, I've updated this solution to include a log file.
This is similar to Publish a Web Application from the Command Line, but just cleaned up and added log file. also check out original source http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild
Create an MSBuild_publish_site.bat (name it whatever) in the root of your web application project
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v4.0.30319
set destPath=C:\Publish\MyWebBasedApp\
:: clear existing publish folder
RD /S /Q "%destPath%"
call %msBuildDir%\msbuild.exe MyWebBasedApp.csproj "/p:Configuration=Debug;PublishDestination=%destPath%;AutoParameterizationWebConfigConnectionStrings=False" /t:PublishToFileSystem /l:FileLogger,Microsoft.Build.Engine;logfile=Manual_MSBuild_Publish_LOG.log
set msBuildDir=
set destPath=
Update your Web Application project file MyWebBasedApp.csproj by adding the following xml under the <Import Project= tag
<Target Name="PublishToFileSystem" DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
<Error Condition="'$(PublishDestination)'==''" Text="The PublishDestination property must be set to the intended publishing destination." />
<MakeDir Condition="!Exists($(PublishDestination))" Directories="$(PublishDestination)" />
<ItemGroup>
<PublishFiles Include="$(_PackageTempDir)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(PublishFiles)" DestinationFiles="#(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="True" />
</Target>
this works better for me than other solutions.
Check out the following for more info:
1) http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild
2) Publish a Web Application from the Command Line
3) Build Visual Studio project through the command line
My solution for CCNET with the Web.config transformation:
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe</executable>
<workingDirectory>E:\VersionesCC\Trunk_4\SBatz\Gertakariak_Orokorrak\GertakariakMS\Web</workingDirectory>
<projectFile>GertakariakMSWeb2.vbproj</projectFile>
<targets>Build</targets>
<timeout>600</timeout>
<logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll</logger>
<buildArgs>
/noconsolelogger /p:Configuration=Release /v:diag
/p:DeployOnBuild=true
/p:AutoParameterizationWebConfigConnectionStrings=false
/p:DeployTarget=Package
/p:_PackageTempDir=E:\Aplicaciones\GertakariakMS2\Web
</buildArgs>
</msbuild>
</tasks>
On VS2012 and above, you can refer to existing publish profiles on your project with msbuild 12.0, this would be equivalent to right-click and publish... selecting a publish profile ("MyProfile" on this example):
msbuild C:\myproject\myproject.csproj "/P:DeployOnBuild=True;PublishProfile=MyProfile"
I've got a solution for Visual Studio 2012: https://stackoverflow.com/a/15387814/2164198
However, it works with no Visual Studio installed at all! (see UPDATE).
I didn't checked yet whether one can get all needed stuff from Visual Studio Express 2012 for Web installation.
A complete msbuild file with inspiration from CubanX
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Publish">
<RemoveDir Directories="..\build\Release\Web\"
ContinueOnError="true" />
<MSBuild Projects="TheWebSite.csproj"
Targets="ResolveReferences;_CopyWebApplication"
Properties="Configuration=Release;WebProjectOutputDir=..\build\Release\Web;OutDir=..\build\Release\Web\bin\"
/>
</Target>
<Target
Name="Build"
DependsOnTargets="Publish;">
</Target>
</Project>
This places the published website in the Web..\build\Release folder

Problem with CruiseControl.net configuration

I started using ccnet to build my project. This is quite new issue for me so I have some problems.
First thing: Why does ccnet copy directory with my project to another directory (ccnet creates new folder named the same as project name included in ccnet.config file and copies to them directory with my project)
Second thing: Dashboard page cannot show reports for recent build (When I click on any item in recent build then I get page: "The page Cannot be found" I suppose that page cannot link files with logs. but I don't know how to link it.
I create one publisher:
<publishers>
<xmllogger logDir="c:\Branches" />
Can anyone help me?
Just a question, does the batch file "C:\Branches\Scripts\Build Release.bat" perform that step?
Because I can't see anything obvious within the CruiseControl config to copy the files into "c:\Program Files\CruiseControl.NET\Sever\TestProject"...
In build Release script I just call devenv to compile my project
Not sure I fully understand the 'first thing' if you can elaborate on it I'll try to help.
On our system it performs an SVN checkout of the code to a specified location and builds it there. Even though our CCNet installation is on the same box as the SVN repository it still needs somewhere separate to build the project.
On the 'second thing' it sounds like you have not set the <webURL> element properly - not a major problem. If you can post your config file that may help (with both issues).
Our CCNet installation pretty much worked out of the box but it is pretty fussy about it's config files. Have you made any changes to the dashboard.config file or is it as installed?
[Edit in response to posted config file]
I can't see anything in this config that will cause CCNet to copy the project to c:\Program Files\CruiseControl.NET\Server\TestProject. It could be something to do with the way you are calling devenv in your batch file - do you specify any paths in there?
Based on your config file and assuming you have an out of the box installation, your <webURL> element should read something like this:
<webURL>http://localhost/ccnet/server/local/testProject/ViewProjectReport.aspx</webURL>
On top of all that I would highly recommend that you drop the use of .bat files and devenv.exe for building your projects. Although this is the way I started with CCNet I quickly found that using NAnt and MSBuild well worth the effort.
I Try explain it more.
I have my local copy of repository on the path: "c:\Branches\trunk"
here is my config file:
<cruiseControl>
<project name="testProject">
<webURL>http://localhost/ccnet/</webURL>
<triggers>
<intervalTrigger name="interval trigger" seconds="600" initialSeconds="30" />
</triggers>
<sourcecontrol type="svn" autoGetSource="true">
<trunkUrl>http://********/svn/general/provider/prototype/Trunk</trunkUrl>
<workingDirectory>C:\Branches\Trunk</workingDirectory>
<password>***********</password>
<username>*************</username>
</sourcecontrol>
<tasks>
<exec>
<description>Compile program</description>
<baseDirectory>C:\Branches\Trunk\</baseDirectory>
<buildTimeoutSeconds>9000</buildTimeoutSeconds>
<executable>C:\Branches\Scripts\Build Release.bat</executable>
</exec>
</tasks>
<publishers>
<xmllogger logDir="C:\Branches\Trunk\Logs" />
</publishers>
<state type="state" directory="C:\Branches\Trunk\Logs"></state>
</project>
</cruisecontrol>
I didn't change anything in dashboard.config File.
cnet copy all folder c:\Branches\Trunk
to new folder c:\Program Files\CruiseControl.NET\Sever\TestProject
First problem was cause because in previous version of config file i use filesystem as sourcecontrol. Right now this problem don't occur.
Second problem is not resolved, But I have one Idea, Does any configuration files should be placed in virtual directory?

Checking a file out (TFS) for a pre-build action

I've added a pre-build action for an ASP.NET web control (server control) project, that runs jsmin.exe on a set of Javascript files. These output files are part of the source control tree and are embedded into the assembly.
The problem is when the pre-build runs, jsmin can't write the file as it's readonly. Is it possible to check the file out before hand? Or am I forced to set the file's attributes in the command line.
Any improved solution to the problem is welcome.
Update
One small issue with Mehmet's answer -you need to prepend the VS directory:
"$(DevEnvDir)tf" checkout /lock:none "$(ProjectDir)myfile"
If you're using Team Foundation Server, you can use team foundation command line utility (tf.exe) to check out the file(s) during pre-build and then check them back in during post-build. If you're using something else for source control, you can check if they have a command line tool like tf.exe.
If you do not want to check the files in as part of the build (which you normally wouldn't for this sort of thing) then I would simply set the attributes of the .js files before running jsmin on them. The easiest way of setting the files read-writeable is to use the the Attrib task provided by the MSBuild community extensions. The same community extensions also provide a JSCompress task for easily calling JSMin from MSBuild.
Therefore you'd have something like the following (not tested):
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<!-- rest of TFSBuild.proj file -->
<Target Name="AfterGet">
<Message Text="Compressing Javascript files under "$(SolutionRoot)"." />
<CreateItem Include="$(SolutionRoot)\**\*.js">
<Output TaskParameter="Include" ItemName="JsFiles"/>
</CreateItem>
<Attrib Files="#(JsFiles)" ReadOnly="false"/>
<JSCompress Files="#(JsFiles)" />
</Target>
Note that by modifying the files after getting them may well cause issues if you tried to move to an incremental build.

VS Post Build Event

I would like to implement a post build event that performs the following actions
A relative path copy of the DLL output (1 file, not all the debug jazz)
A register the output DLL to GAC
How is this done?
Does that do you want?
copy $(TargetPath) $(TargetDir)..\..\someFolder\myoutput.dll
regasm $(TargetPath)
(Entered into the field for post-build step under project properties)
Enter following into "Project properties->Build events->Post build events command line:"
xcopy "$(TargetPath)" "target path" /Y && regasm "$(TargetPath)"
or add following snippet to project (e.g. csproj) file
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "target path" /Y && regasm "$(TargetPath)"</PostBuildEvent>
</PropertyGroup>
Note that it is recommended to add "" around copy command arguments to avoid problems with paths containing whitespaces. Also note that multiple commands can be combined using &&
Are you sure you want to do this as part of a compile? I would recommend using project references in solutions rather than the GAC if you can avoid it. Copying files is one thing, but registering in the GAC is fairly intrusive and you may want to consider the other environments your code is compiled in. Things like other developers' machines, and test environments/build servers etc. If you have a build server really you should be using something like NAnt with some sort of continuous integration server.
I had to same issue and I struggled a bit to make it works.
In my case, I wanted to do the other way around which is copying the SDL dll into my output folder.
copy "$(SolutionDir)SDL\lib\x86\SDL.dll" "$(SolutionDir)$(Configuration)\"
Note that, $(Configuration) will be your output folder (e.g. Debug or Release).
The quotes was what I was missing, apparently you need them when the right hand side end with a \. Thus, it might be safer to always use them.
Hope to save someone else a 5 minutes!
P.S. I use Visual Studio 2010
you may want to look at MS Build. Its what we use here at work.
CodeProject Link &
MSDN Ref
For step 2 in the question I seem to prefer the following:
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil" /f /i $(TargetPath)
Note: this requires the Windows SDK to be installed on your development machine.
More info on the available macros, such as $(TargetPath), on MSDN.
Ran into a related issue. The answers here helped (thanks!).
My scenario was in debugging an MEF-reliant application I needed to have the related DLLs in a particular location. I ran into issue with overwriting the prior build so did need to add a delete to the script.
delete $(SolutionDir)FileService\$(ProjectName).dll
copy $(TargetPath) $(SolutionDir)FileService\$(ProjectName).dll
Hope that helps someone, too!
This question is old. The easiest way is to add something like this on your .csproj file. For example I am running some tests on a virtual machine and its nice to have it sent to it after I compile:
<Project>
...
<!-- Upload to virtual machine -->
<Target Name="rsync" AfterTargets="Build">
<Exec Command="C:\Windows\System32\wsl.exe rsync -azv -e 'ssh -i /path/to/my/private/key' --delete /mnt/c/repos/MyProject/bin/Debug/net7.0/ root#vm.ublux.com:/usr/share/foo/" />
</Target>
</Project>

Resources