Azure Custom KUDU Deployment Script

Home / Azure Custom KUDU Deployment Script

A couple of weeks ago, I wrote about deploying multiple applications to Azure virtual directories from a single Git repository to Azure. That method works well. However, it by default only supports building and deploying a single .NET project. This was fine in my previously example in which only one of the deployment projects I had was .NET based. Using a custom KUDU script, it’s possible to deploy multiple .NET applications to the virtual directories from a single git repository.


Using the Azure CLI, you can create a default KUDU script. Install Azure CLI with NPM, and then run it get a script for an arbitrary project/solution.

1
2
3
npm install azure-cli -g
azure config mode asm
azure site deploymentscript --aspWAP solutionFolder/ProjectFolder/Project.csproj -s solutionFolder/Solution.sln

For a Windows system, this will output a Windows batch file called “deploy.cmd.” As I detailed in my other post, this deploy.cmd can be used in conjunction with submerge folders to pull multiple projects into a single git repository.

The script, though, only will build and deploy a single project. However, it’s a Windows batch file, so we can modify it to deploy multiple projects to our virtual directories. What I did with the default script was modify it to have iterate over an array of projects/solutions and deploy them. This iterating simply calls the default deployment bits with specific variables from the iterated parameters.

Here’s my custom script. You can see that I specify (2) projects/solutions and these two projects get deployed appropriately. To achieve this, I put the default deployment functionality into a Windows batch function and call it during the looping over the project names.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
@if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off
 
:: ----------------------
:: KUDU Deployment Script
:: Version: 1.0.9
:: ----------------------
 
:: Prerequisites
:: -------------
 
:: Verify node.js installed
where node 2>nul >nul
IF %ERRORLEVEL% NEQ 0 (
  echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
  goto error
)
 
:: Setup
:: -----
 
setlocal enabledelayedexpansion
 
SET ARTIFACTS=%~dp0%..\artifacts
 
IF NOT DEFINED DEPLOYMENT_SOURCE (
  SET DEPLOYMENT_SOURCE=%~dp0%.
)
 
IF NOT DEFINED DEPLOYMENT_TARGET (
  SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
)
 
IF NOT DEFINED NEXT_MANIFEST_PATH (
  SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest
 
  IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
    SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
  )
)
 
IF NOT DEFINED KUDU_SYNC_CMD (
  :: Install kudu sync
  echo Installing Kudu Sync
  call npm install kudusync -g --silent
  IF !ERRORLEVEL! NEQ 0 goto error
 
  :: Locally just running "kuduSync" would also work
  SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
)
IF NOT DEFINED DEPLOYMENT_TEMP (
  SET DEPLOYMENT_TEMP=%temp%\___deployTemp%random%
  SET CLEAN_LOCAL_DEPLOYMENT_TEMP=true
)
 
IF DEFINED CLEAN_LOCAL_DEPLOYMENT_TEMP (
  IF EXIST "%DEPLOYMENT_TEMP%" rd /s /q "%DEPLOYMENT_TEMP%"
  mkdir "%DEPLOYMENT_TEMP%"
)
 
IF DEFINED MSBUILD_PATH goto MsbuildPathDefined
SET MSBUILD_PATH=%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe
:MsbuildPathDefined
 
SET "projects[0]=dir1\Project1\Project1.csproj"
SET "solutions[0]=dir1\Solution1.sln"
SET "solutiondirs[0]=dir1"
 
SET "projects[1]=dir2\Project2\Project2.csproj"
SET "solutions[1]=dir2\Solution2.sln"
SET "solutiondirs[1]=dir2"
 
SET len=0
:SymLoop
if defined projects[%len%] (
   SET /a "len+=1"
   GOTO :SymLoop
)
 
echo "The length of the array is" %len%
SET /a "len-=1"
 
FOR /L %%A IN (0,1,%len%) DO (
    echo !projects[%%A]! !solutions[%%A]! !solutiondirs[%%A]!
    call :deploy !projects[%%A]! !solutions[%%A]! !solutiondirs[%%A]!
)
 
:deploy
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------
SHIFT
IF (%0)==() GOTO error
SET "PROJECT_PATH=%~0"
SET "SOLUTION_PATH=%~1"
SET "SOLUTION_DIR=%~2"
 
echo Handling .NET Web Application deployment.
 
:: 1. Restore NuGet packages
IF /I "%SOLUTION_PATH%" NEQ "" (
  call :ExecuteCmd nuget restore "%DEPLOYMENT_SOURCE%\%SOLUTION_PATH%"
  IF !ERRORLEVEL! NEQ 0 goto error
)
 
:: 2. Build to the temporary path
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\%PROJECT_PATH%" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="%DEPLOYMENT_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\%SOLUTION_DIR%\\" %SCM_BUILD_ARGS%
) ELSE (
  call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\%PROJECT_PATH%" /nologo /verbosity:m /t:Build /p:AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\%SOLUTION_DIR%\\" %SCM_BUILD_ARGS%
)
 
IF !ERRORLEVEL! NEQ 0 goto error
 
:: 3. KuduSync
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%\%SOLUTION_DIR%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
)
EXIT /B
 
:: Execute command routine that will echo out when error
:ExecuteCmd
setlocal
set _CMD_=%*
call %_CMD_%
if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
exit /b %ERRORLEVEL%
 
:error
endlocal
echo An error has occurred during web site deployment.
call :exitSetErrorLevel
call :exitFromFunction 2>nul
 
:exitSetErrorLevel
exit /b 1
 
:exitFromFunction
()
 
:end
endlocal
echo Finished successfully.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.