326 строки
9.9 KiB
PowerShell
326 строки
9.9 KiB
PowerShell
#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..."
|