Sunday, 23 August 2015

Package Azure Web Job with TFS Build to a Web Deployment Package & Deploy via VS RM Template

A web job can be deployed with web deploy in Visual Studio to Azure very easily. Getting a web job packaged with VS Web Application is equally simple and straight forward.

image

To package WebJobTest console application to the deployment package created with WebJobApp web application can be done using VS publish.

image

image

image

image

image

Web job getting packaged to deployment package.

image

A TFS Build can be defined to build the package. More information on setting up a TFS build to create web deploy package refer the post “How to Deploy to Azure Websites with TFS build 2013 and VS Release Management 2013”.

image

Web deployment package created with TFS Build.

image

But the web deployment package created with TFS build does not contain the app_data folder and the jobs in it.

image

Instead it is getting created as a separate package in build drop.

image

Investigations done in WWW pointed to below useful suggestions but none worked with TFS build as explained in them.


hhttps://github.com/davidebbo-test/WebAppWithWebJobsVS/commit/15e7579075312d620fe42a8746503ba82adf5305

http://chriskirby.net/deploy-your-webjob-projects-with-your-azure-website-using-continuous-delivery/

This issue is discussed in this forum post with Visual Studio Online.

https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/c3f4479b-3502-4fdf-97f9-ababe97ea8fa/webjobs-continuous-deployment-from-vs-online-build?forum=windowsazurewebsitespreview

However when tried building with msbuild locally with deploy arguments successfully packaged the web jobs into the Web Application deployment package.

With that knowledge, as a workaround (It really works :)), set the TFS Build to build to output as configured. This will build the solution with TFS Build outputs in to the local folder of the build agent, which would allow the jobs to be packaged into the web deployment package.

image

The next problem is getting the built package to the output folder. For that the https://tfsbuildextensions.codeplex.com/SourceControl/latest#Scripts/GatherItemsForDrop.ps1can be modified and used. Modified script is below.

##-----------------------------------------------------------------------
## <copyright file="GatherItemsForDrop.ps1">(c) http://TfsBuildExtensions.codeplex.com/. This source is subject to the Microsoft Permissive License. See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. All other rights reserved.</copyright>
##-----------------------------------------------------------------------
# Copy the binaries to the bin directory 
# so that the build server can drop them
# to the staging location specified on the Build Defaults tab 
#
# See 
# http://msdn.microsoft.com/en-us/library/bb778394(v=vs.120).aspx
# http://msdn.microsoft.com/en-us/library/dd647547(v=vs.120).aspx#scripts  
 
# Enable -Verbose option
[CmdletBinding()]
 
# Disable parameter
# Convenience option so you can debug this script or disable it in 
# your build definition without having to remove it from
# the 'Post-build script path' build process parameter.
param([switch]$Disable)
if ($PSBoundParameters.ContainsKey('Disable'))
{
 Write-Verbose "Script disabled; no actions will be taken on the files."
}
 
# This script copies the basic file types for managed code projects.
# You can change this list to meet your needs.
# $FileTypes = $("*.exe","*.dll","*.exe.config","*.pdb")
$FileTypes = $("*.xyz") # make it copy no files from bin (if required a file enable again with proper filename/extension)
 
# Specify the sub-folders to include
$SourceSubFolders = $("*bin*","*obj*")

# Specify Azure Package File Types
$AzurePackageFileTypes = $("*.deploy.cmd","*.deploy-readme.txt","*.SetParameters.xml","*.SourceManifest.xml", "*.zip")

# Specify Azure Package Containers
$AzureWebPackageContainers = $("*_PublishedWebsites*")

# Specify Azure Web Project Names
$AzureWebProjects = $("WebJobApp")
 
# If this script is not running on a build server, remind user to 
# set environment variables so that this script can be debugged
if(-not $Env:TF_BUILD -and -not ($Env:TF_BUILD_SOURCESDIRECTORY -and $Env:TF_BUILD_BINARIESDIRECTORY))
{
 Write-Error "You must set the following environment variables"
 Write-Error "to test this script interactively."
 Write-Host '$Env:TF_BUILD_SOURCESDIRECTORY - For example, enter something like:'
 Write-Host '$Env:TF_BUILD_SOURCESDIRECTORY = "C:\code\FabrikamTFVC\HelloWorld"'
 Write-Host '$Env:TF_BUILD_BINARIESDIRECTORY - For example, enter something like:'
 Write-Host '$Env:TF_BUILD_BINARIESDIRECTORY = "C:\code\bin"'
 exit 1
}
 
# Make sure path to source code directory is available
if (-not $Env:TF_BUILD_SOURCESDIRECTORY)
{
 Write-Error ("TF_BUILD_SOURCESDIRECTORY environment variable is missing.")
 exit 1
}
elseif (-not (Test-Path $Env:TF_BUILD_SOURCESDIRECTORY))
{
 Write-Error "TF_BUILD_SOURCESDIRECTORY does not exist: $Env:TF_BUILD_SOURCESDIRECTORY"
 exit 1
}
Write-Verbose "TF_BUILD_SOURCESDIRECTORY: $Env:TF_BUILD_SOURCESDIRECTORY"
 
