Deploying files with CruiseControl.net using xcopy
Each CruiseControl.net job that needs to deploy files to a web server, does this through a batch file. Inside that batch file is an xcopy command.
Here is an example
xcopy /exclude:..Scriptsexcludes.txt /E /F /Y /M .DerbyDerby.Website*.* \SBD-WEB-1inetpubDev1.derby.reurgency.netDerby
NOTE: the current working directory is always the folder called “Working” in our standard folder structure.
You will notice that the xcopy command uses a variety of switches that require some explanation and some WARNINGS. Look at documentation here: http://support.microsoft.com/kb/289483
Here are my notes regarding these switches:
/exclude allows to exclude certain files. Those file names are listed in the excluded.txt file. At a minimum this should contain one entry for web.config.
/E copies any subfolder, even if empty. This ensures that the proper structure exists on the web server.
/F displayes the full source and destination file names will copying. This is helpful when looking at CC.net logs.
/Y overwrites existing files without prompting. Important not to prompt since this runs automatically.
/M copies files with the archive attribute set. This switch turns off the archive attribute.
That last switch /M works great as long as you only have one deployment script for this website using that switch. i.e. if you have both a dev1 cc.net project and test1 cc.net project you will have a problem with that switch.
Here’s the way it works with dev1:
- CC.net gets latest files from SVN. Any new or modified files get their archive bit set. This is not a CC.net thing, this is a basic feature of every OS file system.
- CC.net builds DLLs. All DLLs build have their archive bit set. Again, just basic file system behavior.
- CC.net runs the deploy batch file that contains the xcopy. The xcopy uses the /M switch which tells it to only copy the changed files (archive bit set). It also resets the archive bit so it is not seen as changed the next time it runs.
This process makes deployments much faster. However, it only works if there is one entity clearing that archive bit. As soon as you have another environment (e.g. test1) you cannot use that trick for those other environments. The issue is that two jobs are stomping on each other’s record of what has changed. After a few runs, they will BOTH have out of sync files.
Therefore, here is best practice:
- Dev1 will always use the /M switch because those deploys happen more frequently and we benefit the most from only copying changed files.
- All other environments (Test1, Demo1, etc) will NOT use the /M switch because those jobs are run less frequently and it is OK if all files get copied each time.
Thank you so much for finding this issue Ty. Robbie and I suspected it might have something to do with the archive flag but we didn’t investigate it enough. It you think about it logically it makes perfect sense why the test environment wasn’t getting the latest files.