build/build.ps1 (187 lines of code) (raw):
$ErrorActionPreference = 'Stop'
$isAppveyor = [bool]$env:APPVEYOR
$configuration = if ($CONFIGURATION -ne $null) { $CONFIGURATION } else { 'Debug' }
$platform = if ($PLATFORM -ne $null) { $PLATFORM } else { 'Any CPU' }
$projectFolder = if ($ENV:APPVEYOR_BUILD_FOLDER -ne $null) { "$ENV:APPVEYOR_BUILD_FOLDER" } else { $(Get-Location).path }
$buildFolder = $projectFolder + '\build\'
$runtime = if ($ENV:DotNetRunTime -ne $null) { $ENV:DotNetRunTime } else { 'netcoreapp2.1' }
$artifactsFolder = $buildFolder + 'artifacts\'
$appProject = $projectFolder + '\src\Microsoft.Azure.Relay\Microsoft.Azure.Relay.csproj'
$testProject = $projectFolder + '\test\Microsoft.Azure.Relay.UnitTests\Microsoft.Azure.Relay.UnitTests.csproj'
$coverageFile = $buildFolder + 'coverage.xml'
$appNamespace = 'Microsoft.Azure.Relay'
$testNamespace = 'Microsoft.Azure.Relay.UnitTests'
# Environment variables
$connectionStringVariableName = 'azure-relay-dotnet/ConnectionString'
$codeCovSecret = [Environment]::GetEnvironmentVariable('azure-relay-dotnet/CodeCovSecret')
$clientSecret = [Environment]::GetEnvironmentVariable('azure-relay-dotnet/ClientSecret')
$tenantId = [Environment]::GetEnvironmentVariable('azure-relay-dotnet/TenantId')
$appId = [Environment]::GetEnvironmentVariable('azure-relay-dotnet/AppId')
$canDeploy = ([bool]$clientSecret -and [bool]$tenantId -and [bool]$appId)
$skipCodeCoverage = if ([bool][Environment]::GetEnvironmentVariable('azure-relay-dotnet/SkipCodeCoverage')) { $true } else { $false }
function Build-Solution
{
Write-Host "Building projects"
# Restore solution files
MSBuild.exe Microsoft.Azure.Relay.sln /t:restore /p:Configuration=$configuration /p:Platform=$platform /verbosity:minimal
# $? Returns True or False value indicating whether previous command ended with an error.
# This is used to throw an error that will cause the AppVeyor process to fail as expected.
if (-not $?)
{
throw "Package restore failed."
}
# Build solution
MSBuild.exe Microsoft.Azure.Relay.sln /p:Configuration=$configuration /p:Platform=$platform /verbosity:minimal
if (-not $?)
{
throw "Build failed."
}
else
{
Write-Host "Building complete."
}
}
function Deploy-AzureResources
{
$resourceNamePrefix = 'relay-dotnet-av-'
Write-Host "Creating Azure resources"
Enable-AzureDataCollection -WarningAction SilentlyContinue | Out-Null
$buildVersion =
if ($isAppveyor)
{
($env:APPVEYOR_BUILD_NUMBER + $env:APPVEYOR_JOB_NUMBER).Replace(".", "")
}
else { Get-Random }
$global:resourceGroupName = $resourceNamePrefix + $buildVersion + '-rg'
$namespaceName = $resourceNamePrefix + $buildVersion + '-ns'
$location =
if ([bool][Environment]::GetEnvironmentVariable('azure-relay-dotnet/location'))
{
[Environment]::GetEnvironmentVariable('azure-relay-dotnet/location')
} else { 'westus' }
$password = ConvertTo-SecureString -AsPlainText -Force $clientSecret
$credentials = New-Object `
-TypeName System.Management.Automation.PSCredential `
-ArgumentList $appId, $password
# https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal
Add-AzureRmAccount -Credential $credentials -ServicePrincipal -TenantId $tenantId | Out-Null
$resourceGroup = New-AzureRmResourceGroup -Name $resourceGroupName -Location $location -Force -WarningAction SilentlyContinue
Write-Host ("Resource group name: " + $resourceGroup.ResourceGroupName)
$armParameters = @{
namespaceName = $namespaceName;
}
$templatePath = $buildFolder + 'azuredeploy.json'
$settings = New-AzureRmResourceGroupDeployment `
-ResourceGroupName $resourceGroupName `
-TemplateFile $templatePath `
-TemplateParameterObject $armParameters `
-Force `
-WarningAction SilentlyContinue
Write-Host "Namespace: $namespaceName"
$connectionString = $settings.Outputs.Get_Item("namespaceConnectionString").Value
[Environment]::SetEnvironmentVariable($connectionStringVariableName, $connectionString)
Write-Host "Completed creating Azure resources"
# Useful for debugging ARM deployments
# Get-AzureRmLog -CorrelationId "GUID" -DetailedOutput
}
function Run-UnitTests
{
if ($skipCodeCoverage)
{
dotnet test $testProject -f $runtime
if (-not $?)
{
throw "Unit tests failed."
}
return;
}
Write-Host "Running unit tests."
if (-Not (Test-Path .\nuget.exe))
{
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -outfile $buildFolder\nuget.exe
}
$openCoverVersion = '4.6.712'
$openCoverNuPkgOutFile = $buildFolder + 'OpenCover.' + $openCoverVersion + '.nupkg'
# Using a temporary version of OpenCover until a NuGet is published. https://github.com/OpenCover/opencover/issues/669
# Once there is a new NuGet package, this if statement can be removed, and so can '-source $buildFolder' in the line after
if (-Not (Test-Path $openCoverNuPkgOutFile)) {
Invoke-WebRequest `
-Uri "https://ci.appveyor.com/api/buildjobs/upad53qdyo1iv382/artifacts/main%2Fbin%2Fpackages%2Fnuget%2Fopencover%2FOpenCover.4.6.712.nupkg" `
-OutFile $openCoverNuPkgOutFile
}
& $buildFolder\nuget.exe install OpenCover -version $openCoverVersion -SolutionDirectory $buildFolder -source $buildFolder
$openCoverConsole = $buildFolder + 'packages\' + 'OpenCover.' + $openCoverVersion + '\tools\OpenCover.Console.exe'
$target = '-target:C:\Program Files\dotnet\dotnet.exe'
$targetArgs = '-targetargs: test ' + $testProject + ' -f ' + $runtime
$filter = '-filter:+[' + $appNamespace + '*]* -[' + $testNamespace + ']*'
$output = '-output:' + $coverageFile
& $openCoverConsole $target $targetArgs $filter $output '-register:user' '-oldStyle'
if (-not $?)
{
throw "Unit tests failed."
}
if (-Not (Test-Path $coverageFile))
{
return
}
if ([bool]$codeCovSecret)
{
$ENV:PATH = 'C:\\Python34;C:\\Python34\\Scripts;' + $ENV:PATH
python -m pip install --upgrade pip
pip install git+git://github.com/codecov/codecov-python.git
codecov -f $coverageFile -t $codeCovSecret -X gcov
}
else
{
$reportGeneratorVersion = '2.5.7'
& $buildFolder\nuget.exe install ReportGenerator -version $reportGeneratorVersion -SolutionDirectory $buildFolder
$reportGenerator = $buildFolder + 'packages\' + 'ReportGenerator.' + $reportGeneratorVersion + '\tools\ReportGenerator.exe'
$targetDirectory = $buildFolder + 'OpenCoverReport\'
& $reportGenerator -reports:$coverageFile -targetdir:$targetDirectory
}
}
function CopyArtifacts
{
if (-Not $isAppveyor)
{
return
}
New-Item -ItemType Directory -Force -Path $artifactsFolder | Out-Null
MSBuild.exe $appProject /t:pack /p:Configuration=$configuration /p:Platform=$platform /p:PackageOutputPath=$artifactsFolder /verbosity:minimal
if (Test-Path $coverageFile)
{
Copy-Item $coverageFile $artifactsFolder
}
}
function Delete-AzureResources
{
Write-Host "Deleting Azure resources"
$password = ConvertTo-SecureString -AsPlainText -Force $clientSecret
$credentials = New-Object `
-TypeName System.Management.Automation.PSCredential `
-ArgumentList $appId, $password
Remove-AzureRmResourceGroup -Name $resourceGroupName -WarningAction SilentlyContinue -Force | Out-Null
Write-Host "Completed deleting Azure resources"
}
dotnet --info
Build-Solution
if (-Not $canDeploy -and -Not [bool][Environment]::GetEnvironmentVariable($connectionStringVariableName)) {
return
}
try {
if ($canDeploy -and -not [bool][Environment]::GetEnvironmentVariable($connectionStringVariableName)) {
Deploy-AzureResources
}
if ([bool][Environment]::GetEnvironmentVariable($connectionStringVariableName)) {
Run-UnitTests
CopyArtifacts
}
}
catch {
throw
}
finally {
if ($canDeploy -and $resourceGroupName) {
Delete-AzureResources
}
}