# Make sure path to binary output directory is available
if (-not $Env:TF_BUILD_BINARIESDIRECTORY)
{
 Write-Error ("TF_BUILD_BINARIESDIRECTORY environment variable is missing.")
 exit 1
}
if ([IO.File]::Exists($Env:TF_BUILD_BINARIESDIRECTORY))
{
 Write-Error "Cannot create output directory."
    Write-Error "File with name $Env:TF_BUILD_BINARIESDIRECTORY already exists."
 exit 1
}
Write-Verbose "TF_BUILD_BINARIESDIRECTORY: $Env:TF_BUILD_BINARIESDIRECTORY"
 
# Tell user what script is about to do
Write-Verbose "Will look for and then gather "
Write-Verbose "$FileTypes files from"
Write-Verbose "$Env:TF_BUILD_SOURCESDIRECTORY and copy them to "
Write-Verbose $Env:TF_BUILD_BINARIESDIRECTORY
 
# Find the files
$files = gci $Env:TF_BUILD_SOURCESDIRECTORY -recurse -include $SourceSubFolders | 
 ?{ $_.PSIsContainer } | 
 foreach { gci -Path $_.FullName -Recurse -include $FileTypes }
if($files)
{
 Write-Verbose "Found $files.count files:"
  
 foreach ($file in $files) {
  Write-Verbose $file.FullName 
 }
}
else
{
 Write-Warning "Found no files."
}
 
# If binary output directory exists, make sure it is empty
# If it does not exist, create one
# (this happens when 'Clean workspace' build process parameter is set to True)
if ([IO.Directory]::Exists($Env:TF_BUILD_BINARIESDIRECTORY)) 
{ 
 $DeletePath = $Env:TF_BUILD_BINARIESDIRECTORY + "\*"
 Write-Verbose "$Env:TF_BUILD_BINARIESDIRECTORY exists."
 if(-not $Disable)
 {
  Write-Verbose "Ready to delete $DeletePath"
  Remove-Item $DeletePath -recurse
  Write-Verbose "Files deleted."
 } 
} 
else
{ 
 Write-Verbose "$Env:TF_BUILD_BINARIESDIRECTORY does not exist."
  
 if(-not $Disable)
 {
  Write-Verbose "Ready to create it."
  [IO.Directory]::CreateDirectory($Env:TF_BUILD_BINARIESDIRECTORY) | Out-Null
  Write-Verbose "Directory created."
 }
} 
 
# Copy the binaries 
Write-Verbose "Ready to copy files."
if(-not $Disable)
{
 foreach ($file in $files) 
 {
  Copy $file $Env:TF_BUILD_BINARIESDIRECTORY
 }
 Write-Verbose "Files copied."
}


#Copy Publish Web Site outputs

foreach ($AzureWebProject in $AzureWebProjects)
{

 $AzureWebProjectOutputDirectory = [io.path]::combine($Env:TF_BUILD_BINARIESDIRECTORY, $AzureWebProject)
 [IO.Directory]::CreateDirectory($AzureWebProjectOutputDirectory) | Out-Null


 $AzureWebProjectSourceDirectory = [io.path]::combine($Env:TF_BUILD_SOURCESDIRECTORY, $AzureWebProject)

 # Find the files
 $PackageFiles = gci $AzureWebProjectSourceDirectory -recurse -include $AzureWebPackageContainers | 
  ?{ $_.PSIsContainer } | 
  foreach { gci -Path $_.FullName -Recurse -include $AzurePackageFileTypes }
 if($PackageFiles)
 {
  Write-Verbose "Found $PackageFiles.count files:"
  
  foreach ($PackageFile in $PackageFiles) {
   Write-Verbose $PackageFile.FullName 
  }
 }
 else
 {
  Write-Warning "Found no files."
 }

 # Copy the binaries 
 Write-Verbose "Ready to copy files."
 if(-not $Disable)
 {
  foreach ($PackageFile in $PackageFiles) 
  {
   Copy $PackageFile $AzureWebProjectOutputDirectory
  }
  Write-Verbose "Files copied."
 }
}


Check the above script to TFS and use it in the build definition.

image


WebJobApp package created in build drop.

image

image

Now the TFS Build successfully packaged the jobs to the WebJobApp deployment package.

image

image

A release management template as explained in “How to Deploy to Azure Websites with TFS build 2013 and VS Release Management 2013” can be created to deploy the WebJobApp to Azure including the web job.

A new website created in Azure.

image

image

Release template created.

image

image

image

Creation of above tool is explained in “How to Deploy to Azure Websites with TFS build 2013 and VS Release Management 2013

image

Set deploy parameters from publish profile of the Azure web application.
image

A release triggered with the template using the TFS build.

image

Deployment succeeded.

image

Job deployed with Web Application.

image

Web Application and the job deployed.

image

image

No comments: