-
Notifications
You must be signed in to change notification settings - Fork 141
/
Copy pathbuild.ps1
325 lines (272 loc) · 9.85 KB
/
build.ps1
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Entry point for building/testing the project, common usage:
.\build.ps1 -devSetup -publish -install -test -verbose
What the command does
* Ensure local machine is properly setup for build and test the repo
* Build and publish application in `dist` directory
* Build and run installer
* Run functional tests
.\build.ps1 -devSetup -test -testRoot "C:\inetpub" -verbose
Run test on a machine with IIS Administration API already installed
.PARAMETER publish
build and publish the manifests in dist directory.
Include this switch to build and test the project in a single step. However, its required that msbuild and nuget needs to be in the path when `publish` is set to true
.PARAMETER devSetup
Ensure local machine is properly setup for build and test the repo
.PARAMETER install
Install the built manifest for testing
.PARAMETER keep
Do not uninstall the application after steps are run
.PARAMETER test
.PARAMETER testFilter
Run the functional tests, use testFilter to filter to tests to be performed
.PARAMETER testPort
The port to use for service
.PARAMETER testRoot
The root directory for tests to create web sites. Note that the directory must be granted both read and write permission via IIS Administration API's config file
.PARAMETER pingRetryCount
.PARAMETER pingRetryPeriod
When waiting for the service to come up, these properties defines the fequency and number of time to retry pinging the endpoint
.PARAMETER buildType
Build the binaries in debug or release mode, default: release
.PARAMETER appName
Do not change: the name of the application
.PARAMETER installedCertName
Do not change: the name of the self host certed installed
#>
[CmdletBinding()]
param(
[switch]
$publish,
[switch]
$devSetup,
[switch]
$install,
[switch]
$keep,
[switch]
$test,
[string]
$testFilter,
[int]
$testPort = 55539,
[string]
$testRoot,
[int]
$pingRetryCount = 20,
[int]
$pingRetryPeriod = 10,
[ValidateSet('debug','release')]
[string]
$buildType = 'release',
[string]
$appName = "Microsoft IIS Administration",
[string]
$installedCertName = "Microsoft IIS Administration Server Certificate"
)
$ErrorActionPreference = "Stop"
function BuildHeader {
"[Build] $(Get-Date -Format yyyyMMddTHHmmssffff):"
}
function ForceResolvePath($path) {
$path = Resolve-Path $path -ErrorAction SilentlyContinue -ErrorVariable err
if (-not($path)) {
$path = $err[0].TargetObject
}
return $path
}
function DevEnvSetup() {
$configArgs = @{}
$configArgs.ConfigureTestEnvironment = $true
if ($testPort) {
$configArgs.TestPort = $testPort
}
if ($testRoot) {
Write-Verbose "Test port $testPort"
$configArgs.TestRoot = $testRoot
}
& ([System.IO.Path]::Combine($scriptDir, "Configure-DevEnvironment.ps1")) @configArgs
}
function Publish() {
if (!(Where.exe msbuild)) {
throw "msbuild command is required for publish option"
}
msbuild /t:publish /p:Configuration=$buildType
}
function BuildSetupExe() {
if (!(Where.exe msbuild)) {
throw "msbuild command is required to build installer"
}
if (!(Where.exe nuget)) {
throw "nuget command is required to build installer"
}
Push-Location installer
try {
nuget restore
msbuild /p:Configuration=$buildType
} finally {
Pop-Location
}
}
function EnsureIISFeatures() {
Get-WindowsOptionalFeature -Online `
| Where-Object {$_.FeatureName -match "IIS-" -and $_.State -eq [Microsoft.Dism.Commands.FeatureState]::Disabled} `
| ForEach-Object {Enable-WindowsOptionalFeature -Online -FeatureName $_.FeatureName}
}
function InstallTestService() {
Start-Process CMD -NoNewWindow -Wait @("/C", $script:installerLocation, "-q")
## Working around a windows group policy issue
## Installer just added the current user to "IIS Adminstration API Owners" group and the group policy may not have been updated without re-logon
$roles = @('administrators', 'owners')
$userJson = (ConvertTo-Json $(whoami)).Trim('"')
foreach ($role in $roles) {
$queryAddUser = '.security.users.' + $role + ' |= . + [\"' + $userJson + '\"]'
Write-Verbose "Running query $queryAddUser to config file"
& ([System.IO.Path]::Combine($scriptDir, "Edit-AppSettings.ps1")) -quiet -wait -query $queryAddUser
}
$script:installed = $true
}
function UninstallTestService() {
Start-Process CMD -NoNewWindow -Wait @("/C", $script:installerLocation, "-q", "-uninstall")
Write-Verbose "Uninstalled $appName"
}
function CleanUp() {
if (!$script:installed -or $keep) {
Write-Verbose "Skipping clean up"
} else {
try {
Write-Verbose "$serviceName is being stopped"
Stop-Service $serviceName
Write-Verbose "$serviceName stopped"
} catch {
Write-Warning "Exception while trying to stop service $($_.Exception.Message)"
if ($_.Exception -and
$_.Exception -is [Microsoft.PowerShell.Commands.ServiceCommandException]) {
Write-Host "$serviceName was not installed"
}
}
try {
Write-Verbose "$serviceName is being uninstalled"
UninstallTestService
Write-Verbose "$serviceName is uninstalled"
} catch {
Write-Warning "Failed to uninistall ${serviceName}: $($_.Exception.Message)"
}
}
}
function StartTest() {
Write-Host "$(BuildHeader) Functional tests..."
$testProj = [System.IO.Path]::Combine($projectRoot, "test", "Microsoft.IIS.Administration.Tests", "Microsoft.IIS.Administration.Tests.csproj")
if ($testFilter) {
dotnet test $testProj --filter $testFilter
} else {
dotnet test $testProj
}
}
function VerifyPath($path) {
if (!(Test-Path $path)) {
Write-Path "$path does not exist"
return $false
}
return $true
}
function VerifyPrecondition() {
if (!(VerifyPath [System.IO.Path]::Combine($projectRoot, "test", "appsettings.test.json")) `
-or !(VerifyPath [System.IO.Path]::Combine($projectRoot, "test", "Microsoft.IIS.Administration.Tests", "test.config.json.template"))) {
throw "Test configurations do no exist, run .\scripts\Configure-DevEnvironment.ps1 -ConfigureTestEnvironment"
}
}
function GetGlobalVariable($name) {
& ([System.IO.Path]::Combine($scriptDir, "setup", "globals.ps1")) $name
}
function SanityTest() {
Write-Host "Sanity tests..."
if ($PSBoundParameters['Verbose']) {
ListCerts
}
TouchUrl "https://localhost:${testPort}"
TouchUrl "https://localhost:${testPort}/security/tokens"
}
function TouchUrl($url) {
try {
Invoke-WebRequest -UseDefaultCredentials $url
} catch {
Write-Host $_
Write-Host (ConvertTo-Json $_.Exception)
throw
}
}
function ListCerts() {
Write-Verbose "Listing from cert:LocalMachine\My"
Get-ChildItem cert:LocalMachine\My | Where-Object { $_.FriendlyName -eq $installedCertName }
Write-Verbose "Listing from cert:LocalMachine\Root"
Get-ChildItem cert:LocalMachine\Root | Where-Object { $_.FriendlyName -eq $installedCertName }
Write-Verbose "Done listing certs"
}
########################################################### Main Script ##################################################################
$debug = $PSBoundParameters['debug']
$script:installed = $false
try {
$projectRoot = git rev-parse --show-toplevel
} catch {
Write-Warning "Error looking for project root $_, using script location instead"
$projectRoot = $PSScriptRoot
}
$scriptDir = Join-Path $projectRoot "scripts"
# publish script only takes full path
$publishPath = Join-Path $projectRoot "dist"
$serviceName = GetGlobalVariable DEFAULT_SERVICE_NAME
if ($testFilter) {
$test = $true
}
Write-Host "$(BuildHeader) Starting clean up..."
CleanUp
try {
if ($devSetup) {
Write-Host "$(BuildHeader) Dev setup..."
DevEnvSetup
Write-Host "$(BuildHeader) Ensure IIS Features..."
EnsureIISFeatures
}
if ($publish) {
Write-Host "$(BuildHeader) Publishing..."
dotnet restore
Publish
& ([System.IO.Path]::Combine($scriptDir, "build", "Clean-BuildDir.ps1")) -manifestDir $publishPath
if ($test) {
& ([System.IO.Path]::Combine($scriptDir, "tests", "Copy-TestConfig.ps1"))
}
}
if ($install) {
# Note: assume 64 bits and release built
$script:installerLocation = [System.IO.Path]::Combine($projectRoot, "installer", "IISAdministrationBundle", "bin", "x64", "Release", "IISAdministrationSetup.exe")
if (!$publish -and (Test-Path $script:installerLocation)) {
Write-Host "Skipping building setup exe because it exists..."
} else {
BuildSetupExe
}
Write-Host "$(BuildHeader) Installing service..."
InstallTestService
if ($debug) {
$proceed = Read-Host "$(BuildHeader) Pausing for debug, continue? (Y/n)..."
if ($proceed -NotLike "y*") {
Write-Host "$(BuildHeader) Aborting..."
Exit 1
}
}
}
if ($test) {
Write-Host "$(BuildHeader) Starting test..."
SanityTest
Write-Host "$(BuildHeader) Starting functional test..."
StartTest
}
} catch {
throw
} finally {
Write-Host "$(BuildHeader) Final clean up..."
CleanUp
}
Write-Host "$(BuildHeader) done..."