Thursday, July 5, 2012

Creating Scripts to Automate a Local Rebuild

As a project grows larger, it tends to take a longer time to pull down the latest from source code, recompile all the code, and if required, redeploy the database to your local machine so you have the latest of everything.  A few weeks ago a coworker remarked that he would like to run a script that would clean, get latest, rebuild everything, and reset his database to the latest from source control, while he goes and gets coffee (our project/local ‘reset’ is a multi-step process that takes about 15 minutes to run).  It was a great idea, and so I went off and created something that is now in use by the team, and something you may find useful in yours.  Let’s walk through it.

Using an MSBuild build file, I created targets for each action: Clean, GetLatest, Compile, BuildDatabase, and DeployDatabase.   At the top of the file there are properties (PropertyGroups and ItemGroups) defined that provide some “configuration” information for what will be run.  Notice that the DeployDatabase target explicitly depends on the BuildDatabase target; the other targets do not have dependencies because I want them to be able to run separately.


 
  
    
    Debug
    Any CPU
    false
    true
    YourDBName
    "if exists(select top 1 1 from sys.databases where [name] = '$(DatabaseName)') BEGIN ALTER DATABASE $(DatabaseName) SET SINGLE_USER WITH ROLLBACK IMMEDIATE;drop database $(DatabaseName);END"
    .\sqlexpress
    sqlcmd -E -S $(DatabaseServer) -Q $(DropDatabaseSQL)
  
 
  
    
    
    
  
 
  
    
    RunCodeAnalysis=$(RunCodeAnalysis);SkipInvalidConfigurations=true;RestorePackages=false;
  
 
  
    
    
  
 
  
    
    
  
 
  
    
  
 
  
    
  
 
  
    
  
 
  
    
  
 
  
    
    
  
 


The items you will need to configure are the DatabaseName, GetPath, SolutionProjectsToBuild, and DatabaseProjectsToBuild values.  Once this is done, you should place this file near or at the root of your project (the location of the file will be the MSBuildProjectDirectory value).  You can then execute MSBuild, calling the targets, or chaining them together.  You should run this from a Visual Studio Command Prompt, as it uses TF.exe.  This command is part of the TFS Power Tools, so ensure that you have it installed.

For our project, I created a .bat file that contains the following (note my build file is called master.build):

call “C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat” x86
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:GetLatest

I have defined additional targets in my build file to run multiple steps; here is an example of one:

    
  

If I want to execute two steps at the same time, in my bat file, I do the following (deploy database pops up in a second command window):
cmd /c start cmd /k “C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:DeployDatabase /m:2″
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:Compile /m:2

And since the team wanted options, I did the following in my bat file:
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
cls
echo Please select one of the following options:
echo 1. Get Latest, Compile, and Deploy DB (default in 10 seconds)
echo 2. Get Latest and Compile only
echo 3. Compile only
echo 4. Deploy Database Only
echo -
 
choice /C:1234 /N /D:1 /T:10 /M:"Your selection >> "
 
if %ERRORLEVEL% == 1 GOTO FULL
if %ERRORLEVEL% == 2 GOTO GETCOMPILE
if %ERRORLEVEL% == 3 GOTO COMPILEONLY
if %ERRORLEVEL% == 4 GOTO DATABASEONLY
 
GOTO END
 
:FULL
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:CleanGetLatest
cmd /c start cmd /k "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:DeployDatabase /m:2"
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:Compile /m:2
GOTO END
 
:GETCOMPILE
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:CleanGetLatest
cmd /c start cmd /k "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:BuildDatabase /m:2"
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:Compile /m:2
GOTO END
 
:COMPILEONLY
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:Clean /m:2
cmd /c start cmd /k "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:BuildDatabase /m:2"
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:Compile /m:2
GOTO END
 
:DATABASEONLY
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Msbuild.exe master.build /t:DeployDatabase /m:2
GOTO END
 
:END
echo on
Pause