This configuration took a while to put together and debug, but once in place it is an incredibly powerful and flexible system.
What follows is the core workflow I implemented for build quality driven deployment.
The process works like this:
1. A “solutions” directory is placed in the root of the team project and a <projectname>.<environment>.tfsbuild.sln (i.e. qmail.dev.tfsbuild.sln) is placed in it.
2. A BuildPrep (or PreBuild) and a PostBuild project are added to the .tfsbuild.sln. These handle preparation and cleanup tasks.
3. A continuous integration build is configured for this solution file.
4. A check in takes place
5. The solution’s BuildPrep project kicks off the following steps:
a. The latest Common.dll and Common.Providers.dll are copied from
file://mytfs/common to the projects ReferenceAssemblies folder
b. Updates a SharedAssemblyVersion file with a Major.Minor.Build.Rev formatted and incremented build number. Then copies it to each project in the solution. This keeps grouped DLLs on the same version number.
6. The projects are compiled
7. If this is a release build then the DLLs are StrongNamed
8. The build output is copied to
file://mytfs/TFS/Builds
9. A build notification is sent out to the
TFSSubscribers@mydom.com distribution list.
10. At this time the Build Quality is “Unassigned”
11. A Developer or BuildMaster reviews the build and assigns a Build Quality. Typically the first assignment is “Ready for Initial Test”.
12. This change fires a BuildQualityChange Event that TFSDeployer is notified of.
13. TFS Deployer then Checks out the BuildProcessTemplates\Deployment scripts for the build that fired the event. These include the DeploymentMappings.xml and the various PowerShell task automation scripts.
14. The event is processed by using rules laid out in the DeploymentMappings.xml document attached. (snippet below)
<Mapping BuildDefinitionPattern="^Dev\.PEKContentService.*$"
Computer="myTFS"
OriginalQuality="*"
NewQuality="Ready for Initial Test"
Script="Dev.PEKContentService-Any2RFIT.ps1"
RunnerType="PowerShell"
NotificationAddress="TFSSubscribers@mydom.com">
<ScriptParameter name="DevelopmentServerName" value="myWEB.myDOM.COM" />
<ScriptParameter name="DevelopmentServerIP" value="10.101.244.106" />
<ScriptParameter name="QAServerName" value="MWEB.myDOM.COM" />
<ScriptParameter name="QAServerIP" value="10.101.244.174" />
<ScriptParameter name="ProdServerName" value="HOSA-P-WEB01-CD" />
<ScriptParameter name="ProdServerIP" value="10.180.28.50" />
</Mapping>
15. Based on the DeploymentMappings rules and the BuildQualityChange event properties the designated powershell script is run. In this case that is “Dev.PEKContentService-Any2RFIT.ps1” (snippet below)
if ($DevelopmentServerName -eq "myWeb") { Write-Output "Script parameter received! Publishing Common.dll to file://$developmentservername/Common/" ; }
#get build variables
$tproj = $TfsDeployerBuildDetail.TeamProject
$bquality = $TfsDeployerBuildDetail.Quality
$dloc = if($TfsDeployerBuildDetail){$TfsDeployerBuildDetail.DropLocation}else{""}
...
#initialize build log
$TFSDEployerLog = "file://mytfs/TFSBUILDS/Log.txt"
$date = ( get-date ).ToString('yyyyMMdd hh:mm:ss')
#write Release Notes
"This is a build notification that a $tproj build has been upgraded to (Ready For Initial Test) on..." >> $TFSDeployerLog
#Register Destination Variables
$Destination = "file://$developmentservername/wwwroot.dev/"
$DestinationPEKWebsiteBin = "file://$developmentservername/wwwroot.dev/PekContentService/bin/"
$DestinationPEKWebsiteBin = "file://$developmentservername/wwwroot.dev/PekContentTestHarness/"
...
#Register Source Variables
$SourceDlls = "$dropLocation\*.dll"
...
$Source="$dropLocation\_PublishedWebsites\"
#publish files and directory structure
Get-ChildItem -Path $Source
Copy-Item -Destination $Destination -Recurse -Force
Get-ChildItem -Path $dropLocation\actn.Lib.Security.dll
Copy-Item -Destination $DestinationPEKWebsiteBin -Force
...
#zip up test form
Get-ChildItem -Path $dropLocation\*.TestForm*
Copy-Item -Destination $DestinationTestHarness -Force
Get-ChildItem -Path $dropLocation\ComponentSpace*
Copy-Item -Destination $DestinationTestHarness -Force
dir DestinationTestHarness
add-Zip $dropLocation\PursuitListTestHarness.zip
#configuration and other follow-up tasks are scripted here…
16. When this script completes the code has been deployed to Dev and can be tested for integration issues by the developers.
17. Then they are comfortable the Developers, a buildmaster, a QA person or a Business Analyst can update the build quality to "Initial Test Passed"
18. This will trigger another event, and the TFSDeployer rules engine will invoke the corresponding script which then deploys and configures the application in the associated environment.